Add a few Glitch

This commit is contained in:
Olivier Gagnon 2024-06-09 18:39:13 -04:00
parent 58a471981c
commit e2e71501a8
No known key found for this signature in database
GPG Key ID: 0018772EA86FA03F
8 changed files with 373 additions and 18 deletions

@ -1,13 +1,26 @@
import { DeviceType, Component, Lock } from "@nsdefs"; import { DeviceType, Component, Lock, Glitch } from "@nsdefs";
import { Myrian } from "./Myrian"; import { Myrian } from "./Myrian";
import { getNextISocketRequest } from "./formulas/formulas"; import { getNextISocketRequest } from "./formulas/formulas";
export const myrianSize = 12; 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 = { const defaultMyrian: Myrian = {
vulns: 0, vulns: 0,
totalVulns: 0, totalVulns: 0,
devices: [], devices: [],
glitches: { ...defaultGlitches },
}; };
export const myrian: Myrian = defaultMyrian; export const myrian: Myrian = defaultMyrian;
@ -26,7 +39,8 @@ export const NewBus = (name: string, x: number, y: number) => {
transferLvl: 0, transferLvl: 0,
reduceLvl: 0, reduceLvl: 0,
installLvl: 0, installLvl: 0,
// energy: 16, energy: 16,
maxEnergy: 16,
}); });
}; };
@ -96,6 +110,19 @@ export const NewLock = (name: string, x: number, y: number) => {
return 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) => { export const loadMyrian = (save: string) => {
if (!save) return; if (!save) return;
// const savedFactory = JSON.parse(save); // const savedFactory = JSON.parse(save);
@ -104,9 +131,14 @@ export const loadMyrian = (save: string) => {
export const resetMyrian = () => { export const resetMyrian = () => {
myrian.vulns = 0; myrian.vulns = 0;
myrian.totalVulns = 0;
myrian.devices = []; myrian.devices = [];
myrian.glitches = { ...defaultGlitches };
Object.assign(myrian, defaultMyrian); Object.assign(myrian, defaultMyrian);
NewBus("alice", Math.floor(myrianSize / 2), Math.floor(myrianSize / 2)); NewBus("alice", Math.floor(myrianSize / 2), Math.floor(myrianSize / 2));
NewISocket("isocket0", Math.floor(myrianSize / 4), 0, Component.R0); NewISocket("isocket0", Math.floor(myrianSize / 4), 0, Component.R0);
NewISocket("isocket1", Math.floor(myrianSize / 2), 0, Component.G0); NewISocket("isocket1", Math.floor(myrianSize / 2), 0, Component.G0);
NewISocket("isocket2", Math.floor((myrianSize * 3) / 4), 0, Component.B0); NewISocket("isocket2", Math.floor((myrianSize * 3) / 4), 0, Component.B0);
@ -116,4 +148,12 @@ export const resetMyrian = () => {
NewOSocket("osocket2", Math.floor((myrianSize * 3) / 4), 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);
resetMyrian(); resetMyrian();

@ -11,13 +11,17 @@ import {
Lock, Lock,
BaseDevice, BaseDevice,
DeviceID, DeviceID,
Glitch,
Battery,
} from "@nsdefs"; } from "@nsdefs";
import { myrian, myrianSize } from "./Helper"; import { myrian, myrianSize } from "./Helper";
import { glitchMult } from "./formulas/glitches";
export interface Myrian { export interface Myrian {
vulns: number; vulns: number;
totalVulns: number; totalVulns: number;
devices: Device[]; devices: Device[];
glitches: Record<Glitch, number>;
} }
export const distance = (a: Device, b: Device) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y); export const distance = (a: Device, b: Device) => Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
@ -112,6 +116,7 @@ export const isDeviceOSocket = (d: Device): d is OSocket => d.type === DeviceTyp
export const isDeviceReducer = (d: Device): d is Reducer => d.type === DeviceType.Reducer; 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 isDeviceCache = (d: Device): d is Cache => d.type === DeviceType.Cache;
export const isDeviceLock = (d: Device): d is Lock => d.type === DeviceType.Lock; 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 => export const findDevice = (id: DeviceID, type?: DeviceType): Device | undefined =>
myrian.devices.find( myrian.devices.find(
@ -123,3 +128,8 @@ export const removeDevice = (id: DeviceID, type?: DeviceType) => {
(e) => !((typeof id === "string" ? e.name === id : e.x === id[0] && e.y === id[1]) && (!type || type === e.type)), (e) => !((typeof id === "string" ? e.name === id : e.x === id[0] && e.y === id[1]) && (!type || type === e.type)),
); );
}; };
export const getTotalGlitchMult = () =>
Object.entries(myrian.glitches).reduce((acc, [glitch, lvl]) => {
return acc * glitchMult(glitch as Glitch, lvl);
}, 1);

@ -11,6 +11,7 @@ export const maxContentScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [Infinity, 1, -1, 4095], [DeviceType.Reducer]: [Infinity, 1, -1, 4095],
[DeviceType.Cache]: [1.2, 10, 0, 63], [DeviceType.Cache]: [1.2, 10, 0, 63],
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Battery]: [Infinity, Infinity, Infinity, Infinity],
}; };
// a^(b*X+c)+d // a^(b*X+c)+d
@ -35,6 +36,7 @@ export const deviceScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [1.5, 1, 2, 0], [DeviceType.Reducer]: [1.5, 1, 2, 0],
[DeviceType.Cache]: [1.2, 10, 0, 63], [DeviceType.Cache]: [1.2, 10, 0, 63],
[DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Lock]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Battery]: [1.2, 10, 0, 63],
}; };
export const deviceCost = (type: DeviceType, count?: number) => export const deviceCost = (type: DeviceType, count?: number) =>
@ -54,6 +56,7 @@ export const tierScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [1.5, 1, 2, 0], [DeviceType.Reducer]: [1.5, 1, 2, 0],
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Lock]: [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); export const tierCost = (type: DeviceType, tier: number) => exp(tierScale[type], tier);
@ -65,6 +68,7 @@ export const emissionScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Lock]: [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); export const emissionCost = (type: DeviceType, emissionLvl: number) => exp(emissionScale[type], emissionLvl);
@ -76,6 +80,7 @@ export const moveLvlScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Lock]: [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); export const moveLvlCost = (type: DeviceType, moveLvl: number) => exp(moveLvlScale[type], moveLvl);
@ -87,6 +92,7 @@ export const transferLvlScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Lock]: [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); export const transferLvlCost = (type: DeviceType, transferLvl: number) => exp(transferLvlScale[type], transferLvl);
@ -98,6 +104,7 @@ export const reduceLvlScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Lock]: [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); export const reduceLvlCost = (type: DeviceType, reduceLvl: number) => exp(reduceLvlScale[type], reduceLvl);
@ -109,10 +116,23 @@ export const installLvlScale: Record<DeviceType, FactoryFormulaParams> = {
[DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Reducer]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity], [DeviceType.Cache]: [Infinity, Infinity, Infinity, Infinity],
[DeviceType.Lock]: [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); export const installLvlCost = (type: DeviceType, installLvl: number) => exp(installLvlScale[type], installLvl);
export 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);
/** /**
glitches: glitches:
@ -120,10 +140,11 @@ glitches:
- moving dock & dispensers (higher level move faster, level 0 does not move) - moving dock & dispensers (higher level move faster, level 0 does not move)
- dock complexity (higher level more complex, level 0 is repeating request) - dock complexity (higher level more complex, level 0 is repeating request)
- energy consumption (higher level consume more, level 0 is no consumption) - energy consumption (higher level consume more, level 0 is no consumption)
- ugrade degradation (higher level degrade faster, level 0 does not degrade) - ugrade degradation (hidden tile degrade upgrades, level 0 does not degrade)
- move hinderance (speed) (higher level slower, level 0 is no hinderance) - move hinderance (speed) (higher level slower, level 0 is no hinderance)
- connection hinderance (transfer / charge) (higher level slower, level 0 is immediate transfer speed and charge) - connection hinderance (transfer / charge) (higher level slower, level 0 is immediate transfer speed and charge)
- allocation hinderance (craft & build) (higher level slower, level 0 is no hinderance) - allocation hinderance (craft & build) (higher level slower, level 0 is no hinderance)
special requests like "has red" that increases the reward special requests like "has red" that increases the reward
*/ */

