mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-03-14 14:22:32 +01:00
Clean up Myrian code
This commit is contained in:
@ -1,250 +0,0 @@
|
||||
import { DeviceType, Component, Lock, Glitch } from "@nsdefs";
|
||||
import { Myrian, findDevice, inMyrianBounds } from "./Myrian";
|
||||
import { getNextISocketRequest } from "./formulas/formulas";
|
||||
import { decodeBase64 } from "bcryptjs";
|
||||
import { roamingTime } from "./formulas/glitches";
|
||||
|
||||
export const myrianSize = 12;
|
||||
|
||||
const defaultGlitches = {
|
||||
[Glitch.Segmentation]: 0,
|
||||
[Glitch.Roaming]: 0,
|
||||
[Glitch.Encryption]: 0,
|
||||
[Glitch.Magnetism]: 0,
|
||||
[Glitch.Rust]: 0,
|
||||
[Glitch.Friction]: 0,
|
||||
[Glitch.Isolation]: 0,
|
||||
[Glitch.Jamming]: 0,
|
||||
[Glitch.Virtualization]: 0,
|
||||
};
|
||||
|
||||
const defaultMyrian: Myrian = {
|
||||
vulns: 0,
|
||||
totalVulns: 0,
|
||||
devices: [],
|
||||
glitches: { ...defaultGlitches },
|
||||
rust: {},
|
||||
};
|
||||
|
||||
export const myrian: Myrian = defaultMyrian;
|
||||
|
||||
export const NewBus = (name: string, x: number, y: number) => {
|
||||
myrian.devices.push({
|
||||
name,
|
||||
type: DeviceType.Bus,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
content: [],
|
||||
maxContent: 1,
|
||||
|
||||
moveLvl: 0,
|
||||
transferLvl: 0,
|
||||
reduceLvl: 0,
|
||||
installLvl: 0,
|
||||
energy: 16,
|
||||
maxEnergy: 16,
|
||||
});
|
||||
};
|
||||
|
||||
export const NewCache = (name: string, x: number, y: number) => {
|
||||
myrian.devices.push({
|
||||
name,
|
||||
type: DeviceType.Cache,
|
||||
isBusy: false,
|
||||
content: [],
|
||||
maxContent: 1,
|
||||
x,
|
||||
y,
|
||||
});
|
||||
};
|
||||
|
||||
export const NewReducer = (name: string, x: number, y: number) => {
|
||||
myrian.devices.push({
|
||||
name,
|
||||
type: DeviceType.Reducer,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
content: [],
|
||||
maxContent: 2,
|
||||
tier: 1,
|
||||
});
|
||||
};
|
||||
|
||||
export const NewISocket = (name: string, x: number, y: number, dispensing: Component) => {
|
||||
myrian.devices.push({
|
||||
name,
|
||||
type: DeviceType.ISocket,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
emitting: dispensing,
|
||||
emissionLvl: 0,
|
||||
cooldownUntil: 0,
|
||||
content: [dispensing],
|
||||
maxContent: 1,
|
||||
});
|
||||
};
|
||||
|
||||
export const NewOSocket = (name: string, x: number, y: number) => {
|
||||
myrian.devices.push({
|
||||
name,
|
||||
type: DeviceType.OSocket,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
currentRequest: getNextISocketRequest(0),
|
||||
content: [],
|
||||
maxContent: 1,
|
||||
});
|
||||
};
|
||||
|
||||
export const NewLock = (name: string, x: number, y: number) => {
|
||||
const lock: Lock = {
|
||||
name,
|
||||
type: DeviceType.Lock,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
};
|
||||
myrian.devices.push(lock);
|
||||
return lock;
|
||||
};
|
||||
|
||||
export const NewBattery = (name: string, x: number, y: number) => {
|
||||
myrian.devices.push({
|
||||
name,
|
||||
type: DeviceType.Battery,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
tier: 0,
|
||||
energy: 64,
|
||||
maxEnergy: 64,
|
||||
});
|
||||
};
|
||||
|
||||
export const loadMyrian = (save: string) => {
|
||||
if (!save) return;
|
||||
// const savedFactory = JSON.parse(save);
|
||||
// Object.assign(factory, savedFactory);
|
||||
};
|
||||
|
||||
export const resetMyrian = () => {
|
||||
myrian.vulns = 0;
|
||||
myrian.totalVulns = 0;
|
||||
myrian.devices = [];
|
||||
myrian.glitches = { ...defaultGlitches };
|
||||
myrian.rust = {};
|
||||
|
||||
Object.assign(myrian, defaultMyrian);
|
||||
|
||||
NewBus("alice", Math.floor(myrianSize / 2), Math.floor(myrianSize / 2));
|
||||
|
||||
NewISocket("isocket0", Math.floor(myrianSize / 4), 0, Component.R0);
|
||||
NewISocket("isocket1", Math.floor(myrianSize / 2), 0, Component.G0);
|
||||
NewISocket("isocket2", Math.floor((myrianSize * 3) / 4), 0, Component.B0);
|
||||
|
||||
NewOSocket("osocket0", Math.floor(myrianSize / 4), Math.floor(myrianSize - 1));
|
||||
NewOSocket("osocket1", Math.floor(myrianSize / 2), Math.floor(myrianSize - 1));
|
||||
NewOSocket("osocket2", Math.floor((myrianSize * 3) / 4), Math.floor(myrianSize - 1));
|
||||
};
|
||||
|
||||
setInterval(() => {
|
||||
myrian.devices.forEach((device) => {
|
||||
if (device.type !== DeviceType.Battery) return;
|
||||
const up = Math.pow(2, device.tier + 1);
|
||||
device.energy = Math.min(device.energy + up, device.maxEnergy);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
setInterval(() => {
|
||||
const segmentation = myrian.glitches[Glitch.Segmentation];
|
||||
for (let i = 0; i < segmentation; i++) {
|
||||
const x = Math.floor(Math.random() * myrianSize);
|
||||
const y = Math.floor(Math.random() * myrianSize);
|
||||
if (findDevice([x, y])) continue;
|
||||
NewLock(`lock-${x}-${y}`, x, y);
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
setInterval(() => {
|
||||
myrian.rust = {};
|
||||
const rust = myrian.glitches[Glitch.Rust];
|
||||
for (let i = 0; i < rust * 3; i++) {
|
||||
const x = Math.floor(Math.random() * myrianSize);
|
||||
const y = Math.floor(Math.random() * myrianSize);
|
||||
myrian.rust[`${x}:${y}`] = true;
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
const clamp = (min: number, v: number, max: number) => Math.min(Math.max(v, min), max);
|
||||
let globalOffset = 0;
|
||||
const dirDiff = (v: number): number => {
|
||||
globalOffset++;
|
||||
const r = Math.random();
|
||||
const d = v - (myrianSize - 1) / 2;
|
||||
const h = d > 0 ? -1 : 1;
|
||||
|
||||
const dv = Math.floor(r * 3 + h * Math.random() * Math.sin(globalOffset * 0.05) * Math.abs(d)) - 1;
|
||||
return clamp(-1, dv, 1);
|
||||
};
|
||||
|
||||
const isEmpty = (x: number, y: number) => {
|
||||
if (!inMyrianBounds(x, y)) return false;
|
||||
return !findDevice([x, y]);
|
||||
};
|
||||
|
||||
const dirs = [
|
||||
[0, 1],
|
||||
[0, -1],
|
||||
[1, 0],
|
||||
[-1, 0],
|
||||
];
|
||||
|
||||
const applyRoaming = () => {
|
||||
const roaming = myrian.glitches[Glitch.Roaming];
|
||||
setTimeout(applyRoaming, roamingTime(roaming));
|
||||
if (roaming === 0) return;
|
||||
myrian.devices.forEach((device) => {
|
||||
if (device.type !== DeviceType.OSocket && device.type !== DeviceType.ISocket) return;
|
||||
if (device.isBusy) return;
|
||||
let canMove = false;
|
||||
for (const dir of dirs) {
|
||||
const [dx, dy] = dir;
|
||||
if (isEmpty(device.x + dx, device.y + dy)) {
|
||||
canMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let x = -1;
|
||||
let y = -1;
|
||||
if (canMove) {
|
||||
let dx = dirDiff(device.x);
|
||||
let dy = dirDiff(device.y);
|
||||
|
||||
if (dx !== 0 && dy !== 0) {
|
||||
if (Math.random() > 0.5) {
|
||||
dx = 0;
|
||||
} else {
|
||||
dy = 0;
|
||||
}
|
||||
}
|
||||
x = device.x + dx;
|
||||
y = device.y + dy;
|
||||
} else {
|
||||
x = Math.floor(Math.random() * myrianSize);
|
||||
y = Math.floor(Math.random() * myrianSize);
|
||||
}
|
||||
|
||||
if (findDevice([x, y])) return;
|
||||
if (!inMyrianBounds(x, y)) return;
|
||||
device.x = x;
|
||||
device.y = y;
|
||||
});
|
||||
};
|
||||
|
||||
setTimeout(applyRoaming, 0);
|
||||
|
||||
resetMyrian();
|
@ -1,22 +1,11 @@
|
||||
import {
|
||||
Bus,
|
||||
Device,
|
||||
DeviceType,
|
||||
ContainerDevice,
|
||||
Component,
|
||||
ISocket,
|
||||
OSocket,
|
||||
Reducer,
|
||||
Cache,
|
||||
Lock,
|
||||
BaseDevice,
|
||||
DeviceID,
|
||||
Glitch,
|
||||
Battery,
|
||||
} from "@nsdefs";
|
||||
import { myrian, myrianSize } from "./Helper";
|
||||
import { Device, DeviceType, Component, DeviceID, Glitch } from "@nsdefs";
|
||||
import { glitchMult } from "./formulas/glitches";
|
||||
import { pickOne } from "./utils";
|
||||
import { componentTiers } from "./formulas/components";
|
||||
import { NewBattery, NewBus, NewCache, NewISocket, NewLock, NewOSocket, NewReducer } from "./NewDevices";
|
||||
import { startRoaming } from "./glitches/roaming";
|
||||
import { startRust } from "./glitches/rust";
|
||||
import { startSegmentation } from "./glitches/segmentation";
|
||||
|
||||
export interface Myrian {
|
||||
vulns: number;
|
||||
@ -26,100 +15,30 @@ export interface Myrian {
|
||||
rust: Record<string, boolean>;
|
||||
}
|
||||
|
||||
export const distance = (a: Device, b: Device) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
||||
export const distanceCoord2D = (a: Device, coord: [number, number]) =>
|
||||
Math.abs(a.x - coord[0]) + Math.abs(a.y - coord[1]);
|
||||
export const myrianSize = 12;
|
||||
|
||||
export const adjacent = (a: Device, b: Device) => distance(a, b) === 1;
|
||||
export const adjacentCoord2D = (a: Device, coord: [number, number]) => distanceCoord2D(a, coord) === 1;
|
||||
const defaultGlitches = Object.values(Glitch).reduce((acc, g) => ({ ...acc, [g]: 0 }), {}) as Record<Glitch, number>;
|
||||
|
||||
export const inventoryMatches = (a: Component[], b: Component[]) => {
|
||||
if (a.length != b.length) return false;
|
||||
return a.every((i) => b.includes(i));
|
||||
export const myrian: Myrian = {
|
||||
vulns: 0,
|
||||
totalVulns: 0,
|
||||
devices: [],
|
||||
glitches: { ...defaultGlitches },
|
||||
rust: {},
|
||||
};
|
||||
|
||||
export const loadMyrian = (save: string) => {
|
||||
resetMyrian();
|
||||
startRoaming();
|
||||
startRust();
|
||||
startSegmentation();
|
||||
if (!save) return;
|
||||
// const savedMyrian = JSON.parse(save);
|
||||
// Object.assign(myrian, savedMyrian);
|
||||
};
|
||||
|
||||
export const inMyrianBounds = (x: number, y: number) => x >= 0 && x < myrianSize && y >= 0 && y < myrianSize;
|
||||
|
||||
export const vulnsMap: Record<Component, number> = {
|
||||
// tier 0
|
||||
[Component.R0]: 1,
|
||||
[Component.G0]: 1,
|
||||
[Component.B0]: 1,
|
||||
|
||||
// tier 1
|
||||
[Component.R1]: 4,
|
||||
[Component.G1]: 4,
|
||||
[Component.B1]: 4,
|
||||
|
||||
[Component.Y1]: 4,
|
||||
[Component.C1]: 4,
|
||||
[Component.M1]: 4,
|
||||
|
||||
// tier 2
|
||||
[Component.R2]: 16,
|
||||
[Component.G2]: 16,
|
||||
[Component.B2]: 16,
|
||||
|
||||
[Component.Y2]: 16,
|
||||
[Component.C2]: 16,
|
||||
[Component.M2]: 16,
|
||||
|
||||
[Component.W2]: 16,
|
||||
|
||||
// tier 3
|
||||
[Component.R3]: 64,
|
||||
[Component.G3]: 64,
|
||||
[Component.B3]: 64,
|
||||
|
||||
[Component.Y3]: 64,
|
||||
[Component.C3]: 64,
|
||||
[Component.M3]: 64,
|
||||
|
||||
[Component.W3]: 64,
|
||||
|
||||
// tier 4
|
||||
[Component.R4]: 256,
|
||||
[Component.G4]: 256,
|
||||
[Component.B4]: 256,
|
||||
|
||||
[Component.Y4]: 256,
|
||||
[Component.C4]: 256,
|
||||
[Component.M4]: 256,
|
||||
|
||||
[Component.W4]: 256,
|
||||
|
||||
// tier 5
|
||||
[Component.R5]: 1024,
|
||||
[Component.G5]: 1024,
|
||||
[Component.B5]: 1024,
|
||||
|
||||
[Component.Y5]: 1024,
|
||||
[Component.C5]: 1024,
|
||||
[Component.M5]: 1024,
|
||||
|
||||
[Component.W5]: 1024,
|
||||
|
||||
// tier 6
|
||||
[Component.Y6]: 4096,
|
||||
[Component.C6]: 4096,
|
||||
[Component.M6]: 4096,
|
||||
|
||||
[Component.W6]: 4096,
|
||||
|
||||
// tier 7
|
||||
[Component.W7]: 16384,
|
||||
};
|
||||
|
||||
export const isDeviceContainer = (device: BaseDevice): device is ContainerDevice => "content" in device;
|
||||
|
||||
export const isDeviceBus = (d: Device): d is Bus => d.type === DeviceType.Bus;
|
||||
export const isDeviceISocket = (d: Device): d is ISocket => d.type === DeviceType.ISocket;
|
||||
export const isDeviceOSocket = (d: Device): d is OSocket => d.type === DeviceType.OSocket;
|
||||
export const isDeviceReducer = (d: Device): d is Reducer => d.type === DeviceType.Reducer;
|
||||
export const isDeviceCache = (d: Device): d is Cache => d.type === DeviceType.Cache;
|
||||
export const isDeviceLock = (d: Device): d is Lock => d.type === DeviceType.Lock;
|
||||
export const isDeviceBattery = (d: Device): d is Battery => d.type === DeviceType.Battery;
|
||||
|
||||
export const findDevice = (id: DeviceID, type?: DeviceType): Device | undefined =>
|
||||
myrian.devices.find(
|
||||
(e) => (typeof id === "string" ? e.name === id : e.x === id[0] && e.y === id[1]) && (!type || type === e.type),
|
||||
@ -136,16 +55,28 @@ export const getTotalGlitchMult = () =>
|
||||
return acc * glitchMult(glitch as Glitch, lvl);
|
||||
}, 1);
|
||||
|
||||
// DO NOT use `Object.keys` on a Rustable because it will return way more than just the rustable stats.
|
||||
const rustStats: (keyof Rustable)[] = ["moveLvl", "transferLvl", "reduceLvl", "installLvl", "maxEnergy"];
|
||||
type Rustable = Pick<Bus, "moveLvl" | "transferLvl" | "reduceLvl" | "installLvl" | "maxEnergy">;
|
||||
|
||||
export const rustBus = (bus: Bus, rust: number) => {
|
||||
const rustable = bus as Rustable;
|
||||
const nonZero = rustStats.filter((stat) => rustable[stat] > 0);
|
||||
const chosen = pickOne(nonZero);
|
||||
rustable[chosen] = Math.max(0, rustable[chosen] - rust * 0.1);
|
||||
|
||||
// cap energy when maxEnergy is reduced
|
||||
bus.energy = Math.min(bus.energy, bus.maxEnergy);
|
||||
export const getNextOSocketRequest = (tier: number) => {
|
||||
const potential = componentTiers.slice(0, tier + 1).flat();
|
||||
return new Array(Math.floor(Math.pow(Math.random() * tier, 0.75) + 1)).fill(null).map(() => pickOne(potential));
|
||||
};
|
||||
|
||||
export const countDevices = (type: DeviceType) =>
|
||||
myrian.devices.reduce((acc, d) => (d.type === type ? acc + 1 : acc), 0);
|
||||
|
||||
export const resetMyrian = () => {
|
||||
myrian.vulns = 0;
|
||||
myrian.totalVulns = 0;
|
||||
myrian.devices = [];
|
||||
myrian.glitches = { ...defaultGlitches };
|
||||
myrian.rust = {};
|
||||
|
||||
NewBus("alice", Math.floor(myrianSize / 2), Math.floor(myrianSize / 2));
|
||||
|
||||
NewISocket("isocket0", Math.floor(myrianSize / 4), 0, Component.R0);
|
||||
NewISocket("isocket1", Math.floor(myrianSize / 2), 0, Component.G0);
|
||||
NewISocket("isocket2", Math.floor((myrianSize * 3) / 4), 0, Component.B0);
|
||||
|
||||
NewOSocket("osocket0", Math.floor(myrianSize / 4), Math.floor(myrianSize - 1));
|
||||
NewOSocket("osocket1", Math.floor(myrianSize / 2), Math.floor(myrianSize - 1));
|
||||
NewOSocket("osocket2", Math.floor((myrianSize * 3) / 4), Math.floor(myrianSize - 1));
|
||||
};
|
||||
|
109
src/Myrian/NewDevices.ts
Normal file
109
src/Myrian/NewDevices.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { Battery, Bus, Cache, Component, DeviceType, ISocket, Lock, OSocket, Reducer } from "@nsdefs";
|
||||
import { myrian } from "./Myrian";
|
||||
import { getNextOSocketRequest } from "./Myrian";
|
||||
|
||||
export const NewBus = (name: string, x: number, y: number) => {
|
||||
const bus: Bus = {
|
||||
name,
|
||||
type: DeviceType.Bus,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
content: [],
|
||||
maxContent: 1,
|
||||
|
||||
moveLvl: 0,
|
||||
transferLvl: 0,
|
||||
reduceLvl: 0,
|
||||
installLvl: 0,
|
||||
energy: 16,
|
||||
maxEnergy: 16,
|
||||
};
|
||||
myrian.devices.push(bus);
|
||||
};
|
||||
|
||||
export const NewCache = (name: string, x: number, y: number) => {
|
||||
const cache: Cache = {
|
||||
name,
|
||||
type: DeviceType.Cache,
|
||||
isBusy: false,
|
||||
content: [],
|
||||
maxContent: 1,
|
||||
x,
|
||||
y,
|
||||
};
|
||||
myrian.devices.push(cache);
|
||||
return cache;
|
||||
};
|
||||
|
||||
export const NewReducer = (name: string, x: number, y: number) => {
|
||||
const reducer: Reducer = {
|
||||
name,
|
||||
type: DeviceType.Reducer,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
content: [],
|
||||
maxContent: 2,
|
||||
tier: 1,
|
||||
};
|
||||
myrian.devices.push(reducer);
|
||||
return reducer;
|
||||
};
|
||||
|
||||
export const NewISocket = (name: string, x: number, y: number, emitting: Component) => {
|
||||
const isocket: ISocket = {
|
||||
name,
|
||||
type: DeviceType.ISocket,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
emitting: emitting,
|
||||
emissionLvl: 0,
|
||||
cooldownUntil: 0,
|
||||
content: [emitting],
|
||||
maxContent: 1,
|
||||
};
|
||||
myrian.devices.push(isocket);
|
||||
};
|
||||
|
||||
export const NewOSocket = (name: string, x: number, y: number) => {
|
||||
const osocket: OSocket = {
|
||||
name,
|
||||
type: DeviceType.OSocket,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
currentRequest: getNextOSocketRequest(0),
|
||||
content: [],
|
||||
maxContent: 1,
|
||||
};
|
||||
myrian.devices.push(osocket);
|
||||
return osocket;
|
||||
};
|
||||
|
||||
export const NewLock = (name: string, x: number, y: number) => {
|
||||
const lock: Lock = {
|
||||
name,
|
||||
type: DeviceType.Lock,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
};
|
||||
myrian.devices.push(lock);
|
||||
return lock;
|
||||
};
|
||||
|
||||
export const NewBattery = (name: string, x: number, y: number) => {
|
||||
const battery: Battery = {
|
||||
name,
|
||||
type: DeviceType.Battery,
|
||||
isBusy: false,
|
||||
x,
|
||||
y,
|
||||
tier: 0,
|
||||
energy: 64,
|
||||
maxEnergy: 64,
|
||||
};
|
||||
myrian.devices.push(battery);
|
||||
};
|
67
src/Myrian/formulas/costs.ts
Normal file
67
src/Myrian/formulas/costs.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { DeviceType } from "@nsdefs";
|
||||
|
||||
// parameters for a exponential formula, a^(b*X+c)+d
|
||||
type ExponentialFormulaParams = [number, number, number, number];
|
||||
|
||||
// Parameters for a cost that shouldn't be available. Such as upgrading the max energy of a isocket.
|
||||
const NA: ExponentialFormulaParams = [Infinity, Infinity, Infinity, Infinity];
|
||||
|
||||
type DeviceScale = Record<DeviceType, ExponentialFormulaParams>;
|
||||
|
||||
// Default scale for each device type, helps simplify code.
|
||||
const defaultScale = Object.keys(DeviceType).reduce((acc, type) => ({ ...acc, [type]: NA }), {}) as DeviceScale;
|
||||
|
||||
// Exponential formula, a^(b*X+c)+d
|
||||
const exp = (p: ExponentialFormulaParams, x: number): number => Math.pow(p[0], p[1] * x + p[2]) + p[3];
|
||||
|
||||
// Wrap exp with a specific scale for each device type.
|
||||
const makeExpFunction = (p: Partial<DeviceScale>) => {
|
||||
const scale = { ...defaultScale, ...p };
|
||||
return (type: DeviceType, x: number) => exp(scale[type], x);
|
||||
};
|
||||
|
||||
export const upgradeMaxContentCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [8, 0.5, 2, 0],
|
||||
[DeviceType.ISocket]: [4, 1, 5, 0],
|
||||
[DeviceType.Reducer]: [Infinity, 1, -1, 4095],
|
||||
[DeviceType.Cache]: [1.2, 10, 0, 63],
|
||||
});
|
||||
|
||||
export const upgradeTierCost = makeExpFunction({
|
||||
[DeviceType.Reducer]: [1.5, 1, 2, 0],
|
||||
[DeviceType.Battery]: [2, 1, 3, 0],
|
||||
});
|
||||
|
||||
export const upgradeEmissionCost = makeExpFunction({
|
||||
[DeviceType.ISocket]: [2, 1, 3, 0],
|
||||
});
|
||||
|
||||
export const upgradeMoveLvlCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
});
|
||||
|
||||
export const upgradeTransferLvlCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
});
|
||||
|
||||
export const upgradeReduceLvlCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
});
|
||||
|
||||
export const upgradeInstallLvlCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
});
|
||||
|
||||
export const upgradeMaxEnergyCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
[DeviceType.Battery]: [1.1, 1, 3, 8],
|
||||
});
|
||||
|
||||
export const installDeviceCost = makeExpFunction({
|
||||
[DeviceType.Bus]: [4, 0.5, 2, 0],
|
||||
[DeviceType.ISocket]: [2, 1, 4, 0],
|
||||
[DeviceType.OSocket]: [4, 1, 3, 0],
|
||||
[DeviceType.Reducer]: [1.5, 1, 2, 0],
|
||||
[DeviceType.Cache]: [1.2, 10, 0, 63],
|
||||
[DeviceType.Battery]: [1.2, 10, 0, 63],
|
||||
});
|
@ -1,126 +0,0 @@
|
||||
import { DeviceType } from "@nsdefs";
|
||||
import { myrian } from "../Helper";
|
||||
import { componentTiers } from "./components";
|
||||
import { pickOne } from "../utils";
|
||||
|
||||
type FactoryFormulaParams = [number, number, number, number];
|
||||
|
||||
const maxContentScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [8, 0.5, 2, 0],
|
||||
[DeviceType.ISocket]: [4, 1, 5, 0],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, 1, -1, 4095],
|
||||
[DeviceType.Cache]: [1.2, 10, 0, 63],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
|
||||
};
|
||||
|
||||
// a^(b*X+c)+d
|
||||
const exp = (p: FactoryFormulaParams, x: number): number => Math.pow(p[0], p[1] * x + p[2]) + p[3];
|
||||
|
||||
export const upgradeMaxContentCost = (type: DeviceType, currentMaxContent: number): number =>
|
||||
exp(maxContentScale[type], currentMaxContent);
|
||||
|
||||
const countDevices = (type: DeviceType) => myrian.devices.reduce((acc, d) => (d.type === type ? acc + 1 : acc), 0);
|
||||
|
||||
const deviceScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [4, 0.5, 2, 0],
|
||||
[DeviceType.ISocket]: [2, 1, 4, 0],
|
||||
[DeviceType.OSocket]: [4, 1, 3, 0],
|
||||
[DeviceType.Reducer]: [1.5, 1, 2, 0],
|
||||
[DeviceType.Cache]: [1.2, 10, 0, 63],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [1.2, 10, 0, 63],
|
||||
};
|
||||
|
||||
export const deviceCost = (type: DeviceType, count?: number) =>
|
||||
exp(deviceScale[type], count === undefined ? countDevices(type) : count);
|
||||
|
||||
export const getNextISocketRequest = (tier: number) => {
|
||||
const potential = componentTiers.slice(0, tier + 1).flat();
|
||||
return new Array(Math.floor(Math.pow(Math.random() * tier, 0.75) + 1)).fill(null).map(() => pickOne(potential));
|
||||
};
|
||||
|
||||
const tierScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.ISocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [1.5, 1, 2, 0],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [2, 1, 3, 0],
|
||||
};
|
||||
|
||||
export const tierCost = (type: DeviceType, tier: number) => exp(tierScale[type], tier);
|
||||
|
||||
const emissionScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.ISocket]: [2, 1, 3, 0],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
|
||||
};
|
||||
|
||||
export const emissionCost = (type: DeviceType, emissionLvl: number) => exp(emissionScale[type], emissionLvl);
|
||||
|
||||
const moveLvlScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
[DeviceType.ISocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
|
||||
};
|
||||
|
||||
export const moveLvlCost = (type: DeviceType, moveLvl: number) => exp(moveLvlScale[type], moveLvl);
|
||||
|
||||
const transferLvlScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
[DeviceType.ISocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
|
||||
};
|
||||
|
||||
export const transferLvlCost = (type: DeviceType, transferLvl: number) => exp(transferLvlScale[type], transferLvl);
|
||||
|
||||
const reduceLvlScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
[DeviceType.ISocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
|
||||
};
|
||||
|
||||
export const reduceLvlCost = (type: DeviceType, reduceLvl: number) => exp(reduceLvlScale[type], reduceLvl);
|
||||
|
||||
const installLvlScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
[DeviceType.ISocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
|
||||
};
|
||||
|
||||
export const installLvlCost = (type: DeviceType, installLvl: number) => exp(installLvlScale[type], installLvl);
|
||||
|
||||
const maxEnergyScale: Record<DeviceType, FactoryFormulaParams> = {
|
||||
[DeviceType.Bus]: [2, 1, 3, 0],
|
||||
[DeviceType.ISocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.OSocket]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
|
||||
[DeviceType.Battery]: [1.1, 1, 3, 8],
|
||||
};
|
||||
|
||||
export const maxEnergyCost = (type: DeviceType, maxEnergy: number) => exp(maxEnergyScale[type], maxEnergy);
|
@ -14,8 +14,8 @@ export const glitchMaxLvl: Record<Glitch, number> = {
|
||||
|
||||
export const giltchMultCoefficients: Record<Glitch, number> = {
|
||||
[Glitch.Segmentation]: 1,
|
||||
[Glitch.Roaming]: 0, // 1,
|
||||
[Glitch.Encryption]: 0, // 0.1,
|
||||
[Glitch.Roaming]: 1,
|
||||
[Glitch.Encryption]: 0.1,
|
||||
[Glitch.Magnetism]: 0.2,
|
||||
[Glitch.Rust]: 1,
|
||||
[Glitch.Friction]: 0.2,
|
||||
@ -24,6 +24,7 @@ export const giltchMultCoefficients: Record<Glitch, number> = {
|
||||
[Glitch.Jamming]: 0.2,
|
||||
};
|
||||
|
||||
// vulns mult by glitch lvl
|
||||
export const glitchMult = (glitch: Glitch, lvl: number) => 1 + lvl * giltchMultCoefficients[glitch];
|
||||
|
||||
// move hinderance
|
||||
@ -41,4 +42,5 @@ export const jammingMult = (lvl: number) => Math.pow(1.3, lvl);
|
||||
// energy loss
|
||||
export const magnetismLoss = (lvl: number) => lvl;
|
||||
|
||||
// How often isocket/osocke move
|
||||
export const roamingTime = (lvl: number) => 30000 * Math.pow(0.7, lvl);
|
||||
|
@ -1,206 +1,74 @@
|
||||
import { Component, Recipe } from "@nsdefs";
|
||||
|
||||
export const Tier1Recipes: Recipe[] = [
|
||||
{
|
||||
input: [Component.R0, Component.R0],
|
||||
output: Component.R1,
|
||||
},
|
||||
{
|
||||
input: [Component.G0, Component.G0],
|
||||
output: Component.G1,
|
||||
},
|
||||
{
|
||||
input: [Component.B0, Component.B0],
|
||||
output: Component.B1,
|
||||
},
|
||||
const make = (input: Component[], output: Component): Recipe => ({ input, output });
|
||||
|
||||
{
|
||||
input: [Component.R0, Component.G0],
|
||||
output: Component.Y1,
|
||||
},
|
||||
{
|
||||
input: [Component.G0, Component.B0],
|
||||
output: Component.C1,
|
||||
},
|
||||
{
|
||||
input: [Component.B0, Component.R0],
|
||||
output: Component.M1,
|
||||
},
|
||||
export const Tier1Recipes: Recipe[] = [
|
||||
make([Component.R0, Component.R0], Component.R1),
|
||||
make([Component.G0, Component.G0], Component.G1),
|
||||
make([Component.B0, Component.B0], Component.B1),
|
||||
|
||||
make([Component.R0, Component.G0], Component.Y1),
|
||||
make([Component.G0, Component.B0], Component.C1),
|
||||
make([Component.B0, Component.R0], Component.M1),
|
||||
];
|
||||
|
||||
export const Tier2Recipes: Recipe[] = [
|
||||
// primary
|
||||
{
|
||||
input: [Component.R1, Component.R1],
|
||||
output: Component.R2,
|
||||
},
|
||||
{
|
||||
input: [Component.G1, Component.G1],
|
||||
output: Component.G2,
|
||||
},
|
||||
{
|
||||
input: [Component.B1, Component.B1],
|
||||
output: Component.B2,
|
||||
},
|
||||
make([Component.R1, Component.R1], Component.R2),
|
||||
make([Component.G1, Component.G1], Component.G2),
|
||||
make([Component.B1, Component.B1], Component.B2),
|
||||
|
||||
// secondary
|
||||
{
|
||||
input: [Component.R1, Component.G1],
|
||||
output: Component.Y2,
|
||||
},
|
||||
{
|
||||
input: [Component.G1, Component.B1],
|
||||
output: Component.C2,
|
||||
},
|
||||
{
|
||||
input: [Component.B1, Component.R1],
|
||||
output: Component.M2,
|
||||
},
|
||||
make([Component.R1, Component.G1], Component.Y2),
|
||||
make([Component.G1, Component.B1], Component.C2),
|
||||
make([Component.B1, Component.R1], Component.M2),
|
||||
|
||||
// white
|
||||
{
|
||||
input: [Component.Y1, Component.C1, Component.M1],
|
||||
output: Component.W2,
|
||||
},
|
||||
make([Component.Y1, Component.C1, Component.M1], Component.W2),
|
||||
];
|
||||
|
||||
export const Tier3Recipes: Recipe[] = [
|
||||
// primary
|
||||
{
|
||||
input: [Component.R2, Component.R2],
|
||||
output: Component.R3,
|
||||
},
|
||||
{
|
||||
input: [Component.G2, Component.G2],
|
||||
output: Component.G3,
|
||||
},
|
||||
{
|
||||
input: [Component.B2, Component.B2],
|
||||
output: Component.B3,
|
||||
},
|
||||
make([Component.R2, Component.R2], Component.R3),
|
||||
make([Component.G2, Component.G2], Component.G3),
|
||||
make([Component.B2, Component.B2], Component.B3),
|
||||
|
||||
// secondary
|
||||
{
|
||||
input: [Component.R2, Component.G2],
|
||||
output: Component.Y3,
|
||||
},
|
||||
{
|
||||
input: [Component.G2, Component.B2],
|
||||
output: Component.C3,
|
||||
},
|
||||
{
|
||||
input: [Component.B2, Component.R2],
|
||||
output: Component.M3,
|
||||
},
|
||||
make([Component.R2, Component.G2], Component.Y3),
|
||||
make([Component.G2, Component.B2], Component.C3),
|
||||
make([Component.B2, Component.R2], Component.M3),
|
||||
|
||||
// white
|
||||
{
|
||||
input: [Component.Y2, Component.C2, Component.M2],
|
||||
output: Component.W3,
|
||||
},
|
||||
make([Component.Y2, Component.C2, Component.M2], Component.W3),
|
||||
];
|
||||
|
||||
export const Tier4Recipes: Recipe[] = [
|
||||
// primary
|
||||
{
|
||||
input: [Component.R3, Component.R3],
|
||||
output: Component.R4,
|
||||
},
|
||||
{
|
||||
input: [Component.G3, Component.G3],
|
||||
output: Component.G4,
|
||||
},
|
||||
{
|
||||
input: [Component.B3, Component.B3],
|
||||
output: Component.B4,
|
||||
},
|
||||
make([Component.R3, Component.R3], Component.R4),
|
||||
make([Component.G3, Component.G3], Component.G4),
|
||||
make([Component.B3, Component.B3], Component.B4),
|
||||
|
||||
// secondary
|
||||
{
|
||||
input: [Component.R3, Component.G3],
|
||||
output: Component.Y4,
|
||||
},
|
||||
{
|
||||
input: [Component.G3, Component.B3],
|
||||
output: Component.C4,
|
||||
},
|
||||
{
|
||||
input: [Component.B3, Component.R3],
|
||||
output: Component.M4,
|
||||
},
|
||||
make([Component.R3, Component.G3], Component.Y4),
|
||||
make([Component.G3, Component.B3], Component.C4),
|
||||
make([Component.B3, Component.R3], Component.M4),
|
||||
|
||||
// white
|
||||
{
|
||||
input: [Component.Y3, Component.C3, Component.M3],
|
||||
output: Component.W4,
|
||||
},
|
||||
make([Component.Y3, Component.C3, Component.M3], Component.W4),
|
||||
];
|
||||
|
||||
export const Tier5Recipes: Recipe[] = [
|
||||
// primary
|
||||
{
|
||||
input: [Component.R4, Component.R4],
|
||||
output: Component.R5,
|
||||
},
|
||||
{
|
||||
input: [Component.G4, Component.G4],
|
||||
output: Component.G5,
|
||||
},
|
||||
{
|
||||
input: [Component.B4, Component.B4],
|
||||
output: Component.B5,
|
||||
},
|
||||
make([Component.R4, Component.R4], Component.R5),
|
||||
make([Component.G4, Component.G4], Component.G5),
|
||||
make([Component.B4, Component.B4], Component.B5),
|
||||
|
||||
// secondary
|
||||
{
|
||||
input: [Component.R4, Component.G4],
|
||||
output: Component.Y5,
|
||||
},
|
||||
{
|
||||
input: [Component.G4, Component.B4],
|
||||
output: Component.C5,
|
||||
},
|
||||
{
|
||||
input: [Component.B4, Component.R4],
|
||||
output: Component.M5,
|
||||
},
|
||||
make([Component.R4, Component.G4], Component.Y5),
|
||||
make([Component.G4, Component.B4], Component.C5),
|
||||
make([Component.B4, Component.R4], Component.M5),
|
||||
|
||||
// white
|
||||
{
|
||||
input: [Component.Y4, Component.C4, Component.M4],
|
||||
output: Component.W5,
|
||||
},
|
||||
make([Component.Y4, Component.C4, Component.M4], Component.W5),
|
||||
];
|
||||
|
||||
export const Tier6Recipes: Recipe[] = [
|
||||
// secondary
|
||||
{
|
||||
input: [Component.R5, Component.G5],
|
||||
output: Component.Y6,
|
||||
},
|
||||
{
|
||||
input: [Component.G5, Component.B5],
|
||||
output: Component.C6,
|
||||
},
|
||||
{
|
||||
input: [Component.B5, Component.R5],
|
||||
output: Component.M6,
|
||||
},
|
||||
make([Component.R5, Component.G5], Component.Y6),
|
||||
make([Component.G5, Component.B5], Component.C6),
|
||||
make([Component.B5, Component.R5], Component.M6),
|
||||
|
||||
// white
|
||||
{
|
||||
input: [Component.Y5, Component.C5, Component.M5],
|
||||
output: Component.W6,
|
||||
},
|
||||
make([Component.Y5, Component.C5, Component.M5], Component.W6),
|
||||
];
|
||||
|
||||
export const Tier7Recipes: Recipe[] = [
|
||||
// white
|
||||
{
|
||||
input: [Component.Y6, Component.C6, Component.M6],
|
||||
output: Component.W7,
|
||||
},
|
||||
];
|
||||
export const Tier7Recipes: Recipe[] = [make([Component.Y6, Component.C6, Component.M6], Component.W7)];
|
||||
|
||||
export const recipes: Recipe[][] = [
|
||||
[],
|
||||
|
@ -1,5 +1,14 @@
|
||||
// speed to move between 2 tiles
|
||||
export const moveSpeed = (level: number) => 1000 / (level + 10);
|
||||
|
||||
// speed to reduce components
|
||||
export const reduceSpeed = (level: number) => 50000 / (level + 10);
|
||||
|
||||
// speed to transfer components between devices
|
||||
export const transferSpeed = (level: number) => 1000 / (level + 10);
|
||||
|
||||
// speed to install / uninstall devices and tweak ISockets
|
||||
export const installSpeed = (level: number) => 100000 / (level + 10);
|
||||
export const isocketSpeed = (level: number) => 100000 / (level + 10);
|
||||
|
||||
// time until ISocket refreshes
|
||||
export const emissionSpeed = (level: number) => 100000 / (level + 10);
|
||||
|
12
src/Myrian/glitches/battery.ts
Normal file
12
src/Myrian/glitches/battery.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { DeviceType } from "@nsdefs";
|
||||
import { myrian } from "../Myrian";
|
||||
|
||||
const applyBattery = () => {
|
||||
myrian.devices.forEach((device) => {
|
||||
if (device.type !== DeviceType.Battery) return;
|
||||
const up = Math.pow(2, device.tier + 1);
|
||||
device.energy = Math.min(device.energy + up, device.maxEnergy);
|
||||
});
|
||||
};
|
||||
|
||||
export const startBattery = () => setInterval(applyBattery, 1000);
|
74
src/Myrian/glitches/roaming.ts
Normal file
74
src/Myrian/glitches/roaming.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { DeviceType, Glitch } from "@nsdefs";
|
||||
import { myrian, myrianSize } from "../Myrian";
|
||||
import { findDevice, inMyrianBounds } from "../Myrian";
|
||||
import { roamingTime } from "../formulas/glitches";
|
||||
|
||||
const clamp = (min: number, v: number, max: number) => Math.min(Math.max(v, min), max);
|
||||
|
||||
let globalOffset = 0;
|
||||
|
||||
const dirDiff = (v: number): number => {
|
||||
globalOffset++;
|
||||
const r = Math.random();
|
||||
const d = v - (myrianSize - 1) / 2;
|
||||
const h = d > 0 ? -1 : 1;
|
||||
|
||||
const dv = Math.floor(r * 3 + h * Math.random() * Math.sin(globalOffset * 0.05) * Math.abs(d)) - 1;
|
||||
return clamp(-1, dv, 1);
|
||||
};
|
||||
|
||||
const isEmpty = (x: number, y: number) => {
|
||||
if (!inMyrianBounds(x, y)) return false;
|
||||
return !findDevice([x, y]);
|
||||
};
|
||||
|
||||
const dirs = [
|
||||
[0, 1],
|
||||
[0, -1],
|
||||
[1, 0],
|
||||
[-1, 0],
|
||||
];
|
||||
|
||||
const applyRoaming = () => {
|
||||
const roaming = myrian.glitches[Glitch.Roaming];
|
||||
setTimeout(applyRoaming, roamingTime(roaming));
|
||||
if (roaming === 0) return;
|
||||
myrian.devices.forEach((device) => {
|
||||
if (device.type !== DeviceType.OSocket && device.type !== DeviceType.ISocket) return;
|
||||
if (device.isBusy) return;
|
||||
let canMove = false;
|
||||
for (const dir of dirs) {
|
||||
const [dx, dy] = dir;
|
||||
if (isEmpty(device.x + dx, device.y + dy)) {
|
||||
canMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let x = -1;
|
||||
let y = -1;
|
||||
if (canMove) {
|
||||
let dx = dirDiff(device.x);
|
||||
let dy = dirDiff(device.y);
|
||||
|
||||
if (dx !== 0 && dy !== 0) {
|
||||
if (Math.random() > 0.5) {
|
||||
dx = 0;
|
||||
} else {
|
||||
dy = 0;
|
||||
}
|
||||
}
|
||||
x = device.x + dx;
|
||||
y = device.y + dy;
|
||||
} else {
|
||||
x = Math.floor(Math.random() * myrianSize);
|
||||
y = Math.floor(Math.random() * myrianSize);
|
||||
}
|
||||
|
||||
if (findDevice([x, y])) return;
|
||||
if (!inMyrianBounds(x, y)) return;
|
||||
device.x = x;
|
||||
device.y = y;
|
||||
});
|
||||
};
|
||||
|
||||
export const startRoaming = () => setTimeout(applyRoaming, 0);
|
29
src/Myrian/glitches/rust.ts
Normal file
29
src/Myrian/glitches/rust.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Bus, Glitch } from "@nsdefs";
|
||||
import { myrian, myrianSize } from "../Myrian";
|
||||
import { pickOne } from "../utils";
|
||||
|
||||
const applyRust = () => {
|
||||
myrian.rust = {};
|
||||
const rust = myrian.glitches[Glitch.Rust];
|
||||
for (let i = 0; i < rust * 3; i++) {
|
||||
const x = Math.floor(Math.random() * myrianSize);
|
||||
const y = Math.floor(Math.random() * myrianSize);
|
||||
myrian.rust[`${x}:${y}`] = true;
|
||||
}
|
||||
};
|
||||
|
||||
// DO NOT use `Object.keys` on a Rustable because it will return way more than just the rustable stats.
|
||||
const rustStats: (keyof Rustable)[] = ["moveLvl", "transferLvl", "reduceLvl", "installLvl", "maxEnergy"];
|
||||
type Rustable = Pick<Bus, "moveLvl" | "transferLvl" | "reduceLvl" | "installLvl" | "maxEnergy">;
|
||||
|
||||
export const rustBus = (bus: Bus, rust: number) => {
|
||||
const rustable = bus as Rustable;
|
||||
const nonZero = rustStats.filter((stat) => rustable[stat] > 0);
|
||||
const chosen = pickOne(nonZero);
|
||||
rustable[chosen] = Math.max(0, rustable[chosen] - rust * 0.1);
|
||||
|
||||
// cap energy when maxEnergy is reduced
|
||||
bus.energy = Math.min(bus.energy, bus.maxEnergy);
|
||||
};
|
||||
|
||||
export const startRust = () => setInterval(applyRust, 30000);
|
16
src/Myrian/glitches/segmentation.ts
Normal file
16
src/Myrian/glitches/segmentation.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Glitch } from "@nsdefs";
|
||||
import { myrian, myrianSize } from "../Myrian";
|
||||
import { findDevice } from "../Myrian";
|
||||
import { NewLock } from "../NewDevices";
|
||||
|
||||
const applySegmentation = () => {
|
||||
const segmentation = myrian.glitches[Glitch.Segmentation];
|
||||
for (let i = 0; i < segmentation; i++) {
|
||||
const x = Math.floor(Math.random() * myrianSize);
|
||||
const y = Math.floor(Math.random() * myrianSize);
|
||||
if (findDevice([x, y])) continue;
|
||||
NewLock(`lock-${x}-${y}`, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
export const startSegmentation = () => setInterval(applySegmentation, 30000);
|
@ -1,101 +0,0 @@
|
||||
# Myrian
|
||||
|
||||
Myrian is the name of the OS that the BitNodes run on. Eventually you'll unlock the mechanic by going to the glitch in Ishima and "breaking partially free" of the BN.
|
||||
|
||||
By gaining access to the OS directly you can start to break it apart by generating vulnerabilities (vulns).
|
||||
You do so by interracting with the various devices in the OS, represented by a grid.
|
||||
|
||||
## Devices
|
||||
|
||||
### Bus
|
||||
|
||||
The most important device is the Bus. Here's a few of the things it can do:
|
||||
|
||||
- move, only 1 tile at a time and that tile must be empty. No diagonal.
|
||||
- transfer content, most entity can store items called components, bus are the only device that can transfer components to and from other devices
|
||||
- use other devices, certain devices can be used.
|
||||
|
||||
Performing any action makes all devices involved "busy". If a Bus is transfering content between itself and a cache (chest), they both become busy until the operation finishes.
|
||||
|
||||
Contrary to every other mechanic in the game. Async functions using myrian functions CAN run simultenaously.
|
||||
|
||||
### ISocket
|
||||
|
||||
These devices produce basic components that can be used for other devices, [r0, y0, b0]. They must be picked up by busses and will eventually produce another one after a certain cooldown has passed.
|
||||
|
||||
### OSocket
|
||||
|
||||
These devices request components and produce vulns in return, a bus simply needs to transfer a component into a OSocket content in order to fulfill the request
|
||||
|
||||
### Reducer
|
||||
|
||||
These devices can be used by a bus, when being used they will first check their content, if the content matches one of the recipe they will take some time to consume their content in order to produce a new, upgraded, more valuable component, e.g. r0 + r0 => r1
|
||||
|
||||
### Cache
|
||||
|
||||
These devices act as storage for components.
|
||||
|
||||
### Lock
|
||||
|
||||
These devices cannot be installed. They appear after various conditions are fulfilled in order to block certain tiles.
|
||||
|
||||
### Battery
|
||||
|
||||
These devices are only relevant when the Magnetism glitch is active. It recharges the energy of a bus.
|
||||
|
||||
## Installing
|
||||
|
||||
Bus can install new devices, when they do so a lock will appear over the tile that will eventually become the device. The cost of any device depends on the number of that type of device currently in the OS.
|
||||
|
||||
### Uninstalling
|
||||
|
||||
A bus can remove a device, there is no refund.
|
||||
|
||||
## Tiers
|
||||
|
||||
Currently 2 devices have tiers, reducers and OSockets.
|
||||
|
||||
Upgrading a reducer allows it to reduce components of a higher tier and ONLY that higher tier. A tier 2 reducer can only tier 2 components like r1 + r1 => r2 and loses access to r0 + r0 => r1
|
||||
|
||||
Upgrading a OSocket allows it to request higher tier components (as well as more components at a time).
|
||||
|
||||
## Glitches
|
||||
|
||||
glitches are optional difficulty modifiers that make the myrian more difficult BUT increase the amount of vulns gained.
|
||||
All glitches start at level 0 and must be activated when you chose. They also have a max level that differs from glitch to glitch.
|
||||
|
||||
### Magnetism
|
||||
|
||||
By default bus lose 0 energy when moving. But when this glitch is active they start losing energy, at 0 energy bus move much more slowly. Batteries must be installed and used to charge busses.
|
||||
|
||||
### Friction
|
||||
|
||||
When Friction is active busses move more slowly.
|
||||
|
||||
## Rust
|
||||
|
||||
When rust is active, hidden tiles are set on the Myrian. When a bus steps on one of these hidden tiles one of their upgrade lowers. Higher Rust level means lowers by a larger amount and more rust tiles are set.
|
||||
|
||||
### Isolation
|
||||
|
||||
When Isolation is active busses transfer and charge more slowly.
|
||||
|
||||
## Segmentation
|
||||
|
||||
When Segmentation is active random Locks will spawn on the Myrian. You have to remove these locks or the bord will be overrun with Locks and you won't be able to move.
|
||||
|
||||
### Virtualization
|
||||
|
||||
When Virtualization is active busses install and uninstall devices more slowly.
|
||||
|
||||
### Jamming
|
||||
|
||||
When Jamming is active busses use reducers more slowly.
|
||||
|
||||
## Roaming
|
||||
|
||||
When Roaming is active, isockets and osockets start to move around the map
|
||||
|
||||
## Encryption
|
||||
|
||||
Encryption is the only glitch that's always active. The level of Encryption determines the complexity of the requests made by osockets.
|
22
src/Myrian/ui/BatteryIcon.tsx
Normal file
22
src/Myrian/ui/BatteryIcon.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import { Battery } from "@nsdefs";
|
||||
import BatteryChargingFullIcon from "@mui/icons-material/BatteryChargingFull";
|
||||
import { defaultIconStyle } from "./common";
|
||||
import { styled } from "@mui/styles";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
import { TooltipTier } from "./TooltipTier";
|
||||
import { TooltipEnergy } from "./TooltipEnergy";
|
||||
|
||||
const Template = styled(BatteryChargingFullIcon)(defaultIconStyle);
|
||||
const Icon = <Template />;
|
||||
|
||||
interface IBatteryIconProps {
|
||||
battery: Battery;
|
||||
}
|
||||
|
||||
export const BatteryIcon = ({ battery }: IBatteryIconProps): React.ReactElement => (
|
||||
<DeviceTooltip device={battery} icon={Icon}>
|
||||
<TooltipTier device={battery} />
|
||||
<TooltipEnergy device={battery} />
|
||||
</DeviceTooltip>
|
||||
);
|
27
src/Myrian/ui/BusIcon.tsx
Normal file
27
src/Myrian/ui/BusIcon.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import { defaultIconStyle } from "./common";
|
||||
import DirectionsBusIcon from "@mui/icons-material/DirectionsBus";
|
||||
import { styled } from "@mui/styles";
|
||||
import { Bus } from "@nsdefs";
|
||||
import { TooltipContent } from "./TooltipContent";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
import { TooltipEnergy } from "./TooltipEnergy";
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
const Template = styled(DirectionsBusIcon)(defaultIconStyle);
|
||||
const Icon = <Template />;
|
||||
|
||||
interface IBusIconProps {
|
||||
bus: Bus;
|
||||
}
|
||||
|
||||
export const BusIcon = ({ bus }: IBusIconProps): React.ReactElement => (
|
||||
<DeviceTooltip device={bus} icon={Icon}>
|
||||
<Typography>moveLvl: {bus.moveLvl}</Typography>
|
||||
<Typography>transferLvl: {bus.transferLvl}</Typography>
|
||||
<Typography>reduceLvl: {bus.reduceLvl}</Typography>
|
||||
<Typography>installLvl: {bus.installLvl}</Typography>
|
||||
<TooltipEnergy device={bus} />
|
||||
<TooltipContent device={bus} />
|
||||
</DeviceTooltip>
|
||||
);
|
20
src/Myrian/ui/CacheIcon.tsx
Normal file
20
src/Myrian/ui/CacheIcon.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
import { TooltipContent } from "./TooltipContent";
|
||||
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
|
||||
import { styled } from "@mui/styles";
|
||||
import { defaultIconStyle } from "./common";
|
||||
import { Cache } from "@nsdefs";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
|
||||
const Template = styled(CheckBoxOutlineBlankIcon)(defaultIconStyle);
|
||||
const Icon = <Template />;
|
||||
|
||||
interface ICacheIconProps {
|
||||
cache: Cache;
|
||||
}
|
||||
|
||||
export const CacheIcon = ({ cache }: ICacheIconProps): React.ReactElement => (
|
||||
<DeviceTooltip device={cache} icon={Icon}>
|
||||
<TooltipContent device={cache} />
|
||||
</DeviceTooltip>
|
||||
);
|
14
src/Myrian/ui/ComponentText.tsx
Normal file
14
src/Myrian/ui/ComponentText.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import { Component } from "@nsdefs";
|
||||
import { getComponentColor } from "./common";
|
||||
|
||||
interface IComponent {
|
||||
component: Component;
|
||||
}
|
||||
|
||||
export const ComponentText = ({ component }: IComponent): React.ReactElement => (
|
||||
<span style={{ color: getComponentColor(component) }}>
|
||||
{component}
|
||||
<br />
|
||||
</span>
|
||||
);
|
@ -1,239 +1,33 @@
|
||||
import React from "react";
|
||||
import DirectionsBusIcon from "@mui/icons-material/DirectionsBus";
|
||||
import { styled } from "@mui/system";
|
||||
import { ISocket, Device, DeviceType, Component } from "@nsdefs";
|
||||
import { Device, DeviceType } from "@nsdefs";
|
||||
|
||||
import MoveToInboxIcon from "@mui/icons-material/MoveToInbox";
|
||||
import OutboxIcon from "@mui/icons-material/Outbox";
|
||||
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
|
||||
import MergeTypeIcon from "@mui/icons-material/MergeType";
|
||||
import BatteryChargingFullIcon from "@mui/icons-material/BatteryChargingFull";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import { Tooltip, Typography } from "@mui/material";
|
||||
import { isDeviceContainer } from "../Myrian";
|
||||
import { BusIcon } from "./BusIcon";
|
||||
import { ReducerIcon } from "./Reducer";
|
||||
import { LockIcon } from "./LockIcon";
|
||||
import { CacheIcon } from "./CacheIcon";
|
||||
import { BatteryIcon } from "./BatteryIcon";
|
||||
import { OSocketIcon } from "./OSocketIcon";
|
||||
import { ISocketIcon } from "./ISocketIcon";
|
||||
|
||||
export const cellSize = 48;
|
||||
|
||||
const defaultIconStyle = {
|
||||
width: cellSize + "px",
|
||||
height: cellSize + "px",
|
||||
color: "white",
|
||||
};
|
||||
|
||||
const ColorR = "red";
|
||||
const ColorG = "#7CFC00";
|
||||
const ColorB = "#1E90FF";
|
||||
const ColorY = "yellow";
|
||||
const ColorC = "cyan";
|
||||
const ColorM = "magenta";
|
||||
const ColorW = "whte";
|
||||
|
||||
const itemColorMap: Record<Component, string> = {
|
||||
// tier 0
|
||||
[Component.R0]: ColorR,
|
||||
[Component.G0]: ColorG,
|
||||
[Component.B0]: ColorB,
|
||||
|
||||
// tier 1
|
||||
[Component.R1]: ColorR,
|
||||
[Component.G1]: ColorG,
|
||||
[Component.B1]: ColorB,
|
||||
|
||||
[Component.Y1]: ColorY,
|
||||
[Component.C1]: ColorC,
|
||||
[Component.M1]: ColorM,
|
||||
|
||||
// tier 2
|
||||
[Component.R2]: ColorR,
|
||||
[Component.G2]: ColorG,
|
||||
[Component.B2]: ColorB,
|
||||
|
||||
[Component.Y2]: ColorY,
|
||||
[Component.C2]: ColorC,
|
||||
[Component.M2]: ColorM,
|
||||
|
||||
[Component.W2]: ColorW,
|
||||
|
||||
// tier 3
|
||||
[Component.R3]: ColorR,
|
||||
[Component.G3]: ColorG,
|
||||
[Component.B3]: ColorB,
|
||||
|
||||
[Component.Y3]: ColorY,
|
||||
[Component.C3]: ColorC,
|
||||
[Component.M3]: ColorM,
|
||||
|
||||
[Component.W3]: ColorW,
|
||||
|
||||
// tier 4
|
||||
[Component.R4]: ColorR,
|
||||
[Component.G4]: ColorG,
|
||||
[Component.B4]: ColorB,
|
||||
|
||||
[Component.Y4]: ColorY,
|
||||
[Component.C4]: ColorC,
|
||||
[Component.M4]: ColorM,
|
||||
|
||||
[Component.W4]: ColorW,
|
||||
|
||||
// tier 5
|
||||
[Component.R5]: ColorR,
|
||||
[Component.G5]: ColorG,
|
||||
[Component.B5]: ColorB,
|
||||
|
||||
[Component.Y5]: ColorY,
|
||||
[Component.C5]: ColorC,
|
||||
[Component.M5]: ColorM,
|
||||
|
||||
[Component.W5]: ColorW,
|
||||
|
||||
// tier 6
|
||||
[Component.Y6]: ColorY,
|
||||
[Component.C6]: ColorC,
|
||||
[Component.M6]: ColorM,
|
||||
|
||||
[Component.W6]: ColorW,
|
||||
|
||||
// tier 7
|
||||
[Component.W7]: ColorW,
|
||||
};
|
||||
|
||||
const LockIcon = styled(BlockIcon)(defaultIconStyle);
|
||||
const BusIcon = styled(DirectionsBusIcon)(defaultIconStyle);
|
||||
const ISocketIcon = styled(OutboxIcon)((props: { dispenser: ISocket; col: string }) => ({
|
||||
...defaultIconStyle,
|
||||
color: new Date().getTime() > props.dispenser.cooldownUntil ? props.col : "gray",
|
||||
}));
|
||||
|
||||
const OSocketIcon = styled(MoveToInboxIcon)(defaultIconStyle);
|
||||
|
||||
const ReducerIcon = styled(MergeTypeIcon)(defaultIconStyle);
|
||||
|
||||
const CacheIcon = styled(CheckBoxOutlineBlankIcon)(defaultIconStyle);
|
||||
|
||||
const BatteryIcon = styled(BatteryChargingFullIcon)(defaultIconStyle);
|
||||
|
||||
interface ITooltipContentProps {
|
||||
interface IDeviceIconProps {
|
||||
device: Device;
|
||||
content: React.ReactElement;
|
||||
}
|
||||
const TooltipContent = ({ device, content }: ITooltipContentProps): React.ReactElement => {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
{device.name} ({device.type})
|
||||
</Typography>
|
||||
{content}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const TooltipInventory = ({ device }: { device: Device }): React.ReactElement => {
|
||||
if (!isDeviceContainer(device)) return <></>;
|
||||
return (
|
||||
<Typography component="span">
|
||||
{device.content.map((item) => (
|
||||
<span key={item} style={{ color: itemColorMap[item] }}>
|
||||
{item}
|
||||
</span>
|
||||
))}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
export const DeviceIcon = ({ device }: { device: Device }): React.ReactElement => {
|
||||
export const DeviceIcon = ({ device }: IDeviceIconProps): React.ReactElement => {
|
||||
switch (device.type) {
|
||||
case DeviceType.Lock: {
|
||||
return <LockIcon />;
|
||||
}
|
||||
case DeviceType.Battery: {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<TooltipContent
|
||||
device={device}
|
||||
content={
|
||||
<Typography>
|
||||
{device.energy} / {device.maxEnergy}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<BatteryIcon />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
case DeviceType.Cache: {
|
||||
return (
|
||||
<Tooltip title={<TooltipContent device={device} content={<TooltipInventory device={device} />} />}>
|
||||
<CacheIcon />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
case DeviceType.Bus: {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
{device.name}
|
||||
<br /> <TooltipInventory device={device} />
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<BusIcon />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
case DeviceType.ISocket: {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<TooltipContent device={device} content={<Typography>{`dispensing: ${device.emitting}`}</Typography>} />
|
||||
<TooltipInventory device={device} />
|
||||
</>
|
||||
}
|
||||
>
|
||||
<ISocketIcon dispenser={device} col={itemColorMap[device.emitting]} />
|
||||
</Tooltip>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case DeviceType.OSocket: {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<TooltipContent
|
||||
device={device}
|
||||
content={<Typography>{`requesting: ${device.currentRequest}`}</Typography>}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<OSocketIcon sx={{ color: itemColorMap[device.currentRequest[0] ?? Component.R0] }} />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
case DeviceType.Reducer: {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<TooltipContent
|
||||
device={device}
|
||||
content={
|
||||
<>
|
||||
<Typography>Tier: {device.tier}</Typography>
|
||||
<TooltipInventory device={device} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ReducerIcon />
|
||||
</Tooltip>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case DeviceType.ISocket:
|
||||
return <ISocketIcon socket={device} />;
|
||||
case DeviceType.OSocket:
|
||||
return <OSocketIcon socket={device} />;
|
||||
case DeviceType.Bus:
|
||||
return <BusIcon bus={device} />;
|
||||
case DeviceType.Reducer:
|
||||
return <ReducerIcon reducer={device} />;
|
||||
case DeviceType.Lock:
|
||||
return <LockIcon lock={device} />;
|
||||
case DeviceType.Cache:
|
||||
return <CacheIcon cache={device} />;
|
||||
case DeviceType.Battery:
|
||||
return <BatteryIcon battery={device} />;
|
||||
}
|
||||
return <></>;
|
||||
};
|
||||
|
24
src/Myrian/ui/DeviceTooltip.tsx
Normal file
24
src/Myrian/ui/DeviceTooltip.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React, { ReactNode } from "react";
|
||||
import { Device } from "../../ScriptEditor/NetscriptDefinitions";
|
||||
import { Tooltip, Typography } from "@mui/material";
|
||||
|
||||
interface INewTooltipProps {
|
||||
icon: React.JSX.Element;
|
||||
device: Device;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const DeviceTooltip = ({ device, icon, children }: INewTooltipProps): React.ReactElement => (
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<Typography>
|
||||
{device.name} ({device.type})
|
||||
</Typography>
|
||||
{children}
|
||||
</>
|
||||
}
|
||||
>
|
||||
{icon}
|
||||
</Tooltip>
|
||||
);
|
88
src/Myrian/ui/Grid.tsx
Normal file
88
src/Myrian/ui/Grid.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import { cellSize } from "./common";
|
||||
import { styled } from "@mui/system";
|
||||
import { findDevice, myrianSize } from "../Myrian";
|
||||
import { DeviceIcon } from "./DeviceIcon";
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
const BaseCell = styled("div")({
|
||||
width: cellSize,
|
||||
height: cellSize,
|
||||
backgroundColor: "#444",
|
||||
padding: 0,
|
||||
margin: "2px",
|
||||
marginTop: "4px",
|
||||
marginBottom: "4px",
|
||||
});
|
||||
|
||||
const TextCell = styled(BaseCell)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#00000000",
|
||||
});
|
||||
|
||||
const DeviceCell = ({ x, y }: { x: number; y: number }): React.ReactElement => {
|
||||
const device = findDevice([x, y]);
|
||||
return <BaseCell>{device && <DeviceIcon device={device} />}</BaseCell>;
|
||||
};
|
||||
|
||||
const ColD = styled("div")({
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
});
|
||||
|
||||
interface IColProps {
|
||||
x: number;
|
||||
}
|
||||
|
||||
const DeviceCol = ({ x }: IColProps): React.ReactElement => {
|
||||
return (
|
||||
<ColD>
|
||||
<TextCell>
|
||||
<Typography>{x}</Typography>
|
||||
</TextCell>
|
||||
{new Array(myrianSize).fill(undefined).map((_, y) => (
|
||||
<DeviceCell key={y} x={x} y={y}></DeviceCell>
|
||||
))}
|
||||
</ColD>
|
||||
);
|
||||
};
|
||||
|
||||
const Table = styled("div")({
|
||||
border: "1px solid #fff",
|
||||
borderSpacing: "2px",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
paddingLeft: "2px",
|
||||
paddingRight: "2px",
|
||||
});
|
||||
|
||||
const YColumn = (
|
||||
<ColD>
|
||||
<TextCell>
|
||||
<Typography>
|
||||
X
|
||||
<br />
|
||||
Y
|
||||
</Typography>
|
||||
</TextCell>
|
||||
{new Array(myrianSize).fill(undefined).map((_, y) => (
|
||||
<TextCell key={y}>
|
||||
<Typography>{y}</Typography>
|
||||
</TextCell>
|
||||
))}
|
||||
</ColD>
|
||||
);
|
||||
|
||||
export const Grid = () => (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Table>
|
||||
{YColumn}
|
||||
{new Array(myrianSize).fill(undefined).map((_, x) => (
|
||||
<DeviceCol key={x} x={x} />
|
||||
))}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
33
src/Myrian/ui/ISocketIcon.tsx
Normal file
33
src/Myrian/ui/ISocketIcon.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { TooltipContent } from "./TooltipContent";
|
||||
import { ISocket } from "../../ScriptEditor/NetscriptDefinitions";
|
||||
import { defaultIconStyle, getComponentColor } from "./common";
|
||||
import OutboxIcon from "@mui/icons-material/Outbox";
|
||||
import { styled } from "@mui/styles";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
import { ComponentText } from "./ComponentText";
|
||||
|
||||
interface IIconProps {
|
||||
socket: ISocket;
|
||||
col: string;
|
||||
}
|
||||
|
||||
const Icon = styled(OutboxIcon)(({ socket, col }: IIconProps) => ({
|
||||
...defaultIconStyle,
|
||||
color: new Date().getTime() > socket.cooldownUntil ? col : "gray",
|
||||
}));
|
||||
|
||||
interface IIsocketIconProps {
|
||||
socket: ISocket;
|
||||
}
|
||||
|
||||
export const ISocketIcon = ({ socket }: IIsocketIconProps) => (
|
||||
<DeviceTooltip device={socket} icon={<Icon socket={socket} col={getComponentColor(socket.emitting)} />}>
|
||||
<Typography>
|
||||
dispensing:
|
||||
<ComponentText component={socket.emitting} />
|
||||
</Typography>
|
||||
<TooltipContent device={socket} />
|
||||
</DeviceTooltip>
|
||||
);
|
15
src/Myrian/ui/LockIcon.tsx
Normal file
15
src/Myrian/ui/LockIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import { styled } from "@mui/styles";
|
||||
import { defaultIconStyle } from "./common";
|
||||
import { Lock } from "@nsdefs";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
|
||||
const Template = styled(BlockIcon)(defaultIconStyle);
|
||||
const Icon = <Template />;
|
||||
|
||||
interface ILockIconProps {
|
||||
lock: Lock;
|
||||
}
|
||||
|
||||
export const LockIcon = ({ lock }: ILockIconProps): React.ReactElement => <DeviceTooltip device={lock} icon={Icon} />;
|
@ -1,93 +1,20 @@
|
||||
import React from "react";
|
||||
import { Container, IconButton, Typography } from "@mui/material";
|
||||
|
||||
import { styled } from "@mui/system";
|
||||
import { myrian, myrianSize } from "../Helper";
|
||||
import { myrian } from "../Myrian";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { DeviceIcon, cellSize } from "./DeviceIcon";
|
||||
import { Info } from "@mui/icons-material";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { MD } from "../../ui/MD/MD";
|
||||
import { tutorial } from "./tutorial";
|
||||
import { Grid } from "./Grid";
|
||||
|
||||
const CellD = styled("div")({
|
||||
width: cellSize + "px",
|
||||
height: cellSize + "px",
|
||||
backgroundColor: "#444",
|
||||
padding: 0,
|
||||
margin: "2px",
|
||||
marginTop: "4px",
|
||||
marginBottom: "4px",
|
||||
});
|
||||
const tut = <MD md={tutorial} />;
|
||||
|
||||
const Cell = ({ x, y }: { x: number; y: number }): React.ReactElement => {
|
||||
const device = myrian.devices.find((e) => e.x === x && e.y === y);
|
||||
return <CellD>{device && <DeviceIcon device={device} />}</CellD>;
|
||||
};
|
||||
|
||||
const RowD = styled("div")({
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
});
|
||||
|
||||
interface IColProps {
|
||||
x: number;
|
||||
}
|
||||
|
||||
const Col = ({ x }: IColProps): React.ReactElement => {
|
||||
return (
|
||||
<RowD>
|
||||
{new Array(myrianSize + 1).fill(null).map((_, y) => {
|
||||
if (y === 0)
|
||||
return (
|
||||
<CellD
|
||||
sx={{ display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "#00000000" }}
|
||||
key={y}
|
||||
>
|
||||
<Typography>{x - 1}</Typography>
|
||||
</CellD>
|
||||
);
|
||||
return <Cell key={y} x={x - 1} y={y - 1}></Cell>;
|
||||
})}
|
||||
</RowD>
|
||||
);
|
||||
};
|
||||
|
||||
const Table = styled("div")({
|
||||
border: "1px solid #fff",
|
||||
borderSpacing: "2px",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
paddingLeft: "2px",
|
||||
paddingRight: "2px",
|
||||
});
|
||||
|
||||
const YHeader = () => {
|
||||
return (
|
||||
<RowD>
|
||||
{new Array(myrianSize + 1).fill(null).map((_, y) => {
|
||||
return (
|
||||
<CellD
|
||||
sx={{ display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "#00000000" }}
|
||||
key={y}
|
||||
>
|
||||
<Typography>{y === 0 ? "Y\\X" : y - 1}</Typography>
|
||||
</CellD>
|
||||
);
|
||||
})}
|
||||
</RowD>
|
||||
);
|
||||
};
|
||||
|
||||
interface IProps {}
|
||||
|
||||
export const MyrianRoot = (__props: IProps): React.ReactElement => {
|
||||
export const MyrianRoot = (): React.ReactElement => {
|
||||
useRerender(50);
|
||||
|
||||
const onHelp = () => {
|
||||
dialogBoxCreate(<MD md={tutorial} />);
|
||||
};
|
||||
const onHelp = () => dialogBoxCreate(tut);
|
||||
return (
|
||||
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
|
||||
<Typography variant="h4">
|
||||
@ -99,14 +26,7 @@ export const MyrianRoot = (__props: IProps): React.ReactElement => {
|
||||
<Typography>
|
||||
{myrian.vulns} vulns : {myrian.totalVulns} total vulns
|
||||
</Typography>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Table>
|
||||
{new Array(myrianSize + 1).fill(null).map((_, x) => {
|
||||
if (x === 0) return <YHeader key={x} />;
|
||||
return <Col key={x} x={x} />;
|
||||
})}
|
||||
</Table>
|
||||
</div>
|
||||
<Grid />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
35
src/Myrian/ui/OSocketIcon.tsx
Normal file
35
src/Myrian/ui/OSocketIcon.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import { Typography } from "@mui/material";
|
||||
import { OSocket } from "@nsdefs";
|
||||
import { defaultIconStyle, getComponentColor } from "./common";
|
||||
import MoveToInboxIcon from "@mui/icons-material/MoveToInbox";
|
||||
import { styled } from "@mui/styles";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
import { TooltipContent } from "./TooltipContent";
|
||||
import { ComponentText } from "./ComponentText";
|
||||
|
||||
interface IIconProps {
|
||||
col: string;
|
||||
}
|
||||
|
||||
const Icon = styled(MoveToInboxIcon)(({ col }: IIconProps) => ({
|
||||
...defaultIconStyle,
|
||||
color: col,
|
||||
}));
|
||||
|
||||
interface IOSocketIconProps {
|
||||
socket: OSocket;
|
||||
}
|
||||
|
||||
export const OSocketIcon = ({ socket }: IOSocketIconProps): React.ReactElement => (
|
||||
<DeviceTooltip device={socket} icon={<Icon col={getComponentColor(socket.currentRequest[0])} />}>
|
||||
<Typography>
|
||||
requesting:
|
||||
<br />
|
||||
{socket.currentRequest.map((c, i) => (
|
||||
<ComponentText key={i} component={c} />
|
||||
))}
|
||||
</Typography>
|
||||
<TooltipContent device={socket} />
|
||||
</DeviceTooltip>
|
||||
);
|
22
src/Myrian/ui/Reducer.tsx
Normal file
22
src/Myrian/ui/Reducer.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import { TooltipContent } from "./TooltipContent";
|
||||
import { Reducer } from "@nsdefs";
|
||||
import MergeTypeIcon from "@mui/icons-material/MergeType";
|
||||
import { styled } from "@mui/styles";
|
||||
import { defaultIconStyle } from "./common";
|
||||
import { DeviceTooltip } from "./DeviceTooltip";
|
||||
import { TooltipTier } from "./TooltipTier";
|
||||
|
||||
const Template = styled(MergeTypeIcon)(defaultIconStyle);
|
||||
const Icon = <Template />;
|
||||
|
||||
interface IReducerIconProps {
|
||||
reducer: Reducer;
|
||||
}
|
||||
|
||||
export const ReducerIcon = ({ reducer }: IReducerIconProps): React.ReactElement => (
|
||||
<DeviceTooltip device={reducer} icon={Icon}>
|
||||
<TooltipTier device={reducer} />
|
||||
<TooltipContent device={reducer} />
|
||||
</DeviceTooltip>
|
||||
);
|
18
src/Myrian/ui/TooltipContent.tsx
Normal file
18
src/Myrian/ui/TooltipContent.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
import { ContainerDevice } from "@nsdefs";
|
||||
import { Typography } from "@mui/material";
|
||||
import { ComponentText } from "./ComponentText";
|
||||
|
||||
export const TooltipContent = ({ device }: { device: ContainerDevice }): React.ReactElement => (
|
||||
<>
|
||||
{device.content.length !== 0 && (
|
||||
<Typography>
|
||||
content ({device.content.length} / {device.maxContent}):
|
||||
<br />
|
||||
{device.content.map((component, i) => (
|
||||
<ComponentText key={i} component={component} />
|
||||
))}
|
||||
</Typography>
|
||||
)}
|
||||
</>
|
||||
);
|
13
src/Myrian/ui/TooltipEnergy.tsx
Normal file
13
src/Myrian/ui/TooltipEnergy.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
import { EnergyDevice } from "@nsdefs";
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
interface ITooltipEnergyProps {
|
||||
device: EnergyDevice;
|
||||
}
|
||||
|
||||
export const TooltipEnergy = ({ device }: ITooltipEnergyProps): React.ReactElement => (
|
||||
<Typography>
|
||||
{device.energy} / {device.maxEnergy} energy
|
||||
</Typography>
|
||||
);
|
11
src/Myrian/ui/TooltipTier.tsx
Normal file
11
src/Myrian/ui/TooltipTier.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
import { TieredDevice } from "@nsdefs";
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
interface ITooltipTierProps {
|
||||
device: TieredDevice;
|
||||
}
|
||||
|
||||
export const TooltipTier = ({ device }: ITooltipTierProps): React.ReactElement => (
|
||||
<Typography>Tier: {device.tier}</Typography>
|
||||
);
|
30
src/Myrian/ui/common.ts
Normal file
30
src/Myrian/ui/common.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Component } from "@nsdefs";
|
||||
|
||||
export const cellSize = 48;
|
||||
|
||||
export const defaultIconStyle = {
|
||||
width: cellSize + "px",
|
||||
height: cellSize + "px",
|
||||
color: "white",
|
||||
};
|
||||
|
||||
const ColorR = "red";
|
||||
const ColorG = "#7CFC00";
|
||||
const ColorB = "#1E90FF";
|
||||
const ColorY = "yellow";
|
||||
const ColorC = "cyan";
|
||||
const ColorM = "magenta";
|
||||
const ColorW = "white";
|
||||
|
||||
const componentColors: Record<string, string> = {
|
||||
r: ColorR,
|
||||
g: ColorG,
|
||||
b: ColorB,
|
||||
y: ColorY,
|
||||
c: ColorC,
|
||||
m: ColorM,
|
||||
w: ColorW,
|
||||
};
|
||||
|
||||
export const getComponentColor = (component: Component): string =>
|
||||
componentColors[component[0].toLowerCase()] ?? ColorW;
|
@ -1 +1,118 @@
|
||||
import {
|
||||
Component,
|
||||
BaseDevice,
|
||||
ContainerDevice,
|
||||
Device,
|
||||
Bus,
|
||||
DeviceType,
|
||||
ISocket,
|
||||
OSocket,
|
||||
Reducer,
|
||||
Cache,
|
||||
Lock,
|
||||
Battery,
|
||||
TieredDevice,
|
||||
EnergyDevice,
|
||||
} from "@nsdefs";
|
||||
|
||||
export const pickOne = <T>(arr: T[]): T => arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
export const distance = (a: Device, b: Device) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
|
||||
export const distanceCoord2D = (a: Device, coord: [number, number]) =>
|
||||
Math.abs(a.x - coord[0]) + Math.abs(a.y - coord[1]);
|
||||
|
||||
export const adjacent = (a: Device, b: Device) => distance(a, b) === 1;
|
||||
export const adjacentCoord2D = (a: Device, coord: [number, number]) => distanceCoord2D(a, coord) === 1;
|
||||
|
||||
export const inventoryMatches = (a: Component[], b: Component[]) => {
|
||||
if (a.length != b.length) return false;
|
||||
return a.every((i) => b.includes(i));
|
||||
};
|
||||
|
||||
const vulnsMap: Record<Component, number> = {
|
||||
// tier 0
|
||||
[Component.R0]: 1,
|
||||
[Component.G0]: 1,
|
||||
[Component.B0]: 1,
|
||||
|
||||
// tier 1
|
||||
[Component.R1]: 4,
|
||||
[Component.G1]: 4,
|
||||
[Component.B1]: 4,
|
||||
|
||||
[Component.Y1]: 4,
|
||||
[Component.C1]: 4,
|
||||
[Component.M1]: 4,
|
||||
|
||||
// tier 2
|
||||
[Component.R2]: 16,
|
||||
[Component.G2]: 16,
|
||||
[Component.B2]: 16,
|
||||
|
||||
[Component.Y2]: 16,
|
||||
[Component.C2]: 16,
|
||||
[Component.M2]: 16,
|
||||
|
||||
[Component.W2]: 16,
|
||||
|
||||
// tier 3
|
||||
[Component.R3]: 64,
|
||||
[Component.G3]: 64,
|
||||
[Component.B3]: 64,
|
||||
|
||||
[Component.Y3]: 64,
|
||||
[Component.C3]: 64,
|
||||
[Component.M3]: 64,
|
||||
|
||||
[Component.W3]: 64,
|
||||
|
||||
// tier 4
|
||||
[Component.R4]: 256,
|
||||
[Component.G4]: 256,
|
||||
[Component.B4]: 256,
|
||||
|
||||
[Component.Y4]: 256,
|
||||
[Component.C4]: 256,
|
||||
[Component.M4]: 256,
|
||||
|
||||
[Component.W4]: 256,
|
||||
|
||||
// tier 5
|
||||
[Component.R5]: 1024,
|
||||
[Component.G5]: 1024,
|
||||
[Component.B5]: 1024,
|
||||
|
||||
[Component.Y5]: 1024,
|
||||
[Component.C5]: 1024,
|
||||
[Component.M5]: 1024,
|
||||
|
||||
[Component.W5]: 1024,
|
||||
|
||||
// tier 6
|
||||
[Component.Y6]: 4096,
|
||||
[Component.C6]: 4096,
|
||||
[Component.M6]: 4096,
|
||||
|
||||
[Component.W6]: 4096,
|
||||
|
||||
// tier 7
|
||||
[Component.W7]: 16384,
|
||||
};
|
||||
|
||||
export const contentVulnsValue = (content: Component[]) => content.map((i) => vulnsMap[i]).reduce((a, b) => a + b, 0);
|
||||
|
||||
export const isDeviceContainer = (device: BaseDevice): device is ContainerDevice => "content" in device;
|
||||
export const isDeviceBus = (d: Device): d is Bus => d.type === DeviceType.Bus;
|
||||
export const isDeviceISocket = (d: Device): d is ISocket => d.type === DeviceType.ISocket;
|
||||
export const isDeviceOSocket = (d: Device): d is OSocket => d.type === DeviceType.OSocket;
|
||||
export const isDeviceReducer = (d: Device): d is Reducer => d.type === DeviceType.Reducer;
|
||||
export const isDeviceCache = (d: Device): d is Cache => d.type === DeviceType.Cache;
|
||||
export const isDeviceLock = (d: Device): d is Lock => d.type === DeviceType.Lock;
|
||||
export const isDeviceBattery = (d: Device): d is Battery => d.type === DeviceType.Battery;
|
||||
export const isDeviceTiered = (d: BaseDevice): d is TieredDevice => "tier" in d;
|
||||
export const isEmittingDevice = (d: BaseDevice): d is BaseDevice & { emissionLvl: number } => "emissionLvl" in d;
|
||||
export const isMovingDevice = (d: BaseDevice): d is BaseDevice & { moveLvl: number } => "moveLvl" in d;
|
||||
export const isTransferingDevice = (d: BaseDevice): d is BaseDevice & { transferLvl: number } => "transferLvl" in d;
|
||||
export const isReducingDevice = (d: BaseDevice): d is BaseDevice & { reduceLvl: number } => "reduceLvl" in d;
|
||||
export const isInstallingDevice = (d: BaseDevice): d is BaseDevice & { installLvl: number } => "installLvl" in d;
|
||||
export const isEnergyDevice = (d: BaseDevice): d is EnergyDevice => "maxEnergy" in d;
|
||||
|
@ -2,42 +2,27 @@ import { Bus, Myrian as IMyrian, DeviceType, Component, Reducer, Glitch, Battery
|
||||
import { InternalAPI } from "../Netscript/APIWrapper";
|
||||
import { helpers } from "../Netscript/NetscriptHelpers";
|
||||
import {
|
||||
NewBattery,
|
||||
NewBus,
|
||||
NewCache,
|
||||
NewISocket,
|
||||
NewLock,
|
||||
NewOSocket,
|
||||
NewReducer,
|
||||
myrian as myrian,
|
||||
myrianSize,
|
||||
resetMyrian,
|
||||
} from "../Myrian/Helper";
|
||||
import {
|
||||
adjacent,
|
||||
adjacentCoord2D,
|
||||
vulnsMap,
|
||||
findDevice,
|
||||
inMyrianBounds,
|
||||
inventoryMatches,
|
||||
isDeviceContainer,
|
||||
isDeviceBus,
|
||||
removeDevice,
|
||||
getTotalGlitchMult,
|
||||
rustBus,
|
||||
getNextOSocketRequest,
|
||||
countDevices,
|
||||
resetMyrian,
|
||||
myrian,
|
||||
myrianSize,
|
||||
} from "../Myrian/Myrian";
|
||||
import {
|
||||
deviceCost,
|
||||
emissionCost,
|
||||
getNextISocketRequest,
|
||||
installLvlCost,
|
||||
maxEnergyCost,
|
||||
moveLvlCost,
|
||||
reduceLvlCost,
|
||||
tierCost,
|
||||
transferLvlCost,
|
||||
installDeviceCost,
|
||||
upgradeEmissionCost,
|
||||
upgradeInstallLvlCost,
|
||||
upgradeMaxEnergyCost,
|
||||
upgradeMoveLvlCost,
|
||||
upgradeReduceLvlCost,
|
||||
upgradeTierCost,
|
||||
upgradeTransferLvlCost,
|
||||
upgradeMaxContentCost,
|
||||
} from "../Myrian/formulas/formulas";
|
||||
} from "../Myrian/formulas/costs";
|
||||
import { recipes } from "../Myrian/formulas/recipes";
|
||||
import { componentTiers } from "../Myrian/formulas/components";
|
||||
import {
|
||||
@ -49,8 +34,25 @@ import {
|
||||
magnetismLoss,
|
||||
virtualizationMult,
|
||||
} from "../Myrian/formulas/glitches";
|
||||
import { pickOne } from "../Myrian/utils";
|
||||
import { installSpeed, isocketSpeed, moveSpeed, reduceSpeed, transferSpeed } from "../Myrian/formulas/speed";
|
||||
import {
|
||||
adjacent,
|
||||
adjacentCoord2D,
|
||||
contentVulnsValue,
|
||||
inventoryMatches,
|
||||
isDeviceBus,
|
||||
isDeviceContainer,
|
||||
isDeviceTiered,
|
||||
isEmittingDevice,
|
||||
isEnergyDevice,
|
||||
isInstallingDevice,
|
||||
isMovingDevice,
|
||||
isReducingDevice,
|
||||
isTransferingDevice,
|
||||
pickOne,
|
||||
} from "../Myrian/utils";
|
||||
import { installSpeed, emissionSpeed, moveSpeed, reduceSpeed, transferSpeed } from "../Myrian/formulas/speed";
|
||||
import { NewBattery, NewBus, NewCache, NewISocket, NewLock, NewOSocket, NewReducer } from "../Myrian/NewDevices";
|
||||
import { rustBus } from "../Myrian/glitches/rust";
|
||||
|
||||
export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
return {
|
||||
@ -209,7 +211,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
switch (container.type) {
|
||||
case DeviceType.ISocket: {
|
||||
if (previousSize <= container.content.length) break;
|
||||
const cooldown = isocketSpeed(container.emissionLvl);
|
||||
const cooldown = emissionSpeed(container.emissionLvl);
|
||||
container.cooldownUntil = Date.now() + cooldown;
|
||||
setTimeout(() => {
|
||||
container.content = new Array(container.maxContent).fill(container.emitting);
|
||||
@ -219,12 +221,11 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
|
||||
case DeviceType.OSocket: {
|
||||
if (!inventoryMatches(container.currentRequest, container.content)) break;
|
||||
const gain =
|
||||
container.content.map((i) => vulnsMap[i]).reduce((a, b) => a + b, 0) * getTotalGlitchMult();
|
||||
const gain = contentVulnsValue(container.content) * getTotalGlitchMult();
|
||||
myrian.vulns += gain;
|
||||
myrian.totalVulns += gain;
|
||||
container.content = [];
|
||||
const request = getNextISocketRequest(myrian.glitches[Glitch.Encryption]);
|
||||
const request = getNextOSocketRequest(myrian.glitches[Glitch.Encryption]);
|
||||
container.currentRequest = request;
|
||||
container.maxContent = request.length;
|
||||
break;
|
||||
@ -323,7 +324,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
.then(() => {
|
||||
isocket.emitting = component;
|
||||
isocket.content = [];
|
||||
const cooldown = isocketSpeed(isocket.emissionLvl);
|
||||
const cooldown = emissionSpeed(isocket.emissionLvl);
|
||||
isocket.cooldownUntil = Date.now() + cooldown;
|
||||
setTimeout(() => {
|
||||
isocket.content = new Array(isocket.maxContent).fill(isocket.emitting);
|
||||
@ -410,7 +411,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
|
||||
getDeviceCost: (ctx) => (_type) => {
|
||||
const type = helpers.string(ctx, "type", _type);
|
||||
return deviceCost(type as DeviceType);
|
||||
return installDeviceCost(type as DeviceType, countDevices(type as DeviceType));
|
||||
},
|
||||
|
||||
installDevice: (ctx) => async (_bus, _name, _coord, _deviceType) => {
|
||||
@ -441,7 +442,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
const cost = deviceCost(deviceType);
|
||||
const cost = installDeviceCost(deviceType, countDevices(deviceType));
|
||||
if (myrian.vulns < cost) {
|
||||
helpers.log(ctx, () => `not enough vulns to install device`);
|
||||
return Promise.resolve(false);
|
||||
@ -548,15 +549,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("tier" in device)) return -1;
|
||||
return tierCost(device.type, device.tier);
|
||||
if (!isDeviceTiered(device)) return -1;
|
||||
return upgradeTierCost(device.type, device.tier);
|
||||
},
|
||||
upgradeTier: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("tier" in device)) return false;
|
||||
const cost = tierCost(device.type, device.tier);
|
||||
if (!isDeviceTiered(device)) return false;
|
||||
const cost = upgradeTierCost(device.type, device.tier);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.tier++;
|
||||
@ -566,15 +567,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("emissionLvl" in device)) return -1;
|
||||
return emissionCost(device.type, device.emissionLvl);
|
||||
if (!isEmittingDevice(device)) return -1;
|
||||
return upgradeEmissionCost(device.type, device.emissionLvl);
|
||||
},
|
||||
upgradeEmissionLvl: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("emissionLvl" in device)) return false;
|
||||
const cost = emissionCost(device.type, device.emissionLvl);
|
||||
if (!isEmittingDevice(device)) return false;
|
||||
const cost = upgradeEmissionCost(device.type, device.emissionLvl);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.emissionLvl++;
|
||||
@ -584,15 +585,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("moveLvl" in device)) return -1;
|
||||
return moveLvlCost(device.type, device.moveLvl);
|
||||
if (!isMovingDevice(device)) return -1;
|
||||
return upgradeMoveLvlCost(device.type, device.moveLvl);
|
||||
},
|
||||
upgradeMoveLvl: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("moveLvl" in device)) return false;
|
||||
const cost = moveLvlCost(device.type, device.moveLvl);
|
||||
if (!isMovingDevice(device)) return false;
|
||||
const cost = upgradeMoveLvlCost(device.type, device.moveLvl);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.moveLvl++;
|
||||
@ -602,15 +603,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("transferLvl" in device)) return -1;
|
||||
return transferLvlCost(device.type, device.transferLvl);
|
||||
if (!isTransferingDevice(device)) return -1;
|
||||
return upgradeTransferLvlCost(device.type, device.transferLvl);
|
||||
},
|
||||
upgradeTransferLvl: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("transferLvl" in device)) return false;
|
||||
const cost = transferLvlCost(device.type, device.transferLvl);
|
||||
if (!isTransferingDevice(device)) return false;
|
||||
const cost = upgradeTransferLvlCost(device.type, device.transferLvl);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.transferLvl++;
|
||||
@ -620,15 +621,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("reduceLvl" in device)) return -1;
|
||||
return reduceLvlCost(device.type, device.reduceLvl);
|
||||
if (!isReducingDevice(device)) return -1;
|
||||
return upgradeReduceLvlCost(device.type, device.reduceLvl);
|
||||
},
|
||||
upgradeReduceLvl: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("reduceLvl" in device)) return false;
|
||||
const cost = reduceLvlCost(device.type, device.reduceLvl);
|
||||
if (!isReducingDevice(device)) return false;
|
||||
const cost = upgradeReduceLvlCost(device.type, device.reduceLvl);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.reduceLvl++;
|
||||
@ -638,15 +639,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("installLvl" in device)) return -1;
|
||||
return installLvlCost(device.type, device.installLvl);
|
||||
if (!isInstallingDevice(device)) return -1;
|
||||
return upgradeInstallLvlCost(device.type, device.installLvl);
|
||||
},
|
||||
upgradeInstallLvl: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("installLvl" in device)) return false;
|
||||
const cost = installLvlCost(device.type, device.installLvl);
|
||||
if (!isInstallingDevice(device)) return false;
|
||||
const cost = upgradeInstallLvlCost(device.type, device.installLvl);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.installLvl++;
|
||||
@ -656,15 +657,15 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return -1;
|
||||
if (!("maxEnergy" in device)) return -1;
|
||||
return maxEnergyCost(device.type, device.maxEnergy);
|
||||
if (!isEnergyDevice(device)) return -1;
|
||||
return upgradeMaxEnergyCost(device.type, device.maxEnergy);
|
||||
},
|
||||
upgradeMaxEnergy: (ctx) => (_id) => {
|
||||
const id = helpers.deviceID(ctx, "device", _id);
|
||||
const device = findDevice(id);
|
||||
if (!device) return false;
|
||||
if (!("maxEnergy" in device)) return false;
|
||||
const cost = maxEnergyCost(device.type, device.maxEnergy);
|
||||
if (!isEnergyDevice(device)) return false;
|
||||
const cost = upgradeMaxEnergyCost(device.type, device.maxEnergy);
|
||||
if (myrian.vulns < cost) return false;
|
||||
myrian.vulns -= cost;
|
||||
device.maxEnergy++;
|
||||
|
@ -45,7 +45,7 @@ import { downloadContentAsFile } from "./utils/FileUtils";
|
||||
import { showAPIBreaks } from "./utils/APIBreaks/APIBreak";
|
||||
import { breakInfos261 } from "./utils/APIBreaks/2.6.1";
|
||||
import { handleGetSaveDataError } from "./Netscript/ErrorMessages";
|
||||
import { myrian, loadMyrian } from "./Myrian/Helper";
|
||||
import { myrian, loadMyrian } from "./Myrian/Myrian";
|
||||
|
||||
/* SaveObject.js
|
||||
* Defines the object used to save/load games
|
||||
|
Reference in New Issue
Block a user