@ -0,0 +1,42 @@
import { Glitch } from "@nsdefs";
export const glitchMaxLvl: Record<Glitch, number> = {
[Glitch.Segmentation]: 10,
[Glitch.Roaming]: 10,
[Glitch.Encryption]: 7,
[Glitch.Magnetism]: 10,
[Glitch.Rust]: 10,
[Glitch.Friction]: 3,
[Glitch.Isolation]: 3,
[Glitch.Virtualization]: 3,
[Glitch.Jamming]: 3,
};
export const giltchMultCoefficients: Record<Glitch, number> = {
[Glitch.Segmentation]: 0, // 1,
[Glitch.Roaming]: 0, // 1,
[Glitch.Encryption]: 0, // 0.1,
[Glitch.Magnetism]: 0.2,
[Glitch.Rust]: 0, // 1,
[Glitch.Friction]: 0.2,
[Glitch.Isolation]: 0.2,
[Glitch.Virtualization]: 0.2,
[Glitch.Jamming]: 0.2,
};
export const glitchMult = (glitch: Glitch, lvl: number) => 1 + lvl * giltchMultCoefficients[glitch];
// move hinderance
export const frictionMult = (lvl: number) => Math.pow(1.25, lvl);
// transfer slow down
export const isolationMult = (lvl: number) => Math.pow(2, lvl);
// install/uninstall slow down
export const virtualizationMult = (lvl: number) => Math.pow(3, lvl);
// reduce slow down
export const jammingMult = (lvl: number) => Math.pow(1.3, lvl);
// energy loss
export const magnetismLoss = (lvl: number) => lvl;

@ -39,6 +39,10 @@ These devices act as storage for components.
These devices cannot be installed. They appear after various conditions are fulfilled in order to block certain tiles. 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 ## 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. 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.
@ -54,3 +58,28 @@ 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 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). 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.
### Isolation
When Isolation is active busses transfer and charge more slowly.
### Virtualization
When Virtualization is active busses install and uninstall devices more slowly.
### Jamming
When Jamming is active busses use reducers more slowly.

@ -7,6 +7,7 @@ import MoveToInboxIcon from "@mui/icons-material/MoveToInbox";
import OutboxIcon from "@mui/icons-material/Outbox"; import OutboxIcon from "@mui/icons-material/Outbox";
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank"; import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
import MergeTypeIcon from "@mui/icons-material/MergeType"; import MergeTypeIcon from "@mui/icons-material/MergeType";
import BatteryChargingFullIcon from "@mui/icons-material/BatteryChargingFull";
import BlockIcon from "@mui/icons-material/Block"; import BlockIcon from "@mui/icons-material/Block";
import { Tooltip, Typography } from "@mui/material"; import { Tooltip, Typography } from "@mui/material";
import { isDeviceContainer } from "../Myrian"; import { isDeviceContainer } from "../Myrian";
@ -110,6 +111,8 @@ const ReducerIcon = styled(MergeTypeIcon)(defaultIconStyle);
const CacheIcon = styled(CheckBoxOutlineBlankIcon)(defaultIconStyle); const CacheIcon = styled(CheckBoxOutlineBlankIcon)(defaultIconStyle);
const BatteryIcon = styled(BatteryChargingFullIcon)(defaultIconStyle);
interface ITooltipContentProps { interface ITooltipContentProps {
device: Device; device: Device;
content: React.ReactElement; content: React.ReactElement;
@ -143,6 +146,24 @@ export const DeviceIcon = ({ device }: { device: Device }): React.ReactElement =
case DeviceType.Lock: { case DeviceType.Lock: {
return <LockIcon />; return <LockIcon />;
} }
case DeviceType.Battery: {
return (
<Tooltip
title={
<TooltipContent
device={device}
content={
<Typography>
{device.energy} / {device.maxEnergy}
</Typography>
}
/>
}
>
<BatteryIcon />
</Tooltip>
);
}
case DeviceType.Cache: { case DeviceType.Cache: {
return ( return (
<Tooltip title={<TooltipContent device={device} content={<TooltipInventory device={device} />} />}> <Tooltip title={<TooltipContent device={device} content={<TooltipInventory device={device} />} />}>

@ -1,7 +1,8 @@
import { Bus, Myrian as IMyrian, DeviceType, Component, Reducer } from "@nsdefs"; import { Bus, Myrian as IMyrian, DeviceType, Component, Reducer, Glitch, Battery } from "@nsdefs";
import { InternalAPI } from "../Netscript/APIWrapper"; import { InternalAPI } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";
import { import {
NewBattery,
NewBus, NewBus,
NewCache, NewCache,
NewISocket, NewISocket,
@ -22,6 +23,7 @@ import {
isDeviceContainer, isDeviceContainer,
isDeviceBus, isDeviceBus,
removeDevice, removeDevice,
getTotalGlitchMult,
} from "../Myrian/Myrian"; } from "../Myrian/Myrian";
import { import {
deviceCost, deviceCost,
@ -30,6 +32,7 @@ import {
installLvlCost, installLvlCost,
installSpeed, installSpeed,
isocketSpeed, isocketSpeed,
maxEnergyCost,
moveLvlCost, moveLvlCost,
moveSpeed, moveSpeed,
reduceLvlCost, reduceLvlCost,
@ -41,6 +44,15 @@ import {
} from "../Myrian/formulas/formulas"; } from "../Myrian/formulas/formulas";
import { recipes } from "../Myrian/formulas/recipes"; import { recipes } from "../Myrian/formulas/recipes";
import { componentTiers } from "../Myrian/formulas/components"; import { componentTiers } from "../Myrian/formulas/components";
import {
frictionMult,
glitchMaxLvl,
glitchMult,
isolationMult,
jammingMult,
magnetismLoss,
virtualizationMult,
} from "../Myrian/formulas/glitches";
export function NetscriptMyrian(): InternalAPI<IMyrian> { export function NetscriptMyrian(): InternalAPI<IMyrian> {
return { return {
@ -88,11 +100,18 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
return Promise.resolve(false); return Promise.resolve(false);
} }
const outOfEnergy = bus.energy === 0 ? 0.5 : 1;
bus.isBusy = true; bus.isBusy = true;
return helpers return helpers
.netscriptDelay(ctx, moveSpeed(bus.moveLvl), true) .netscriptDelay(
ctx,
moveSpeed(bus.moveLvl) * frictionMult(myrian.glitches[Glitch.Friction]) * outOfEnergy,
true,
)
.then(() => { .then(() => {
bus.isBusy = false; bus.isBusy = false;
bus.energy = Math.max(0, bus.energy - magnetismLoss(myrian.glitches[Glitch.Magnetism]));
if (findDevice([x, y])) { if (findDevice([x, y])) {
helpers.log(ctx, () => `[${x}, ${y}] is occupied`); helpers.log(ctx, () => `[${x}, ${y}] is occupied`);
return Promise.resolve(false); return Promise.resolve(false);
@ -170,7 +189,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
toDevice.isBusy = true; toDevice.isBusy = true;
return helpers return helpers
.netscriptDelay(ctx, transferSpeed(bus.transferLvl), true) .netscriptDelay(ctx, transferSpeed(bus.transferLvl) * isolationMult(myrian.glitches[Glitch.Isolation]), true)
.then(() => { .then(() => {
toDevice.content = toDevice.content.filter((item) => !output.includes(item)); toDevice.content = toDevice.content.filter((item) => !output.includes(item));
toDevice.content.push(...input); toDevice.content.push(...input);
@ -190,7 +209,8 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
case DeviceType.OSocket: { case DeviceType.OSocket: {
if (inventoryMatches(container.currentRequest, container.content)) { if (inventoryMatches(container.currentRequest, container.content)) {
const gain = container.content.map((i) => vulnsMap[i]).reduce((a, b) => a + b, 0); const gain =
container.content.map((i) => vulnsMap[i]).reduce((a, b) => a + b, 0) * getTotalGlitchMult();
myrian.vulns += gain; myrian.vulns += gain;
myrian.totalVulns += gain; myrian.totalVulns += gain;
container.content = []; container.content = [];
@ -246,7 +266,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
bus.isBusy = true; bus.isBusy = true;
reducer.isBusy = true; reducer.isBusy = true;
return helpers return helpers
.netscriptDelay(ctx, reduceSpeed(bus.reduceLvl), true) .netscriptDelay(ctx, reduceSpeed(bus.reduceLvl) * jammingMult(myrian.glitches[Glitch.Jamming]), true)
.then(() => { .then(() => {
reducer.content = [recipe.output]; reducer.content = [recipe.output];
return Promise.resolve(true); return Promise.resolve(true);
@ -256,6 +276,38 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
reducer.isBusy = false; reducer.isBusy = false;
}); });
}, },
energize: (ctx) => async (_bus, _battery) => {
const busID = helpers.deviceID(ctx, "bus", _bus);
const batteryID = helpers.deviceID(ctx, "battery", _battery);
const bus = findDevice(busID, DeviceType.Bus) as Bus;
if (!bus) {
helpers.log(ctx, () => `bus ${busID} not found`);
return Promise.resolve(-1);
}
const battery = findDevice(batteryID, DeviceType.Battery) as Battery;
if (!battery) {
helpers.log(ctx, () => `battery ${batteryID} not found`);
return Promise.resolve(-1);
}
const transfer = Math.min(battery.energy, bus.maxEnergy - bus.energy);
bus.isBusy = true;
battery.isBusy = true;
return helpers
.netscriptDelay(ctx, 100 * transfer, true)
.then(() => {
bus.energy += transfer;
battery.energy -= transfer;
return Promise.resolve(transfer);
})
.finally(() => {
bus.isBusy = false;
battery.isBusy = false;
});
},
upgradeMaxContent: (ctx) => (_id) => { upgradeMaxContent: (ctx) => (_id) => {
const id = helpers.deviceID(ctx, "id", _id); const id = helpers.deviceID(ctx, "id", _id);
const container = findDevice(id); const container = findDevice(id);
@ -353,7 +405,11 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
const lock = NewLock(lockName, x, y); const lock = NewLock(lockName, x, y);
lock.isBusy = true; lock.isBusy = true;
return helpers return helpers
.netscriptDelay(ctx, installSpeed(bus.installLvl), true) .netscriptDelay(
ctx,
installSpeed(bus.installLvl) * virtualizationMult(myrian.glitches[Glitch.Virtualization]),
true,
)
.then(() => { .then(() => {
bus.isBusy = false; bus.isBusy = false;
removeDevice(lockName); removeDevice(lockName);
@ -376,6 +432,11 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
} }
case DeviceType.Cache: { case DeviceType.Cache: {
NewCache(name, x, y); NewCache(name, x, y);
break;
}
case DeviceType.Battery: {
NewBattery(name, x, y);
break;
} }
} }
return Promise.resolve(true); return Promise.resolve(true);
@ -408,7 +469,11 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
bus.isBusy = true; bus.isBusy = true;
placedDevice.isBusy = true; placedDevice.isBusy = true;
return helpers return helpers
.netscriptDelay(ctx, installSpeed(bus.installLvl), true) .netscriptDelay(
ctx,
installSpeed(bus.installLvl) * virtualizationMult(myrian.glitches[Glitch.Virtualization]),
true,
)
.then(() => { .then(() => {
bus.isBusy = false; bus.isBusy = false;
placedDevice.isBusy = false; placedDevice.isBusy = false;
@ -528,5 +593,45 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
device.installLvl++; device.installLvl++;
return true; return true;
}, },
getUpgradeMaxEnergyCost: (ctx) => (_id) => {
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);
},
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 (myrian.vulns < cost) return false;
myrian.vulns -= cost;
device.maxEnergy++;
return true;
},
setGlitchLvl: (ctx) => async (_glitch, _lvl) => {
const glitch = helpers.string(ctx, "glitch", _glitch);
const lvl = helpers.number(ctx, "lvl", _lvl);
if (lvl < 0 || lvl > glitchMaxLvl[glitch as Glitch]) return Promise.resolve();
const currentLvl = myrian.glitches[glitch as Glitch];
return helpers.netscriptDelay(ctx, Math.abs(lvl - currentLvl) * 5000, true).then(() => {
myrian.glitches[glitch as Glitch] = lvl;
});
},
getGlitchLvl: (ctx) => (_glitch) => {
const glitch = helpers.string(ctx, "glitch", _glitch) as Glitch;
return myrian.glitches[glitch];
},
getGlitchMaxLvl: (ctx) => (_glitch) => {
const glitch = helpers.string(ctx, "glitch", _glitch) as Glitch;
return glitchMaxLvl[glitch];
},
getGlitchMult: (ctx) => (_glitch) => {
const glitch = helpers.string(ctx, "glitch", _glitch) as Glitch;
return glitchMult(glitch, myrian.glitches[glitch]);
},
getTotalGlitchMult: () => () => getTotalGlitchMult(),
}; };
} }

@ -5150,6 +5150,7 @@ export enum DeviceType {
Reducer = "reducer", Reducer = "reducer",
Cache = "cache", Cache = "cache",
Lock = "lock", Lock = "lock",
Battery = "battery",
} }
export enum Component { export enum Component {
@ -5222,6 +5223,27 @@ export enum Component {
W7 = "w7", W7 = "w7",
} }
export enum Glitch {
// Locks spawn at random
Segmentation = "segmentation",
// ISockets and OSockets move around on their own
Roaming = "roaming",
// OSocket ask for more complicated components
Encryption = "encryption",
// Energy starts being consumed (level 0 is no consumption)
Magnetism = "magnetism",
// Hidden tiles on the board, when stepped on the bus loses upgrades
Rust = "rust",
// Move slows down
Friction = "friction",
// Transfer components and charging slows down
Isolation = "isolation",
// Install/Uninstall slows down
Virtualization = "virtualization",
// Reduce slows down
Jamming = "jamming",
}
export interface BaseDevice { export interface BaseDevice {
name: string; name: string;
type: DeviceType; type: DeviceType;
@ -5230,14 +5252,21 @@ export interface BaseDevice {
isBusy: boolean; isBusy: boolean;
} }
export interface Bus extends ContainerDevice { export interface Bus extends ContainerDevice, EnergyDevice {
type: DeviceType.Bus; type: DeviceType.Bus;
moveLvl: number; moveLvl: number;
transferLvl: number; transferLvl: number;
reduceLvl: number; reduceLvl: number;
installLvl: number; installLvl: number;
// energy: number; }
// maxEnergy: number;
export interface EnergyDevice extends BaseDevice {
energy: number;
maxEnergy: number;
}
export interface TieredDevice extends BaseDevice {
tier: number;
} }
export interface ContainerDevice extends BaseDevice { export interface ContainerDevice extends BaseDevice {
@ -5252,9 +5281,8 @@ export interface ISocket extends ContainerDevice {
cooldownUntil: number; cooldownUntil: number;
} }
export interface OSocket extends ContainerDevice { export interface OSocket extends ContainerDevice, TieredDevice {
type: DeviceType.OSocket; type: DeviceType.OSocket;
tier: number;
currentRequest: Component[]; currentRequest: Component[];
} }
@ -5262,15 +5290,18 @@ export interface Cache extends ContainerDevice {
type: DeviceType.Cache; type: DeviceType.Cache;
} }
export interface Reducer extends ContainerDevice { export interface Reducer extends ContainerDevice, TieredDevice {
type: DeviceType.Reducer; type: DeviceType.Reducer;
tier: number;
} }
export interface Lock extends BaseDevice { export interface Lock extends BaseDevice {
type: DeviceType.Lock; type: DeviceType.Lock;
} }
export interface Battery extends EnergyDevice, TieredDevice {
type: DeviceType.Battery;
}
export interface Recipe { export interface Recipe {
input: Component[]; input: Component[];
output: Component; output: Component;
@ -5278,7 +5309,7 @@ export interface Recipe {
export type DeviceID = string | [number, number]; export type DeviceID = string | [number, number];
export type Device = Bus | ISocket | OSocket | Reducer | Cache | Lock; export type Device = Bus | ISocket | OSocket | Reducer | Cache | Lock | Battery;
interface Myrian { interface Myrian {
/** /**
@ -5341,6 +5372,12 @@ interface Myrian {
*/ */
reduce(bus: DeviceID, reducer: DeviceID): Promise<boolean>; reduce(bus: DeviceID, reducer: DeviceID): Promise<boolean>;
/**
* Charge a bus with a battery, restoring it's energy.
* @returns positive number for the amount of energy transfered, -1 on failure.
*/
energize(bus: DeviceID, battery: DeviceID): Promise<number>;
/** /**
* Get the cost of a device. * Get the cost of a device.
* @remarks * @remarks
@ -5476,6 +5513,56 @@ interface Myrian {
* @returns true if the upgrade succeeded, false otherwise. * @returns true if the upgrade succeeded, false otherwise.
*/ */
upgradeInstallLvl(device: DeviceID): boolean; upgradeInstallLvl(device: DeviceID): boolean;
/**
* Get the cost of upgrading the maxEnergy of a device
* @remarks
* RAM cost: 0 GB
* @returns cost of upgrading the maxEnergy of a device, -1 on failure.
*/
getUpgradeMaxEnergyCost(device: DeviceID): number;
/**
* Upgrade the maxEnergy of a device
* @remarks
* RAM cost: 0 GB
* @returns true if the upgrade succeeded, false otherwise.
*/
upgradeMaxEnergy(device: DeviceID): boolean;
/**
* Set the lvl of a glitch
* @param glitch name of the glitch
* @param lvl new lvl of the glitch
*/
setGlitchLvl(glitch: Glitch, lvl: number): Promise<void>;
/**
* Get the lvl of a glitch
* @param glitch name of the glitch
* @returns current lvl of the glitch
*/
getGlitchLvl(glitch: Glitch): number;
/**
* Get the max lvl of a glitch
* @param glitch name of the glitch
* @returns max lvl of the glitch
*/
getGlitchMaxLvl(glitch: Glitch): number;
/**
* Get the vulns multiplier for a glitch
* @param glitch name of the glitch
* @returns multiplier for the glitch
*/
getGlitchMult(glitch: Glitch): number;
/**
* Get the total vulns multiplier for all glitches
* @returns total vulns multiplier
*/
getTotalGlitchMult(): number;
} }
/** @public */ /** @public */