Merge pull request #3761 from danielyxie/dev

Fix .script crashing :(((
This commit is contained in:
hydroflame 2022-05-25 16:10:19 -04:00 committed by GitHub
commit 3ba8e59a9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 2423 additions and 2274 deletions

@ -4,7 +4,11 @@ module.exports = {
commonjs: true, commonjs: true,
es6: false, es6: false,
}, },
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
// "plugin:@typescript-eslint/recommended-requiring-type-checking",
],
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
parserOptions: { parserOptions: {
ecmaVersion: 8, ecmaVersion: 8,
@ -12,6 +16,7 @@ module.exports = {
ecmaFeatures: { ecmaFeatures: {
experimentalObjectRestSpread: true, experimentalObjectRestSpread: true,
}, },
project: ["./tsconfig.json", "./test/tsconfig.json", "./tools/tsconfig.json", "./test/cypress/tsconfig.json"],
}, },
plugins: ["@typescript-eslint"], plugins: ["@typescript-eslint"],
rules: { rules: {

4
dist/main.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

42
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -114,8 +114,8 @@
"start:container": "webpack-dev-server --progress --env.devServer --mode development --env.runInContainer", "start:container": "webpack-dev-server --progress --env.devServer --mode development --env.runInContainer",
"build": "webpack --mode production", "build": "webpack --mode production",
"build:dev": "webpack --mode development", "build:dev": "webpack --mode development",
"lint": "eslint --fix --ext js,jsx,ts,tsx --max-warnings 0 .", "lint": "eslint --fix --ext js,jsx,ts,tsx --max-warnings 0 src",
"lint:report": "eslint --ext js,jsx,ts,tsx --max-warnings 0 .", "lint:report": "eslint --ext js,jsx,ts,tsx --max-warnings 0 src",
"lint:report-diff": "eslint --max-warnings 0 $(git diff --name-only --diff-filter=ACMRTUXB origin/dev | grep -E \"(.js$|.jsx$|.ts$|.tsx$)\" | xargs)", "lint:report-diff": "eslint --max-warnings 0 $(git diff --name-only --diff-filter=ACMRTUXB origin/dev | grep -E \"(.js$|.jsx$|.ts$|.tsx$)\" | xargs)",
"preinstall": "node ./tools/engines-check/engines-check.js", "preinstall": "node ./tools/engines-check/engines-check.js",
"postinstall": "cd electron && npm install", "postinstall": "cd electron && npm install",

@ -70,17 +70,17 @@ export class Bladeburner implements IBladeburner {
type: ActionTypes["Idle"], type: ActionTypes["Idle"],
}); });
cities: any = {}; cities: Record<string, City> = {};
city: string = BladeburnerConstants.CityNames[2]; city: string = BladeburnerConstants.CityNames[2];
skills: any = {}; skills: Record<string, number> = {};
skillMultipliers: any = {}; skillMultipliers: Record<string, number> = {};
staminaBonus = 0; staminaBonus = 0;
maxStamina = 0; maxStamina = 0;
stamina = 0; stamina = 0;
contracts: any = {}; contracts: Record<string, Contract> = {};
operations: any = {}; operations: Record<string, Operation> = {};
blackops: any = {}; blackops: Record<string, boolean> = {};
logging: any = { logging = {
general: true, general: true,
contracts: true, contracts: true,
ops: true, ops: true,
@ -477,54 +477,54 @@ export class Bladeburner implements IBladeburner {
this.postToConsole("Effects: "); this.postToConsole("Effects: ");
const multKeys = Object.keys(this.skillMultipliers); const multKeys = Object.keys(this.skillMultipliers);
for (let i = 0; i < multKeys.length; ++i) { for (let i = 0; i < multKeys.length; ++i) {
let mult = this.skillMultipliers[multKeys[i]]; const mult = this.skillMultipliers[multKeys[i]];
if (mult && mult !== 1) { if (mult && mult !== 1) {
mult = formatNumber(mult, 3); const mults = formatNumber(mult, 3);
switch (multKeys[i]) { switch (multKeys[i]) {
case "successChanceAll": case "successChanceAll":
this.postToConsole("Total Success Chance: x" + mult); this.postToConsole("Total Success Chance: x" + mults);
break; break;
case "successChanceStealth": case "successChanceStealth":
this.postToConsole("Stealth Success Chance: x" + mult); this.postToConsole("Stealth Success Chance: x" + mults);
break; break;
case "successChanceKill": case "successChanceKill":
this.postToConsole("Retirement Success Chance: x" + mult); this.postToConsole("Retirement Success Chance: x" + mults);
break; break;
case "successChanceContract": case "successChanceContract":
this.postToConsole("Contract Success Chance: x" + mult); this.postToConsole("Contract Success Chance: x" + mults);
break; break;
case "successChanceOperation": case "successChanceOperation":
this.postToConsole("Operation Success Chance: x" + mult); this.postToConsole("Operation Success Chance: x" + mults);
break; break;
case "successChanceEstimate": case "successChanceEstimate":
this.postToConsole("Synthoid Data Estimate: x" + mult); this.postToConsole("Synthoid Data Estimate: x" + mults);
break; break;
case "actionTime": case "actionTime":
this.postToConsole("Action Time: x" + mult); this.postToConsole("Action Time: x" + mults);
break; break;
case "effHack": case "effHack":
this.postToConsole("Hacking Skill: x" + mult); this.postToConsole("Hacking Skill: x" + mults);
break; break;
case "effStr": case "effStr":
this.postToConsole("Strength: x" + mult); this.postToConsole("Strength: x" + mults);
break; break;
case "effDef": case "effDef":
this.postToConsole("Defense: x" + mult); this.postToConsole("Defense: x" + mults);
break; break;
case "effDex": case "effDex":
this.postToConsole("Dexterity: x" + mult); this.postToConsole("Dexterity: x" + mults);
break; break;
case "effAgi": case "effAgi":
this.postToConsole("Agility: x" + mult); this.postToConsole("Agility: x" + mults);
break; break;
case "effCha": case "effCha":
this.postToConsole("Charisma: x" + mult); this.postToConsole("Charisma: x" + mults);
break; break;
case "effInt": case "effInt":
this.postToConsole("Intelligence: x" + mult); this.postToConsole("Intelligence: x" + mults);
break; break;
case "stamina": case "stamina":
this.postToConsole("Stamina: x" + mult); this.postToConsole("Stamina: x" + mults);
break; break;
default: default:
console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`); console.warn(`Unrecognized SkillMult Key: ${multKeys[i]}`);
@ -2029,12 +2029,12 @@ export class Bladeburner implements IBladeburner {
this.stamina = Math.min(this.maxStamina, this.stamina); this.stamina = Math.min(this.maxStamina, this.stamina);
// Count increase for contracts/operations // Count increase for contracts/operations
for (const contract of Object.values(this.contracts) as Contract[]) { for (const contract of Object.values(this.contracts)) {
const growthF = Growths[contract.name]; const growthF = Growths[contract.name];
if (growthF === undefined) throw new Error(`growth formula for action '${contract.name}' is undefined`); if (growthF === undefined) throw new Error(`growth formula for action '${contract.name}' is undefined`);
contract.count += (seconds * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod; contract.count += (seconds * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
} }
for (const op of Object.values(this.operations) as Operation[]) { for (const op of Object.values(this.operations)) {
const growthF = Growths[op.name]; const growthF = Growths[op.name];
if (growthF === undefined) throw new Error(`growth formula for action '${op.name}' is undefined`); if (growthF === undefined) throw new Error(`growth formula for action '${op.name}' is undefined`);
if (growthF !== undefined) { if (growthF !== undefined) {

@ -74,7 +74,7 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
<CopyableText value={props.action.name} /> <CopyableText value={props.action.name} />
<StartButton <StartButton
bladeburner={props.bladeburner} bladeburner={props.bladeburner}
type={ActionTypes[props.action.name as string]} type={ActionTypes[props.action.name ]}
name={props.action.name} name={props.action.name}
rerender={rerender} rerender={rerender}
/> />

@ -131,8 +131,6 @@ export class Product {
this.fin = true; this.fin = true;
//Calculate properties //Calculate properties
const progrMult = this.prog / 100;
const engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"]; const engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"];
const mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"]; const mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"];
const rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"]; const rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"];
@ -141,7 +139,7 @@ export class Product {
const designMult = 1 + Math.pow(this.designCost, 0.1) / 100; const designMult = 1 + Math.pow(this.designCost, 0.1) / 100;
const balanceMult = 1.2 * engrRatio + 0.9 * mgmtRatio + 1.3 * rndRatio + 1.5 * opsRatio + busRatio; const balanceMult = 1.2 * engrRatio + 0.9 * mgmtRatio + 1.3 * rndRatio + 1.5 * opsRatio + busRatio;
const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800; const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800;
const totalMult = progrMult * balanceMult * designMult * sciMult; const totalMult = balanceMult * designMult * sciMult;
this.qlt = this.qlt =
totalMult * totalMult *

@ -66,7 +66,7 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<TimeSkip player={props.player} engine={props.engine} /> <TimeSkip player={props.player} engine={props.engine} />
<Achievements player={props.player} engine={props.engine} /> <Achievements player={props.player} engine={props.engine} />
<Entropy player={props.player} engine={props.engine} /> <Entropy player={props.player} engine={props.engine} />
<SaveFile player={props.player} /> <SaveFile />
</> </>
); );
} }

@ -22,7 +22,7 @@ export function Augmentations(props: IProps): React.ReactElement {
const [augmentation, setAugmentation] = useState("Augmented Targeting I"); const [augmentation, setAugmentation] = useState("Augmented Targeting I");
function setAugmentationDropdown(event: SelectChangeEvent<string>): void { function setAugmentationDropdown(event: SelectChangeEvent<string>): void {
setAugmentation(event.target.value as string); setAugmentation(event.target.value );
} }
function queueAug(): void { function queueAug(): void {
props.player.queueAugmentation(augmentation); props.player.queueAugmentation(augmentation);

@ -15,7 +15,7 @@ import { CodingContractTypes } from "../../CodingContracts";
export function CodingContracts(): React.ReactElement { export function CodingContracts(): React.ReactElement {
const [codingcontract, setCodingcontract] = useState("Find Largest Prime Factor"); const [codingcontract, setCodingcontract] = useState("Find Largest Prime Factor");
function setCodingcontractDropdown(event: SelectChangeEvent<string>): void { function setCodingcontractDropdown(event: SelectChangeEvent<string>): void {
setCodingcontract(event.target.value as string); setCodingcontract(event.target.value );
} }
function specificContract(): void { function specificContract(): void {

@ -18,7 +18,7 @@ const bigNumber = 1e12;
export function Companies(): React.ReactElement { export function Companies(): React.ReactElement {
const [company, setCompany] = useState(FactionNames.ECorp as string); const [company, setCompany] = useState(FactionNames.ECorp as string);
function setCompanyDropdown(event: SelectChangeEvent<string>): void { function setCompanyDropdown(event: SelectChangeEvent<string>): void {
setCompany(event.target.value as string); setCompany(event.target.value );
} }
function resetCompanyRep(): void { function resetCompanyRep(): void {
AllCompanies[company].playerReputation = 0; AllCompanies[company].playerReputation = 0;

@ -29,7 +29,7 @@ export function Factions(props: IProps): React.ReactElement {
const [faction, setFaction] = useState(FactionNames.Illuminati as string); const [faction, setFaction] = useState(FactionNames.Illuminati as string);
function setFactionDropdown(event: SelectChangeEvent<string>): void { function setFactionDropdown(event: SelectChangeEvent<string>): void {
setFaction(event.target.value as string); setFaction(event.target.value );
} }
function receiveInvite(): void { function receiveInvite(): void {

@ -19,7 +19,7 @@ interface IProps {
export function Programs(props: IProps): React.ReactElement { export function Programs(props: IProps): React.ReactElement {
const [program, setProgram] = useState("NUKE.exe"); const [program, setProgram] = useState("NUKE.exe");
function setProgramDropdown(event: SelectChangeEvent<string>): void { function setProgramDropdown(event: SelectChangeEvent<string>): void {
setProgram(event.target.value as string); setProgram(event.target.value );
} }
function addProgram(): void { function addProgram(): void {
if (!props.player.hasProgram(program)) { if (!props.player.hasProgram(program)) {

@ -6,20 +6,13 @@ import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { saveObject } from "../../SaveObject"; import { saveObject } from "../../SaveObject";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar";
import { Upload } from "@mui/icons-material"; import { Upload } from "@mui/icons-material";
import { Button } from "@mui/material"; import { Button } from "@mui/material";
import { OptionSwitch } from "../../ui/React/OptionSwitch"; import { OptionSwitch } from "../../ui/React/OptionSwitch";
// Update as additional BitNodes get implemented export function SaveFile(): React.ReactElement {
interface IProps {
player: IPlayer;
}
export function SaveFile(props: IProps): React.ReactElement {
const importInput = useRef<HTMLInputElement>(null); const importInput = useRef<HTMLInputElement>(null);
const [saveFile, setSaveFile] = useState(""); const [saveFile, setSaveFile] = useState("");
const [restoreScripts, setRestoreScripts] = useState(true); const [restoreScripts, setRestoreScripts] = useState(true);

@ -15,7 +15,7 @@ import MenuItem from "@mui/material/MenuItem";
export function Servers(): React.ReactElement { export function Servers(): React.ReactElement {
const [server, setServer] = useState("home"); const [server, setServer] = useState("home");
function setServerDropdown(event: SelectChangeEvent<string>): void { function setServerDropdown(event: SelectChangeEvent<string>): void {
setServer(event.target.value as string); setServer(event.target.value );
} }
function rootServer(): void { function rootServer(): void {
const s = GetServer(server); const s = GetServer(server);

@ -8,8 +8,8 @@ export function Unclickable(): React.ReactElement {
function unclickable(event: React.MouseEvent<HTMLDivElement>): void { function unclickable(event: React.MouseEvent<HTMLDivElement>): void {
if (!event.target || !(event.target instanceof Element)) return; if (!event.target || !(event.target instanceof Element)) return;
const display = getComputedStyle(event.target as Element).display; const display = getComputedStyle(event.target ).display;
const visibility = getComputedStyle(event.target as Element).visibility; const visibility = getComputedStyle(event.target ).visibility;
if (display === "none" && visibility === "hidden" && event.isTrusted) player.giveExploit(Exploit.Unclickable); if (display === "none" && visibility === "hidden" && event.isTrusted) player.giveExploit(Exploit.Unclickable);
} }

@ -54,8 +54,8 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
} }
function handleLocaleChange(event: SelectChangeEvent<string>): void { function handleLocaleChange(event: SelectChangeEvent<string>): void {
setLocale(event.target.value as string); setLocale(event.target.value );
Settings.Locale = event.target.value as string; Settings.Locale = event.target.value ;
} }
function handleTimestampFormatChange(event: React.ChangeEvent<HTMLInputElement>): void { function handleTimestampFormatChange(event: React.ChangeEvent<HTMLInputElement>): void {

@ -54,7 +54,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
multiplier = getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel); multiplier = getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel);
} else { } else {
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level; const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult );
} }
const increase = const increase =
@ -94,7 +94,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam); multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam);
} else { } else {
const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram)); const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram));
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult );
} }
const increase = const increase =
@ -144,7 +144,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores); multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores);
} else { } else {
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores; const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult );
} }
const increase = const increase =

@ -9,15 +9,16 @@ import { Settings } from "../Settings/Settings";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
type ExternalFunction = (...args: any[]) => any; type ExternalFunction = (...args: any[]) => any;
type ExternalAPI = { export type ExternalAPI = {
[string: string]: ExternalAPI | ExternalFunction; [string: string]: ExternalAPI | ExternalFunction;
}; };
type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: NetscriptContext) => F; type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: NetscriptContext) => F;
export type InternalAPI<API> = { export type InternalAPI<API> = {
[Property in keyof API]: API[Property] extends ExternalFunction [Property in keyof API]: API[Property] extends ExternalFunction
? InternalFunction<API[Property]> ? InternalFunction<API[Property]>
: API[Property] extends ExternalAPI : API[Property] extends object
? InternalAPI<API[Property]> ? InternalAPI<API[Property]>
: never; : never;
}; };
@ -42,9 +43,14 @@ type NetscriptHelpers = {
number: (funcName: string, argName: string, v: unknown) => number; number: (funcName: string, argName: string, v: unknown) => number;
city: (funcName: string, argName: string, v: unknown) => CityName; city: (funcName: string, argName: string, v: unknown) => CityName;
boolean: (v: unknown) => boolean; boolean: (v: unknown) => boolean;
getServer: (hostname: string, callingFnName: string) => BaseServer; getServer: (hostname: string, ctx: NetscriptContext) => BaseServer;
checkSingularityAccess: (func: string) => void; checkSingularityAccess: (func: string) => void;
hack: (hostname: any, manual: any, { threads: requestedThreads, stock }?: any) => Promise<number>; hack: (
ctx: NetscriptContext,
hostname: any,
manual: any,
{ threads: requestedThreads, stock }?: any,
) => Promise<number>;
getValidPort: (funcName: string, port: any) => IPort; getValidPort: (funcName: string, port: any) => IPort;
}; };
@ -87,7 +93,7 @@ function wrapFunction(
number: (argName: string, v: unknown) => helpers.number(functionPath, argName, v), number: (argName: string, v: unknown) => helpers.number(functionPath, argName, v),
city: (argName: string, v: unknown) => helpers.city(functionPath, argName, v), city: (argName: string, v: unknown) => helpers.city(functionPath, argName, v),
boolean: helpers.boolean, boolean: helpers.boolean,
getServer: (hostname: string) => helpers.getServer(hostname, functionPath), getServer: (hostname: string) => helpers.getServer(hostname, ctx),
checkSingularityAccess: () => helpers.checkSingularityAccess(functionName), checkSingularityAccess: () => helpers.checkSingularityAccess(functionName),
hack: helpers.hack, hack: helpers.hack,
getValidPort: (port: any) => helpers.getValidPort(functionPath, port), getValidPort: (port: any) => helpers.getValidPort(functionPath, port),
@ -98,7 +104,10 @@ function wrapFunction(
helpers.updateDynamicRam(ctx.function, getRamCost(Player, ...tree, ctx.function)); helpers.updateDynamicRam(ctx.function, getRamCost(Player, ...tree, ctx.function));
if (safetyEnabled) { if (safetyEnabled) {
const now = performance.now(); const now = performance.now();
if (now - workerScript.infiniteLoopSafety > CONSTANTS.InfiniteLoopLimit) { if (
now - workerScript.infiniteLoopSafety > CONSTANTS.InfiniteLoopLimit &&
workerScript.scriptRef.filename.endsWith(".js")
) {
throw new Error( throw new Error(
`Potential infinite loop without sleep detected. The game spent ${CONSTANTS.InfiniteLoopLimit}ms stuck in this script. (Are you using 'asleep' by mistake?)`, `Potential infinite loop without sleep detected. The game spent ${CONSTANTS.InfiniteLoopLimit}ms stuck in this script. (Are you using 'asleep' by mistake?)`,
); );

@ -2,6 +2,7 @@
* The environment in which a script runs. The environment holds * The environment in which a script runs. The environment holds
* Netscript functions and arguments for that script. * Netscript functions and arguments for that script.
*/ */
import { NS } from "src/ScriptEditor/NetscriptDefinitions";
import { IMap } from "../types"; import { IMap } from "../types";
export class Environment { export class Environment {
@ -18,7 +19,7 @@ export class Environment {
/** /**
* Environment variables (currently only Netscript functions) * Environment variables (currently only Netscript functions)
*/ */
vars: IMap<any> = {}; vars: any = {};
constructor(parent: Environment | null) { constructor(parent: Environment | null) {
if (parent instanceof Environment) { if (parent instanceof Environment) {

@ -1,6 +1,18 @@
import { IPlayer } from "src/PersonObjects/IPlayer"; import { IPlayer } from "src/PersonObjects/IPlayer";
import { IMap } from "../types"; import { IMap } from "../types";
import { NS as INS } from "../ScriptEditor/NetscriptDefinitions";
import { INetscriptExtra } from "../NetscriptFunctions/Extra";
type RamCostTree<API> = {
[Property in keyof API]: API[Property] extends () => void
? number | ((p: IPlayer) => void)
: API[Property] extends object
? RamCostTree<API[Property]>
: never;
};
// TODO remember to update RamCalculations.js and WorkerScript.js // TODO remember to update RamCalculations.js and WorkerScript.js
// RAM costs for Netscript functions // RAM costs for Netscript functions
@ -89,7 +101,7 @@ function SF4Cost(cost: number): (player: IPlayer) => number {
} }
// Hacknet API // Hacknet API
const hacknet: IMap<any> = { const hacknet = {
numNodes: 0, numNodes: 0,
purchaseNode: 0, purchaseNode: 0,
getPurchaseNodeCost: 0, getPurchaseNodeCost: 0,
@ -106,10 +118,15 @@ const hacknet: IMap<any> = {
hashCost: 0, hashCost: 0,
spendHashes: 0, spendHashes: 0,
maxNumNodes: 0, maxNumNodes: 0,
hashCapacity: 0,
getHashUpgrades: 0,
getHashUpgradeLevel: 0,
getStudyMult: 0,
getTrainingMult: 0,
}; };
// Stock API // Stock API
const stock: IMap<any> = { const stock = {
getSymbols: RamCostConstants.ScriptGetStockRamCost, getSymbols: RamCostConstants.ScriptGetStockRamCost,
getPrice: RamCostConstants.ScriptGetStockRamCost, getPrice: RamCostConstants.ScriptGetStockRamCost,
getAskPrice: RamCostConstants.ScriptGetStockRamCost, getAskPrice: RamCostConstants.ScriptGetStockRamCost,
@ -134,7 +151,7 @@ const stock: IMap<any> = {
}; };
// Singularity API // Singularity API
const singularity: IMap<any> = { const singularity = {
universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
@ -190,7 +207,7 @@ const singularity: IMap<any> = {
}; };
// Gang API // Gang API
const gang: IMap<any> = { const gang = {
createGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, createGang: RamCostConstants.ScriptGangApiBaseRamCost / 4,
inGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, inGang: RamCostConstants.ScriptGangApiBaseRamCost / 4,
getMemberNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, getMemberNames: RamCostConstants.ScriptGangApiBaseRamCost / 4,
@ -215,7 +232,7 @@ const gang: IMap<any> = {
}; };
// Bladeburner API // Bladeburner API
const bladeburner: IMap<any> = { const bladeburner = {
getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
@ -253,15 +270,13 @@ const bladeburner: IMap<any> = {
getBonusTime: 0, getBonusTime: 0,
}; };
const infiltration: IMap<any> = { const infiltration = {
calculateDifficulty: RamCostConstants.ScriptInfiltrationCalculateDifficulty, getPossibleLocations: RamCostConstants.ScriptInfiltrationGetLocations,
calculateRewards: RamCostConstants.ScriptInfiltrationCalculateRewards, getInfiltration: RamCostConstants.ScriptInfiltrationGetInfiltrations,
calculateGetLocations: RamCostConstants.ScriptInfiltrationGetLocations,
calculateGetInfiltrations: RamCostConstants.ScriptInfiltrationGetInfiltrations,
}; };
// Coding Contract API // Coding Contract API
const codingcontract: IMap<any> = { const codingcontract = {
attempt: RamCostConstants.ScriptCodingContractBaseRamCost, attempt: RamCostConstants.ScriptCodingContractBaseRamCost,
getContractType: RamCostConstants.ScriptCodingContractBaseRamCost / 2, getContractType: RamCostConstants.ScriptCodingContractBaseRamCost / 2,
getData: RamCostConstants.ScriptCodingContractBaseRamCost / 2, getData: RamCostConstants.ScriptCodingContractBaseRamCost / 2,
@ -270,7 +285,7 @@ const codingcontract: IMap<any> = {
}; };
// Duplicate Sleeve API // Duplicate Sleeve API
const sleeve: IMap<any> = { const sleeve = {
getNumSleeves: RamCostConstants.ScriptSleeveBaseRamCost, getNumSleeves: RamCostConstants.ScriptSleeveBaseRamCost,
setToShockRecovery: RamCostConstants.ScriptSleeveBaseRamCost, setToShockRecovery: RamCostConstants.ScriptSleeveBaseRamCost,
setToSynchronize: RamCostConstants.ScriptSleeveBaseRamCost, setToSynchronize: RamCostConstants.ScriptSleeveBaseRamCost,
@ -290,7 +305,7 @@ const sleeve: IMap<any> = {
}; };
// Stanek API // Stanek API
const stanek: IMap<any> = { const stanek = {
giftWidth: RamCostConstants.ScriptStanekWidth, giftWidth: RamCostConstants.ScriptStanekWidth,
giftHeight: RamCostConstants.ScriptStanekHeight, giftHeight: RamCostConstants.ScriptStanekHeight,
chargeFragment: RamCostConstants.ScriptStanekCharge, chargeFragment: RamCostConstants.ScriptStanekCharge,
@ -305,7 +320,7 @@ const stanek: IMap<any> = {
}; };
// UI API // UI API
const ui: IMap<any> = { const ui = {
getTheme: 0, getTheme: 0,
setTheme: 0, setTheme: 0,
resetTheme: 0, resetTheme: 0,
@ -313,17 +328,84 @@ const ui: IMap<any> = {
setStyles: 0, setStyles: 0,
resetStyles: 0, resetStyles: 0,
getGameInfo: 0, getGameInfo: 0,
clearTerminal: 0,
}; };
// Grafting API // Grafting API
const grafting: IMap<any> = { const grafting = {
getAugmentationGraftPrice: 3.75, getAugmentationGraftPrice: 3.75,
getAugmentationGraftTime: 3.75, getAugmentationGraftTime: 3.75,
getGraftableAugmentations: 5, getGraftableAugmentations: 5,
graftAugmentation: 7.5, graftAugmentation: 7.5,
}; };
export const RamCosts: IMap<any> = { const corporation = {
createCorporation: 0,
hasUnlockUpgrade: 0,
getUnlockUpgradeCost: 0,
getUpgradeLevel: 0,
getUpgradeLevelCost: 0,
getExpandIndustryCost: 0,
getExpandCityCost: 0,
getInvestmentOffer: 0,
acceptInvestmentOffer: 0,
goPublic: 0,
bribe: 0,
getCorporation: 0,
getDivision: 0,
expandIndustry: 0,
expandCity: 0,
unlockUpgrade: 0,
levelUpgrade: 0,
issueDividends: 0,
buyBackShares: 0,
sellShares: 0,
getBonusTime: 0,
sellMaterial: 0,
sellProduct: 0,
discontinueProduct: 0,
setSmartSupply: 0,
setSmartSupplyUseLeftovers: 0,
buyMaterial: 0,
bulkPurchase: 0,
getWarehouse: 0,
getProduct: 0,
getMaterial: 0,
setMaterialMarketTA1: 0,
setMaterialMarketTA2: 0,
setProductMarketTA1: 0,
setProductMarketTA2: 0,
exportMaterial: 0,
cancelExportMaterial: 0,
purchaseWarehouse: 0,
upgradeWarehouse: 0,
makeProduct: 0,
limitMaterialProduction: 0,
limitProductProduction: 0,
getPurchaseWarehouseCost: 0,
getUpgradeWarehouseCost: 0,
hasWarehouse: 0,
assignJob: 0,
hireEmployee: 0,
upgradeOfficeSize: 0,
throwParty: 0,
buyCoffee: 0,
hireAdVert: 0,
research: 0,
getOffice: 0,
getEmployee: 0,
getHireAdVertCost: 0,
getHireAdVertCount: 0,
getResearchCost: 0,
hasResearched: 0,
setAutoJobAssignment: 0,
getOfficeSizeUpgradeCost: 0,
};
const SourceRamCosts = {
args: undefined as unknown as never[], // special use case
enums: undefined as unknown as never,
corporation,
hacknet, hacknet,
stock, stock,
singularity, singularity,
@ -363,7 +445,6 @@ export const RamCosts: IMap<any> = {
enableLog: 0, enableLog: 0,
isLogEnabled: 0, isLogEnabled: 0,
getScriptLogs: 0, getScriptLogs: 0,
clearTerminal: RamCostConstants.ScriptClearTerminalCost,
nuke: RamCostConstants.ScriptPortProgramRamCost, nuke: RamCostConstants.ScriptPortProgramRamCost,
brutessh: RamCostConstants.ScriptPortProgramRamCost, brutessh: RamCostConstants.ScriptPortProgramRamCost,
ftpcrack: RamCostConstants.ScriptPortProgramRamCost, ftpcrack: RamCostConstants.ScriptPortProgramRamCost,
@ -382,7 +463,6 @@ export const RamCosts: IMap<any> = {
ps: RamCostConstants.ScriptScanRamCost, ps: RamCostConstants.ScriptScanRamCost,
getRecentScripts: RamCostConstants.ScriptRecentScriptsRamCost, getRecentScripts: RamCostConstants.ScriptRecentScriptsRamCost,
hasRootAccess: RamCostConstants.ScriptHasRootAccessRamCost, hasRootAccess: RamCostConstants.ScriptHasRootAccessRamCost,
getIp: RamCostConstants.ScriptGetHostnameRamCost,
getHostname: RamCostConstants.ScriptGetHostnameRamCost, getHostname: RamCostConstants.ScriptGetHostnameRamCost,
getHackingLevel: RamCostConstants.ScriptGetHackingLevelRamCost, getHackingLevel: RamCostConstants.ScriptGetHackingLevelRamCost,
getHackingMultipliers: RamCostConstants.ScriptGetMultipliersRamCost, getHackingMultipliers: RamCostConstants.ScriptGetMultipliersRamCost,
@ -439,12 +519,74 @@ export const RamCosts: IMap<any> = {
getOwnedSourceFiles: RamCostConstants.ScriptGetOwnedSourceFiles, getOwnedSourceFiles: RamCostConstants.ScriptGetOwnedSourceFiles,
tail: 0, tail: 0,
toast: 0, toast: 0,
closeTail: 0,
clearPort: 0,
openDevMenu: 0,
alert: 0,
flags: 0,
exploit: 0,
bypass: 0,
alterReality: 0,
rainbow: 0,
heart: { heart: {
// Easter egg function // Easter egg function
break: 0, break: 0,
}, },
formulas: {
reputation: {
calculateFavorToRep: 0,
calculateRepToFavor: 0,
repFromDonation: 0,
},
skills: {
calculateSkill: 0,
calculateExp: 0,
},
hacking: {
hackChance: 0,
hackExp: 0,
hackPercent: 0,
growPercent: 0,
hackTime: 0,
growTime: 0,
weakenTime: 0,
},
hacknetNodes: {
moneyGainRate: 0,
levelUpgradeCost: 0,
ramUpgradeCost: 0,
coreUpgradeCost: 0,
hacknetNodeCost: 0,
constants: 0,
},
hacknetServers: {
hashGainRate: 0,
levelUpgradeCost: 0,
ramUpgradeCost: 0,
coreUpgradeCost: 0,
cacheUpgradeCost: 0,
hashUpgradeCost: 0,
hacknetServerCost: 0,
constants: 0,
},
gang: {
wantedPenalty: 0,
respectGain: 0,
wantedLevelGain: 0,
moneyGain: 0,
ascensionPointsGain: 0,
ascensionMultiplier: 0,
},
},
}; };
export const RamCosts: IMap<any> = SourceRamCosts;
// This line in particular is there so typescript typechecks that we are not missing any static ram cost.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _typecheck: RamCostTree<INS & INetscriptExtra> = SourceRamCosts;
export function getRamCost(player: IPlayer, ...args: string[]): number { export function getRamCost(player: IPlayer, ...args: string[]): number {
if (args.length === 0) { if (args.length === 0) {
console.warn(`No arguments passed to getRamCost()`); console.warn(`No arguments passed to getRamCost()`);

@ -14,6 +14,7 @@ import { Script } from "../Script/Script";
import { GetServer } from "../Server/AllServers"; import { GetServer } from "../Server/AllServers";
import { BaseServer } from "../Server/BaseServer"; import { BaseServer } from "../Server/BaseServer";
import { IMap } from "../types"; import { IMap } from "../types";
import { NS } from "../ScriptEditor/NetscriptDefinitions";
export class WorkerScript { export class WorkerScript {
/** /**
@ -116,7 +117,7 @@ export class WorkerScript {
*/ */
infiniteLoopSafety = performance.now(); infiniteLoopSafety = performance.now();
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => any) { constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => NS) {
this.name = runningScriptObj.filename; this.name = runningScriptObj.filename;
this.hostname = runningScriptObj.server; this.hostname = runningScriptObj.server;

@ -2,6 +2,7 @@ import { isString } from "./utils/helpers/isString";
import { GetServer } from "./Server/AllServers"; import { GetServer } from "./Server/AllServers";
import { ScriptDeath } from "./Netscript/ScriptDeath"; import { ScriptDeath } from "./Netscript/ScriptDeath";
import { WorkerScript } from "./Netscript/WorkerScript"; import { WorkerScript } from "./Netscript/WorkerScript";
import { NetscriptContext } from "./Netscript/APIWrapper";
export function netscriptDelay(time: number, workerScript: WorkerScript): Promise<void> { export function netscriptDelay(time: number, workerScript: WorkerScript): Promise<void> {
// Cancel any pre-existing netscriptDelay'ed function call // Cancel any pre-existing netscriptDelay'ed function call
@ -36,26 +37,22 @@ export function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string): s
return "|DELIMITER|" + server.hostname + "|DELIMITER|" + workerScript.name + "|DELIMITER|" + msg; return "|DELIMITER|" + server.hostname + "|DELIMITER|" + workerScript.name + "|DELIMITER|" + msg;
} }
export function resolveNetscriptRequestedThreads( export function resolveNetscriptRequestedThreads(ctx: NetscriptContext, requestedThreads: number): number {
workerScript: WorkerScript, const threads = ctx.workerScript.scriptRef.threads;
functionName: string,
requestedThreads: number,
): number {
const threads = workerScript.scriptRef.threads;
if (!requestedThreads) { if (!requestedThreads) {
return isNaN(threads) || threads < 1 ? 1 : threads; return isNaN(threads) || threads < 1 ? 1 : threads;
} }
const requestedThreadsAsInt = requestedThreads | 0; const requestedThreadsAsInt = requestedThreads | 0;
if (isNaN(requestedThreads) || requestedThreadsAsInt < 1) { if (isNaN(requestedThreads) || requestedThreadsAsInt < 1) {
throw makeRuntimeRejectMsg( throw makeRuntimeRejectMsg(
workerScript, ctx.workerScript,
`Invalid thread count passed to ${functionName}: ${requestedThreads}. Threads must be a positive number.`, `Invalid thread count passed to ${ctx.function}: ${requestedThreads}. Threads must be a positive number.`,
); );
} }
if (requestedThreadsAsInt > threads) { if (requestedThreadsAsInt > threads) {
throw makeRuntimeRejectMsg( throw makeRuntimeRejectMsg(
workerScript, ctx.workerScript,
`Too many threads requested by ${functionName}. Requested: ${requestedThreads}. Has: ${threads}.`, `Too many threads requested by ${ctx.function}. Requested: ${requestedThreads}. Has: ${threads}.`,
); );
} }
return requestedThreadsAsInt; return requestedThreadsAsInt;

File diff suppressed because it is too large Load Diff

@ -257,7 +257,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
function getMaterial(divisionName: string, cityName: string, materialName: string): Material { function getMaterial(divisionName: string, cityName: string, materialName: string): Material {
const warehouse = getWarehouse(divisionName, cityName); const warehouse = getWarehouse(divisionName, cityName);
const matName = (materialName as string).replace(/ /g, ""); const matName = (materialName ).replace(/ /g, "");
const material = warehouse.materials[matName]; const material = warehouse.materials[matName];
if (material === undefined) throw new Error(`Invalid material name: '${materialName}'`); if (material === undefined) throw new Error(`Invalid material name: '${materialName}'`);
return material; return material;

@ -1,9 +1,8 @@
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { Exploit } from "../Exploits/Exploit"; import { Exploit } from "../Exploits/Exploit";
import * as bcrypt from "bcryptjs"; import * as bcrypt from "bcryptjs";
import { INetscriptHelper } from "./INetscriptHelper";
import { Apr1Events as devMenu } from "../ui/Apr1"; import { Apr1Events as devMenu } from "../ui/Apr1";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
export interface INetscriptExtra { export interface INetscriptExtra {
heart: { heart: {
@ -16,35 +15,37 @@ export interface INetscriptExtra {
rainbow(guess: string): void; rainbow(guess: string): void;
} }
export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): INetscriptExtra { export function NetscriptExtra(player: IPlayer): InternalAPI<INetscriptExtra> {
return { return {
heart: { heart: {
// Easter egg function // Easter egg function
break: function (): number { break: () => (): number => {
return player.karma; return player.karma;
}, },
}, },
openDevMenu: function (): void { openDevMenu: () => (): void => {
devMenu.emit(); devMenu.emit();
}, },
exploit: function (): void { exploit: () => (): void => {
player.giveExploit(Exploit.UndocumentedFunctionCall); player.giveExploit(Exploit.UndocumentedFunctionCall);
}, },
bypass: function (doc: unknown): void { bypass:
// reset both fields first (ctx: NetscriptContext) =>
const d = doc as any; (doc: unknown): void => {
d.completely_unused_field = undefined; // reset both fields first
const real_document: any = document; const d = doc as any;
real_document.completely_unused_field = undefined; d.completely_unused_field = undefined;
// set one to true and check that it affected the other. const real_document: any = document;
real_document.completely_unused_field = true; real_document.completely_unused_field = undefined;
if (d.completely_unused_field && workerScript.ramUsage === 1.6) { // set one to true and check that it affected the other.
player.giveExploit(Exploit.Bypass); real_document.completely_unused_field = true;
} if (d.completely_unused_field && ctx.workerScript.ramUsage === 1.6) {
d.completely_unused_field = undefined; player.giveExploit(Exploit.Bypass);
real_document.completely_unused_field = undefined; }
}, d.completely_unused_field = undefined;
alterReality: function (): void { real_document.completely_unused_field = undefined;
},
alterReality: () => (): void => {
// We need to trick webpack into not optimizing a variable that is guaranteed to be false (and doesn't use prototypes) // We need to trick webpack into not optimizing a variable that is guaranteed to be false (and doesn't use prototypes)
let x = false; let x = false;
const recur = function (depth: number): void { const recur = function (depth: number): void {
@ -59,20 +60,22 @@ export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, help
player.giveExploit(Exploit.RealityAlteration); player.giveExploit(Exploit.RealityAlteration);
} }
}, },
rainbow: function (guess: unknown): boolean { rainbow:
function tryGuess(): boolean { (ctx: NetscriptContext) =>
// eslint-disable-next-line no-sync (guess: unknown): boolean => {
const verified = bcrypt.compareSync( function tryGuess(): boolean {
helper.string("rainbow", "guess", guess), // eslint-disable-next-line no-sync
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO", const verified = bcrypt.compareSync(
); ctx.helper.string("guess", guess),
if (verified) { "$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO",
player.giveExploit(Exploit.INeedARainbow); );
return true; if (verified) {
player.giveExploit(Exploit.INeedARainbow);
return true;
}
return false;
} }
return false; return tryGuess();
} },
return tryGuess();
},
}; };
} }

@ -2,36 +2,37 @@ import { toNative } from "./toNative";
import * as libarg from "arg"; import * as libarg from "arg";
export function Flags(vargs: string[]): any { export function Flags(vargs: string[]): any {
return function (data: any): any { return () =>
data = toNative(data); (data: any): any => {
// We always want the help flag. data = toNative(data);
const args: { // We always want the help flag.
[key: string]: any; const args: {
} = {}; [key: string]: any;
} = {};
for (const d of data) { for (const d of data) {
let t: any = String; let t: any = String;
if (typeof d[1] === "number") { if (typeof d[1] === "number") {
t = Number; t = Number;
} else if (typeof d[1] === "boolean") { } else if (typeof d[1] === "boolean") {
t = Boolean; t = Boolean;
} else if (Array.isArray(d[1])) { } else if (Array.isArray(d[1])) {
t = [String]; t = [String];
}
const numDashes = d[0].length > 1 ? 2 : 1;
args["-".repeat(numDashes) + d[0]] = t;
} }
const numDashes = d[0].length > 1 ? 2 : 1; const ret = libarg(args, { argv: vargs });
args["-".repeat(numDashes) + d[0]] = t; for (const d of data) {
} if (!ret.hasOwnProperty("--" + d[0]) || !ret.hasOwnProperty("-" + d[0])) ret[d[0]] = d[1];
const ret = libarg(args, { argv: vargs }); }
for (const d of data) { for (const key of Object.keys(ret)) {
if (!ret.hasOwnProperty("--" + d[0]) || !ret.hasOwnProperty("-" + d[0])) ret[d[0]] = d[1]; if (!key.startsWith("-")) continue;
} const value = ret[key];
for (const key of Object.keys(ret)) { delete ret[key];
if (!key.startsWith("-")) continue; const numDashes = key.length === 2 ? 1 : 2;
const value = ret[key]; ret[key.slice(numDashes)] = value;
delete ret[key]; }
const numDashes = key.length === 2 ? 1 : 2; return ret;
ret[key.slice(numDashes)] = value; };
}
return ret;
};
} }

@ -1,5 +1,4 @@
import { INetscriptHelper } from "./INetscriptHelper"; import { INetscriptHelper } from "./INetscriptHelper";
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { calculateServerGrowth } from "../Server/formulas/grow"; import { calculateServerGrowth } from "../Server/formulas/grow";
import { import {
@ -39,212 +38,267 @@ import {
} from "../Gang/formulas/formulas"; } from "../Gang/formulas/formulas";
import { favorToRep as calculateFavorToRep, repToFavor as calculateRepToFavor } from "../Faction/formulas/favor"; import { favorToRep as calculateFavorToRep, repToFavor as calculateRepToFavor } from "../Faction/formulas/favor";
import { repFromDonation } from "../Faction/formulas/donation"; import { repFromDonation } from "../Faction/formulas/donation";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IFormulas { export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): InternalAPI<IFormulas> {
const checkFormulasAccess = function (func: string): void { const checkFormulasAccess = function (ctx: NetscriptContext): void {
if (!player.hasProgram(Programs.Formulas.name)) { if (!player.hasProgram(Programs.Formulas.name)) {
throw helper.makeRuntimeErrorMsg(`formulas.${func}`, `Requires Formulas.exe to run.`); throw helper.makeRuntimeErrorMsg(`formulas.${ctx.function}`, `Requires Formulas.exe to run.`);
} }
}; };
return { return {
reputation: { reputation: {
calculateFavorToRep: function (_favor: unknown): number { calculateFavorToRep:
const favor = helper.number("calculateFavorToRep", "favor", _favor); (ctx: NetscriptContext) =>
checkFormulasAccess("reputation.calculateFavorToRep"); (_favor: unknown): number => {
return calculateFavorToRep(favor); const favor = ctx.helper.number("favor", _favor);
}, checkFormulasAccess(ctx);
calculateRepToFavor: function (_rep: unknown): number { return calculateFavorToRep(favor);
const rep = helper.number("calculateRepToFavor", "rep", _rep); },
checkFormulasAccess("reputation.calculateRepToFavor"); calculateRepToFavor:
return calculateRepToFavor(rep); (ctx: NetscriptContext) =>
}, (_rep: unknown): number => {
repFromDonation: function (_amount: unknown, player: any): number { const rep = ctx.helper.number("rep", _rep);
const amount = helper.number("repFromDonation", "amount", _amount); checkFormulasAccess(ctx);
checkFormulasAccess("reputation.repFromDonation"); return calculateRepToFavor(rep);
return repFromDonation(amount, player); },
}, repFromDonation:
(ctx: NetscriptContext) =>
(_amount: unknown, player: any): number => {
const amount = ctx.helper.number("amount", _amount);
checkFormulasAccess(ctx);
return repFromDonation(amount, player);
},
}, },
skills: { skills: {
calculateSkill: function (_exp: unknown, _mult: unknown = 1): number { calculateSkill:
const exp = helper.number("calculateSkill", "exp", _exp); (ctx: NetscriptContext) =>
const mult = helper.number("calculateSkill", "mult", _mult); (_exp: unknown, _mult: unknown = 1): number => {
checkFormulasAccess("skills.calculateSkill"); const exp = ctx.helper.number("exp", _exp);
return calculateSkill(exp, mult); const mult = ctx.helper.number("mult", _mult);
}, checkFormulasAccess(ctx);
calculateExp: function (_skill: unknown, _mult: unknown = 1): number { return calculateSkill(exp, mult);
const skill = helper.number("calculateExp", "skill", _skill); },
const mult = helper.number("calculateExp", "mult", _mult); calculateExp:
checkFormulasAccess("skills.calculateExp"); (ctx: NetscriptContext) =>
return calculateExp(skill, mult); (_skill: unknown, _mult: unknown = 1): number => {
}, const skill = ctx.helper.number("skill", _skill);
const mult = ctx.helper.number("mult", _mult);
checkFormulasAccess(ctx);
return calculateExp(skill, mult);
},
}, },
hacking: { hacking: {
hackChance: function (server: any, player: any): number { hackChance:
checkFormulasAccess("hacking.hackChance"); (ctx: NetscriptContext) =>
return calculateHackingChance(server, player); (server: any, player: any): number => {
}, checkFormulasAccess(ctx);
hackExp: function (server: any, player: any): number { return calculateHackingChance(server, player);
checkFormulasAccess("hacking.hackExp"); },
return calculateHackingExpGain(server, player); hackExp:
}, (ctx: NetscriptContext) =>
hackPercent: function (server: any, player: any): number { (server: any, player: any): number => {
checkFormulasAccess("hacking.hackPercent"); checkFormulasAccess(ctx);
return calculatePercentMoneyHacked(server, player); return calculateHackingExpGain(server, player);
}, },
growPercent: function (server: any, _threads: unknown, player: any, _cores: unknown = 1): number { hackPercent:
const threads = helper.number("growPercent", "threads", _threads); (ctx: NetscriptContext) =>
const cores = helper.number("growPercent", "cores", _cores); (server: any, player: any): number => {
checkFormulasAccess("hacking.growPercent"); checkFormulasAccess(ctx);
return calculateServerGrowth(server, threads, player, cores); return calculatePercentMoneyHacked(server, player);
}, },
hackTime: function (server: any, player: any): number { growPercent:
checkFormulasAccess("hacking.hackTime"); (ctx: NetscriptContext) =>
return calculateHackingTime(server, player) * 1000; (server: any, _threads: unknown, player: any, _cores: unknown = 1): number => {
}, const threads = ctx.helper.number("threads", _threads);
growTime: function (server: any, player: any): number { const cores = ctx.helper.number("cores", _cores);
checkFormulasAccess("hacking.growTime"); checkFormulasAccess(ctx);
return calculateGrowTime(server, player) * 1000; return calculateServerGrowth(server, threads, player, cores);
}, },
weakenTime: function (server: any, player: any): number { hackTime:
checkFormulasAccess("hacking.weakenTime"); (ctx: NetscriptContext) =>
return calculateWeakenTime(server, player) * 1000; (server: any, player: any): number => {
}, checkFormulasAccess(ctx);
return calculateHackingTime(server, player) * 1000;
},
growTime:
(ctx: NetscriptContext) =>
(server: any, player: any): number => {
checkFormulasAccess(ctx);
return calculateGrowTime(server, player) * 1000;
},
weakenTime:
(ctx: NetscriptContext) =>
(server: any, player: any): number => {
checkFormulasAccess(ctx);
return calculateWeakenTime(server, player) * 1000;
},
}, },
hacknetNodes: { hacknetNodes: {
moneyGainRate: function (_level: unknown, _ram: unknown, _cores: unknown, _mult: unknown = 1): number { moneyGainRate:
const level = helper.number("moneyGainRate", "level", _level); (ctx: NetscriptContext) =>
const ram = helper.number("moneyGainRate", "ram", _ram); (_level: unknown, _ram: unknown, _cores: unknown, _mult: unknown = 1): number => {
const cores = helper.number("moneyGainRate", "cores", _cores); const level = ctx.helper.number("level", _level);
const mult = helper.number("moneyGainRate", "mult", _mult); const ram = ctx.helper.number("ram", _ram);
checkFormulasAccess("hacknetNodes.moneyGainRate"); const cores = ctx.helper.number("cores", _cores);
return calculateMoneyGainRate(level, ram, cores, mult); const mult = ctx.helper.number("mult", _mult);
}, checkFormulasAccess(ctx);
levelUpgradeCost: function (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number { return calculateMoneyGainRate(level, ram, cores, mult);
const startingLevel = helper.number("levelUpgradeCost", "startingLevel", _startingLevel); },
const extraLevels = helper.number("levelUpgradeCost", "extraLevels", _extraLevels); levelUpgradeCost:
const costMult = helper.number("levelUpgradeCost", "costMult", _costMult); (ctx: NetscriptContext) =>
checkFormulasAccess("hacknetNodes.levelUpgradeCost"); (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
return calculateLevelUpgradeCost(startingLevel, extraLevels, costMult); const startingLevel = ctx.helper.number("startingLevel", _startingLevel);
}, const extraLevels = ctx.helper.number("extraLevels", _extraLevels);
ramUpgradeCost: function (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number { const costMult = ctx.helper.number("costMult", _costMult);
const startingRam = helper.number("ramUpgradeCost", "startingRam", _startingRam); checkFormulasAccess(ctx);
const extraLevels = helper.number("ramUpgradeCost", "extraLevels", _extraLevels); return calculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
const costMult = helper.number("ramUpgradeCost", "costMult", _costMult); },
checkFormulasAccess("hacknetNodes.ramUpgradeCost"); ramUpgradeCost:
return calculateRamUpgradeCost(startingRam, extraLevels, costMult); (ctx: NetscriptContext) =>
}, (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
coreUpgradeCost: function (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number { const startingRam = ctx.helper.number("startingRam", _startingRam);
const startingCore = helper.number("coreUpgradeCost", "startingCore", _startingCore); const extraLevels = ctx.helper.number("extraLevels", _extraLevels);
const extraCores = helper.number("coreUpgradeCost", "extraCores", _extraCores); const costMult = ctx.helper.number("costMult", _costMult);
const costMult = helper.number("coreUpgradeCost", "costMult", _costMult); checkFormulasAccess(ctx);
checkFormulasAccess("hacknetNodes.coreUpgradeCost"); return calculateRamUpgradeCost(startingRam, extraLevels, costMult);
return calculateCoreUpgradeCost(startingCore, extraCores, costMult); },
}, coreUpgradeCost:
hacknetNodeCost: function (_n: unknown, _mult: unknown): number { (ctx: NetscriptContext) =>
const n = helper.number("hacknetNodeCost", "n", _n); (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number => {
const mult = helper.number("hacknetNodeCost", "mult", _mult); const startingCore = ctx.helper.number("startingCore", _startingCore);
checkFormulasAccess("hacknetNodes.hacknetNodeCost"); const extraCores = ctx.helper.number("extraCores", _extraCores);
return calculateNodeCost(n, mult); const costMult = ctx.helper.number("costMult", _costMult);
}, checkFormulasAccess(ctx);
constants: function (): any { return calculateCoreUpgradeCost(startingCore, extraCores, costMult);
checkFormulasAccess("hacknetNodes.constants"); },
hacknetNodeCost:
(ctx: NetscriptContext) =>
(_n: unknown, _mult: unknown): number => {
const n = ctx.helper.number("n", _n);
const mult = ctx.helper.number("mult", _mult);
checkFormulasAccess(ctx);
return calculateNodeCost(n, mult);
},
constants: (ctx: NetscriptContext) => (): any => {
checkFormulasAccess(ctx);
return Object.assign({}, HacknetNodeConstants); return Object.assign({}, HacknetNodeConstants);
}, },
}, },
hacknetServers: { hacknetServers: {
hashGainRate: function ( hashGainRate:
_level: unknown, (ctx: NetscriptContext) =>
_ramUsed: unknown, (_level: unknown, _ramUsed: unknown, _maxRam: unknown, _cores: unknown, _mult: unknown = 1): number => {
_maxRam: unknown, const level = ctx.helper.number("level", _level);
_cores: unknown, const ramUsed = ctx.helper.number("ramUsed", _ramUsed);
_mult: unknown = 1, const maxRam = ctx.helper.number("maxRam", _maxRam);
): number { const cores = ctx.helper.number("cores", _cores);
const level = helper.number("hashGainRate", "level", _level); const mult = ctx.helper.number("mult", _mult);
const ramUsed = helper.number("hashGainRate", "ramUsed", _ramUsed); checkFormulasAccess(ctx);
const maxRam = helper.number("hashGainRate", "maxRam", _maxRam); return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult);
const cores = helper.number("hashGainRate", "cores", _cores); },
const mult = helper.number("hashGainRate", "mult", _mult); levelUpgradeCost:
checkFormulasAccess("hacknetServers.hashGainRate"); (ctx: NetscriptContext) =>
return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult); (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
}, const startingLevel = ctx.helper.number("startingLevel", _startingLevel);
levelUpgradeCost: function (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number { const extraLevels = ctx.helper.number("extraLevels", _extraLevels);
const startingLevel = helper.number("levelUpgradeCost", "startingLevel", _startingLevel); const costMult = ctx.helper.number("costMult", _costMult);
const extraLevels = helper.number("levelUpgradeCost", "extraLevels", _extraLevels); checkFormulasAccess(ctx);
const costMult = helper.number("levelUpgradeCost", "costMult", _costMult); return HScalculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
checkFormulasAccess("hacknetServers.levelUpgradeCost"); },
return HScalculateLevelUpgradeCost(startingLevel, extraLevels, costMult); ramUpgradeCost:
}, (ctx: NetscriptContext) =>
ramUpgradeCost: function (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number { (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
const startingRam = helper.number("ramUpgradeCost", "startingRam", _startingRam); const startingRam = ctx.helper.number("startingRam", _startingRam);
const extraLevels = helper.number("ramUpgradeCost", "extraLevels", _extraLevels); const extraLevels = ctx.helper.number("extraLevels", _extraLevels);
const costMult = helper.number("ramUpgradeCost", "costMult", _costMult); const costMult = ctx.helper.number("costMult", _costMult);
checkFormulasAccess("hacknetServers.ramUpgradeCost"); checkFormulasAccess(ctx);
return HScalculateRamUpgradeCost(startingRam, extraLevels, costMult); return HScalculateRamUpgradeCost(startingRam, extraLevels, costMult);
}, },
coreUpgradeCost: function (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number { coreUpgradeCost:
const startingCore = helper.number("coreUpgradeCost", "startingCore", _startingCore); (ctx: NetscriptContext) =>
const extraCores = helper.number("coreUpgradeCost", "extraCores", _extraCores); (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number => {
const costMult = helper.number("coreUpgradeCost", "costMult", _costMult); const startingCore = ctx.helper.number("startingCore", _startingCore);
checkFormulasAccess("hacknetServers.coreUpgradeCost"); const extraCores = ctx.helper.number("extraCores", _extraCores);
return HScalculateCoreUpgradeCost(startingCore, extraCores, costMult); const costMult = ctx.helper.number("costMult", _costMult);
}, checkFormulasAccess(ctx);
cacheUpgradeCost: function (_startingCache: unknown, _extraCache: unknown = 1): number { return HScalculateCoreUpgradeCost(startingCore, extraCores, costMult);
const startingCache = helper.number("cacheUpgradeCost", "startingCache", _startingCache); },
const extraCache = helper.number("cacheUpgradeCost", "extraCache", _extraCache); cacheUpgradeCost:
checkFormulasAccess("hacknetServers.cacheUpgradeCost"); (ctx: NetscriptContext) =>
return HScalculateCacheUpgradeCost(startingCache, extraCache); (_startingCache: unknown, _extraCache: unknown = 1): number => {
}, const startingCache = ctx.helper.number("startingCache", _startingCache);
hashUpgradeCost: function (_upgName: unknown, _level: unknown): number { const extraCache = ctx.helper.number("extraCache", _extraCache);
const upgName = helper.string("hashUpgradeCost", "upgName", _upgName); checkFormulasAccess(ctx);
const level = helper.number("hashUpgradeCost", "level", _level); return HScalculateCacheUpgradeCost(startingCache, extraCache);
checkFormulasAccess("hacknetServers.hashUpgradeCost"); },
const upg = player.hashManager.getUpgrade(upgName); hashUpgradeCost:
if (!upg) { (ctx: NetscriptContext) =>
throw helper.makeRuntimeErrorMsg( (_upgName: unknown, _level: unknown): number => {
"formulas.hacknetServers.calculateHashUpgradeCost", const upgName = helper.string("hashUpgradeCost", "upgName", _upgName);
`Invalid Hash Upgrade: ${upgName}`, const level = ctx.helper.number("level", _level);
); checkFormulasAccess(ctx);
} const upg = player.hashManager.getUpgrade(upgName);
return upg.getCost(level); if (!upg) {
}, throw helper.makeRuntimeErrorMsg(
hacknetServerCost: function (_n: unknown, _mult: unknown = 1): number { "formulas.hacknetServers.calculateHashUpgradeCost",
const n = helper.number("hacknetServerCost", "n", _n); `Invalid Hash Upgrade: ${upgName}`,
const mult = helper.number("hacknetServerCost", "mult", _mult); );
checkFormulasAccess("hacknetServers.hacknetServerCost"); }
return HScalculateServerCost(n, mult); return upg.getCost(level);
}, },
constants: function (): any { hacknetServerCost:
checkFormulasAccess("hacknetServers.constants"); (ctx: NetscriptContext) =>
(_n: unknown, _mult: unknown = 1): number => {
const n = ctx.helper.number("n", _n);
const mult = ctx.helper.number("mult", _mult);
checkFormulasAccess(ctx);
return HScalculateServerCost(n, mult);
},
constants: (ctx: NetscriptContext) => (): any => {
checkFormulasAccess(ctx);
return Object.assign({}, HacknetServerConstants); return Object.assign({}, HacknetServerConstants);
}, },
}, },
gang: { gang: {
wantedPenalty(gang: any): number { wantedPenalty:
checkFormulasAccess("gang.wantedPenalty"); (ctx: NetscriptContext) =>
return calculateWantedPenalty(gang); (gang: any): number => {
}, checkFormulasAccess(ctx);
respectGain: function (gang: any, member: any, task: any): number { return calculateWantedPenalty(gang);
checkFormulasAccess("gang.respectGain"); },
return calculateRespectGain(gang, member, task); respectGain:
}, (ctx: NetscriptContext) =>
wantedLevelGain: function (gang: any, member: any, task: any): number { (gang: any, member: any, task: any): number => {
checkFormulasAccess("gang.wantedLevelGain"); checkFormulasAccess(ctx);
return calculateWantedLevelGain(gang, member, task); return calculateRespectGain(gang, member, task);
}, },
moneyGain: function (gang: any, member: any, task: any): number { wantedLevelGain:
checkFormulasAccess("gang.moneyGain"); (ctx: NetscriptContext) =>
return calculateMoneyGain(gang, member, task); (gang: any, member: any, task: any): number => {
}, checkFormulasAccess(ctx);
ascensionPointsGain: function (_exp: unknown): number { return calculateWantedLevelGain(gang, member, task);
const exp = helper.number("ascensionPointsGain", "exp", _exp); },
checkFormulasAccess("gang.ascensionPointsGain"); moneyGain:
return calculateAscensionPointsGain(exp); (ctx: NetscriptContext) =>
}, (gang: any, member: any, task: any): number => {
ascensionMultiplier: function (_points: unknown): number { checkFormulasAccess(ctx);
const points = helper.number("ascensionMultiplier", "points", _points); return calculateMoneyGain(gang, member, task);
checkFormulasAccess("gang.ascensionMultiplier"); },
return calculateAscensionMult(points); ascensionPointsGain:
}, (ctx: NetscriptContext) =>
(_exp: unknown): number => {
const exp = ctx.helper.number("exp", _exp);
checkFormulasAccess(ctx);
return calculateAscensionPointsGain(exp);
},
ascensionMultiplier:
(ctx: NetscriptContext) =>
(_points: unknown): number => {
const points = ctx.helper.number("points", _points);
checkFormulasAccess(ctx);
return calculateAscensionMult(points);
},
}, },
}; };
} }

@ -1,4 +1,6 @@
import { CityName } from "src/Locations/data/CityNames"; import { CityName } from "src/Locations/data/CityNames";
import { NetscriptContext } from "src/Netscript/APIWrapper";
import { IPort } from "src/NetscriptPort";
import { BaseServer } from "../Server/BaseServer"; import { BaseServer } from "../Server/BaseServer";
export interface INetscriptHelper { export interface INetscriptHelper {
@ -8,7 +10,8 @@ export interface INetscriptHelper {
number(funcName: string, argName: string, v: unknown): number; number(funcName: string, argName: string, v: unknown): number;
city(funcName: string, argName: string, v: unknown): CityName; city(funcName: string, argName: string, v: unknown): CityName;
boolean(v: unknown): boolean; boolean(v: unknown): boolean;
getServer(ip: any, fn: any): BaseServer; getServer(ip: any, ctx: NetscriptContext): BaseServer;
checkSingularityAccess(func: string): void; checkSingularityAccess(func: string): void;
hack(hostname: string, manual: boolean): Promise<number>; hack(ctx: NetscriptContext, hostname: string, manual: boolean): Promise<number>;
getValidPort(funcName: string, port: number): IPort;
} }

@ -606,7 +606,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
_ctx.log(() => "cannot backdoor this kind of server"); _ctx.log(() => "cannot backdoor this kind of server");
return Promise.resolve(); return Promise.resolve();
} }
const server = baseserver as Server; const server = baseserver ;
const installTime = (calculateHackingTime(server, player) / 4) * 1000; const installTime = (calculateHackingTime(server, player) / 4) * 1000;
// No root access or skill level too low // No root access or skill level too low

@ -693,7 +693,7 @@ export function Root(props: IProps): React.ReactElement {
if (server === null) throw new Error(`Server '${closingScript.hostname}' should not be null, but it is.`); if (server === null) throw new Error(`Server '${closingScript.hostname}' should not be null, but it is.`);
const serverScriptIndex = server.scripts.findIndex((script) => script.filename === closingScript.fileName); const serverScriptIndex = server.scripts.findIndex((script) => script.filename === closingScript.fileName);
if (serverScriptIndex === -1 || savedScriptCode !== server.scripts[serverScriptIndex as number].code) { if (serverScriptIndex === -1 || savedScriptCode !== server.scripts[serverScriptIndex ].code) {
PromptEvent.emit({ PromptEvent.emit({
txt: `Do you want to save changes to ${closingScript.fileName} on ${closingScript.hostname}?`, txt: `Do you want to save changes to ${closingScript.fileName} on ${closingScript.hostname}?`,
resolve: (result: boolean | string) => { resolve: (result: boolean | string) => {

@ -36,7 +36,7 @@ function toNumber(n: number | IMinMaxRange): number {
return n; return n;
} }
case "object": { case "object": {
const range = n as IMinMaxRange; const range = n ;
value = getRandomInt(range.min, range.max); value = getRandomInt(range.min, range.max);
break; break;
} }

@ -68,7 +68,7 @@ export function placeOrder(
// Process to see if it should be executed immediately // Process to see if it should be executed immediately
const processOrderRefs = { const processOrderRefs = {
stockMarket: StockMarket as IStockMarket, stockMarket: StockMarket ,
symbolToStockMap: SymbolToStockMap, symbolToStockMap: SymbolToStockMap,
}; };
processOrders(stock, order.type, order.pos, processOrderRefs); processOrders(stock, order.type, order.pos, processOrderRefs);

@ -3,8 +3,6 @@ import { IRouter } from "../../ui/Router";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer"; import { BaseServer } from "../../Server/BaseServer";
import { listAllDarkwebItems, buyAllDarkwebItems, buyDarkwebItem } from "../../DarkWeb/DarkWeb"; import { listAllDarkwebItems, buyAllDarkwebItems, buyDarkwebItem } from "../../DarkWeb/DarkWeb";
import { SpecialServers } from "../../Server/data/SpecialServers";
import { GetServer } from "../../Server/AllServers";
export function buy( export function buy(
terminal: ITerminal, terminal: ITerminal,
@ -13,7 +11,7 @@ export function buy(
server: BaseServer, server: BaseServer,
args: (string | number | boolean)[], args: (string | number | boolean)[],
): void { ): void {
if (!GetServer(SpecialServers.DarkWeb)) { if (!player.hasTorRouter()) {
terminal.error( terminal.error(
"You need to be able to connect to the Dark Web to use the buy command. (Maybe there's a TOR router you can buy somewhere)", "You need to be able to connect to the Dark Web to use the buy command. (Maybe there's a TOR router you can buy somewhere)",
); );

@ -84,7 +84,7 @@ export function mv(
script.filename = destPath; script.filename = destPath;
} else if (srcFile instanceof TextFile) { } else if (srcFile instanceof TextFile) {
const textFile = srcFile as TextFile; const textFile = srcFile ;
if (!dest.endsWith(".txt")) { if (!dest.endsWith(".txt")) {
terminal.error(`Source and destination files must have the same type`); terminal.error(`Source and destination files must have the same type`);
return; return;

@ -70,7 +70,6 @@ export async function determineAllPossibilitiesForTabCompletion(
let parentDirPath = ""; let parentDirPath = "";
let evaledParentDirPath: string | null = null; let evaledParentDirPath: string | null = null;
// Helper functions // Helper functions
function addAllCodingContracts(): void { function addAllCodingContracts(): void {
for (const cct of currServ.contracts) { for (const cct of currServ.contracts) {
@ -199,7 +198,8 @@ export async function determineAllPossibilitiesForTabCompletion(
if (evaledParentDirPath === "/") { if (evaledParentDirPath === "/") {
evaledParentDirPath = null; evaledParentDirPath = null;
} else if (evaledParentDirPath == null) { } else if (evaledParentDirPath == null) {
return allPos; // Invalid path // do nothing for some reason tests dont like this?
// return allPos; // Invalid path
} else { } else {
evaledParentDirPath += "/"; evaledParentDirPath += "/";
} }
@ -240,7 +240,6 @@ export async function determineAllPossibilitiesForTabCompletion(
if (isCommand("connect")) { if (isCommand("connect")) {
// All directly connected and backdoored servers are reachable // All directly connected and backdoored servers are reachable
console.log(GetAllServers());
return GetAllServers() return GetAllServers()
.filter( .filter(
(server) => (server) =>

@ -121,7 +121,7 @@ export function getTextFile(fn: string, server: BaseServer): TextFile | null {
filename = removeLeadingSlash(filename); filename = removeLeadingSlash(filename);
} }
for (const file of server.textFiles as TextFile[]) { for (const file of server.textFiles ) {
if (file.fn === filename) { if (file.fn === filename) {
return file; return file;
} }

@ -34,11 +34,13 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
Settings.AutosaveInterval = 0; Settings.AutosaveInterval = 0;
useEffect(() => { useEffect(() => {
load().then((content) => { load()
const epochTime = Math.round(Date.now() / 1000); .then((content) => {
const filename = `RECOVERY_BITBURNER_${epochTime}.json`; const epochTime = Math.round(Date.now() / 1000);
download(filename, content); const filename = `RECOVERY_BITBURNER_${epochTime}.json`;
}); download(filename, content);
})
.catch((err) => console.error(err));
}, []); }, []);
return ( return (

@ -5,6 +5,7 @@ import { Typography, TableCell, TableRow } from "@mui/material";
import { numeralWrapper } from "../numeralFormat"; import { numeralWrapper } from "../numeralFormat";
import { formatNumber } from "../../utils/StringHelperFunctions"; import { formatNumber } from "../../utils/StringHelperFunctions";
import { characterOverviewStyles as useStyles } from "./CharacterOverview"; import { characterOverviewStyles as useStyles } from "./CharacterOverview";
import { ClassNameMap } from "@material-ui/core/styles/withStyles";
interface ITableRowData { interface ITableRowData {
content?: string; content?: string;
@ -15,7 +16,7 @@ interface ITableRowData {
interface IProps { interface IProps {
name: string; name: string;
color: string; color: string;
classes?: any; classes?: ClassNameMap;
data?: ITableRowData; data?: ITableRowData;
children?: React.ReactElement; children?: React.ReactElement;
} }

@ -80,7 +80,7 @@ export function comprLZEncode(plain: string): string {
for (let offset = 1; offset <= Math.min(9, i); ++offset) { for (let offset = 1; offset <= Math.min(9, i); ++offset) {
if (plain[i - offset] === c) { if (plain[i - offset] === c) {
// start new backreference // start new backreference
set(new_state, offset, 1, string + length + plain.substring(i - length, i)); set(new_state, offset, 1, string + String(length) + plain.substring(i - length, i));
} }
} }
} }
@ -99,17 +99,17 @@ export function comprLZEncode(plain: string): string {
set(new_state, offset, length + 1, string); set(new_state, offset, length + 1, string);
} else { } else {
// start new backreference // start new backreference
set(new_state, offset, 1, string + "9" + offset + "0"); set(new_state, offset, 1, string + "9" + String(offset) + "0");
} }
} }
// start new literal // start new literal
set(new_state, 0, 1, string + length + offset); set(new_state, 0, 1, string + String(length) + String(offset));
// end current backreference and start new backreference // end current backreference and start new backreference
for (let new_offset = 1; new_offset <= Math.min(9, i); ++new_offset) { for (let new_offset = 1; new_offset <= Math.min(9, i); ++new_offset) {
if (plain[i - new_offset] === c) { if (plain[i - new_offset] === c) {
set(new_state, new_offset, 1, string + length + offset + "0"); set(new_state, new_offset, 1, string + String(length) + String(offset) + "0");
} }
} }
} }
@ -128,7 +128,7 @@ export function comprLZEncode(plain: string): string {
continue; continue;
} }
string += len + plain.substring(plain.length - len, plain.length); string += String(len) + plain.substring(plain.length - len, plain.length);
if (result == null || string.length < result.length) { if (result == null || string.length < result.length) {
result = string; result = string;
} else if (string.length == result.length && Math.random() < 0.5) { } else if (string.length == result.length && Math.random() < 0.5) {
@ -143,7 +143,7 @@ export function comprLZEncode(plain: string): string {
continue; continue;
} }
string += len + "" + offset; string += String(len) + "" + String(offset);
if (result == null || string.length < result.length) { if (result == null || string.length < result.length) {
result = string; result = string;
} else if (string.length == result.length && Math.random() < 0.5) { } else if (string.length == result.length && Math.random() < 0.5) {

@ -87,7 +87,7 @@ export function getErrorForDisplay(error: Error, errorInfo?: React.ErrorInfo, pa
const fileName = (metadata.error as any).fileName; const fileName = (metadata.error as any).fileName;
const features = const features =
`lang=${metadata.features.language} cookiesEnabled=${metadata.features.cookiesEnabled.toString()}` + `lang=${metadata.features.language} cookiesEnabled=${metadata.features.cookiesEnabled.toString()}` +
` doNotTrack=${metadata.features.doNotTrack} indexedDb=${metadata.features.indexedDb.toString()}`; ` doNotTrack=${metadata.features.doNotTrack ?? "null"} indexedDb=${metadata.features.indexedDb.toString()}`;
const title = `${metadata.error.name}: ${metadata.error.message}${metadata.page && ` (at "${Page[metadata.page]}")`}`; const title = `${metadata.error.name}: ${metadata.error.message}${metadata.page && ` (at "${Page[metadata.page]}")`}`;
const body = ` const body = `

@ -4,8 +4,5 @@ import { getRandomByte } from "./helpers/getRandomByte";
* Generate a random IP address * Generate a random IP address
* Does not check to see if the IP already exists in the game * Does not check to see if the IP already exists in the game
*/ */
export function createRandomIp(): string { export const createRandomIp = (): string =>
const ip: string = getRandomByte(99) + "." + getRandomByte(9) + "." + getRandomByte(9) + "." + getRandomByte(9); `${getRandomByte(99)}.${getRandomByte(9)}.${getRandomByte(9)}.${getRandomByte(9)}`;
return ip;
}

@ -2,7 +2,7 @@
import { validateObject } from "./Validator"; import { validateObject } from "./Validator";
interface IReviverValue { export interface IReviverValue {
ctor: string; ctor: string;
data: any; data: any;
} }

@ -2,7 +2,7 @@
* This is an object that is used to keep track of where all of the player's * This is an object that is used to keep track of where all of the player's
* money is coming from (or going to) * money is coming from (or going to)
*/ */
import { Generic_fromJSON, Generic_toJSON, Reviver } from "./JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver, IReviverValue } from "./JSONReviver";
export class MoneySourceTracker { export class MoneySourceTracker {
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
@ -56,7 +56,7 @@ export class MoneySourceTracker {
// Initiatizes a MoneySourceTracker object from a JSON save state. // Initiatizes a MoneySourceTracker object from a JSON save state.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): MoneySourceTracker { static fromJSON(value: IReviverValue): MoneySourceTracker {
return Generic_fromJSON(MoneySourceTracker, value.data); return Generic_fromJSON(MoneySourceTracker, value.data);
} }
} }

@ -5,11 +5,12 @@
* @param obj the object to clear all properties * @param obj the object to clear all properties
*/ */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function clearObject(obj: any): void { export function clearObject(obj: unknown): void {
for (const key in obj) { if (typeof obj !== "object" || obj === null || obj === undefined) return;
if (obj.hasOwnProperty(key)) { const o = obj as Record<string, unknown>;
// tslint:disable-next-line:no-dynamic-delete for (const key of Object.getOwnPropertyNames(o)) {
delete obj[key]; if (o.hasOwnProperty(key)) {
delete o[key];
} }
} }
} }

@ -9,18 +9,18 @@ export function compareArrays<T>(a1: T[], a2: T[]): boolean {
} }
for (let i = 0; i < a1.length; ++i) { for (let i = 0; i < a1.length; ++i) {
if (Array.isArray(a1[i])) { const v1 = a1[i];
const v2 = a2[i];
if (Array.isArray(v1)) {
// If the other element is not an array, then these cannot be equal // If the other element is not an array, then these cannot be equal
if (!Array.isArray(a2[i])) { if (!Array.isArray(v2)) {
return false; return false;
} }
const elem1 = a1[i] as any; if (!compareArrays(v1, v2)) {
const elem2 = a2[i] as any;
if (!compareArrays(elem1, elem2)) {
return false; return false;
} }
} else if (a1[i] !== a2[i] && !(Number.isNaN(a1[i]) && Number.isNaN(a2[i]))) { } else if (v1 !== v2 && !(Number.isNaN(v1) && Number.isNaN(v2))) {
// strict (in)equality considers NaN not equal to itself // strict (in)equality considers NaN not equal to itself
return false; return false;
} }

@ -7,15 +7,25 @@ interface IError {
export function exceptionAlert(e: IError | string): void { export function exceptionAlert(e: IError | string): void {
console.error(e); console.error(e);
let msg = "";
let file = "UNKNOWN FILE NAME";
let line = "UNKNOWN LINE NUMBER";
const isError = (e: IError | string): e is IError => e.hasOwnProperty("fileName");
if (isError(e)) {
file = e.fileName ?? file;
line = e.lineNumber?.toString() ?? line;
} else {
msg = e;
}
dialogBoxCreate( dialogBoxCreate(
"Caught an exception: " + "Caught an exception: " +
e + msg +
"<br><br>" + "<br><br>" +
"Filename: " + "Filename: " +
((e as any).fileName || "UNKNOWN FILE NAME") + file +
"<br><br>" + "<br><br>" +
"Line Number: " + "Line Number: " +
((e as any).lineNumber || "UNKNOWN LINE NUMBER") + line +
"<br><br>" + "<br><br>" +
"This is a bug, please report to game developer with this " + "This is a bug, please report to game developer with this " +
"message as well as details about how to reproduce the bug.<br><br>" + "message as well as details about how to reproduce the bug.<br><br>" +

@ -1,12 +1,10 @@
export function isArray(arr: unknown): arr is unknown[] {
return Array.isArray(arr);
}
// Checks whether an array is a 2D array. // Checks whether an array is a 2D array.
// For this, a 2D array is an array which contains only other arrays. // For this, a 2D array is an array which contains only other arrays.
// If one element in the array is a number or string, it is NOT a 2D array // If one element in the array is a number or string, it is NOT a 2D array
export function is2DArray(arr: any[]): boolean { export function is2DArray(arr: unknown): arr is unknown[][] {
if (arr.constructor !== Array) { return isArray(arr) && arr.every((u) => isArray(u));
return false;
}
return arr.every((e) => {
return e.constructor === Array;
});
} }

@ -13,6 +13,11 @@ const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost;
describe("Netscript Dynamic RAM Calculation/Generation Tests", function () { describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
// Creates a mock RunningScript object // Creates a mock RunningScript object
/**
*
* @param {string} code
* @returns
*/
async function createRunningScript(code) { async function createRunningScript(code) {
const script = new Script(); const script = new Script();
script.code = code; script.code = code;
@ -24,12 +29,23 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
} }
// Tests numeric equality, allowing for floating point imprecision // Tests numeric equality, allowing for floating point imprecision
/**
*
* @param {number} val
* @param {number} expected
*/
function testEquality(val, expected) { function testEquality(val, expected) {
expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON); expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON);
expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON); expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON);
} }
// Runs a Netscript function and properly catches it if it returns promise // Runs a Netscript function and properly catches it if it returns promise
/**
*
* @param {(...args: unknown[]) => unknown} fn
* @param {unknown[]} args
*/
function runPotentiallyAsyncFunction(fn, ...args) { function runPotentiallyAsyncFunction(fn, ...args) {
const res = fn(...args); const res = fn(...args);
if (res instanceof Promise) { if (res instanceof Promise) {
@ -93,7 +109,7 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
runPotentiallyAsyncFunction(curr, ...args); runPotentiallyAsyncFunction(curr, ...args);
} catch (e) {} } catch (e) {}
} else { } else {
throw new Error(`Invalid function specified: [${fnDesc}]`); throw new Error(`Invalid function specified: [${fnDesc.toString()}]`);
} }
const fnName = fnDesc[fnDesc.length - 1]; const fnName = fnDesc[fnDesc.length - 1];

@ -11,6 +11,11 @@ const HacknetNamespaceCost = RamCostConstants.ScriptHacknetNodesRamCost;
describe("Netscript Static RAM Calculation/Generation Tests", function () { describe("Netscript Static RAM Calculation/Generation Tests", function () {
// Tests numeric equality, allowing for floating point imprecision // Tests numeric equality, allowing for floating point imprecision
/**
*
* @param {number} val
* @param {number} expected
*/
function testEquality(val, expected) { function testEquality(val, expected) {
expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON); expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON);
expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON); expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON);
@ -25,9 +30,6 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
*/ */
async function expectNonZeroRamCost(fnDesc) { async function expectNonZeroRamCost(fnDesc) {
if (!Array.isArray(fnDesc)) {
expect.fail("Non-array passed to expectNonZeroRamCost()");
}
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(Player, ...fnDesc);
expect(expected).toBeGreaterThan(0); expect(expected).toBeGreaterThan(0);
@ -50,9 +52,6 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
*/ */
async function expectZeroRamCost(fnDesc) { async function expectZeroRamCost(fnDesc) {
if (!Array.isArray(fnDesc)) {
expect.fail("Non-array passed to expectZeroRamCost()");
}
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(Player, ...fnDesc);
expect(expected).toEqual(0); expect(expected).toEqual(0);
@ -64,7 +63,12 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
expect(multipleCallsCalculated).toEqual(ScriptBaseCost); expect(multipleCallsCalculated).toEqual(ScriptBaseCost);
} }
// simplyfied version from RamCostGenerator.ts /**
*
* @param {Player} player
* @param {number} cost
* @returns
*/
function SF4Cost(player, cost) { function SF4Cost(player, cost) {
if (player.bitNodeN === 4) return cost; if (player.bitNodeN === 4) return cost;
const sf4 = player.sourceFileLvl(4); const sf4 = player.sourceFileLvl(4);
@ -83,9 +87,6 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* @param {number} cost - expected cost * @param {number} cost - expected cost
*/ */
async function expectSpecificRamCost(fnDesc, cost) { async function expectSpecificRamCost(fnDesc, cost) {
if (!Array.isArray(fnDesc)) {
expect.fail("Non-array passed to expectZeroRamCost()");
}
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(Player, ...fnDesc);
expect(expected).toEqual(SF4Cost(Player, cost)); expect(expected).toEqual(SF4Cost(Player, cost));

@ -18,6 +18,11 @@ const CorpCost = 1024 - ScriptBaseCost;
describe("Parsing NetScript code to work out static RAM costs", function () { describe("Parsing NetScript code to work out static RAM costs", function () {
// Tests numeric equality, allowing for floating point imprecision - and includes script base cost // Tests numeric equality, allowing for floating point imprecision - and includes script base cost
/**
*
* @param {number} val
* @param {number} expected
*/
function expectCost(val, expected) { function expectCost(val, expected) {
const expectedWithBase = expected + ScriptBaseCost; const expectedWithBase = expected + ScriptBaseCost;
expect(val).toBeGreaterThanOrEqual(expectedWithBase - 100 * Number.EPSILON); expect(val).toBeGreaterThanOrEqual(expectedWithBase - 100 * Number.EPSILON);

@ -6,7 +6,6 @@ import { Company } from "../../src/Company/Company";
import { Server } from "../../src/Server/Server"; import { Server } from "../../src/Server/Server";
import { buyStock, sellStock, shortStock, sellShort } from "../../src/StockMarket/BuyingAndSelling"; import { buyStock, sellStock, shortStock, sellShort } from "../../src/StockMarket/BuyingAndSelling";
import { IStockMarket } from "../../src/StockMarket/IStockMarket";
import { Order } from "../../src/StockMarket/Order"; import { Order } from "../../src/StockMarket/Order";
import { import {
forecastForecastChangeFromCompanyWork, forecastForecastChangeFromCompanyWork,
@ -458,17 +457,13 @@ describe("Stock Market Tests", function () {
it("should trigger a price update when it has enough cycles", function () { it("should trigger a price update when it has enough cycles", function () {
// Get the initial prices // Get the initial prices
const initialValues: IMap<any> = {}; const initialValues: IMap<Stock> = {};
for (const stockName in StockMarket) { for (const stockName in StockMarket) {
const stock = StockMarket[stockName]; const stock = StockMarket[stockName];
if (!(stock instanceof Stock)) { if (!(stock instanceof Stock)) {
continue; continue;
} }
initialValues[stock.symbol] = { initialValues[stock.symbol] = stock;
b: stock.b,
otlkMag: stock.otlkMag,
price: stock.price,
};
} }
// Don't know or care how many exact cycles are required // Don't know or care how many exact cycles are required
@ -1149,7 +1144,7 @@ describe("Stock Market Tests", function () {
Player.setMoney(100e9); Player.setMoney(100e9);
processOrdersRefs = { processOrdersRefs = {
stockMarket: StockMarket as IStockMarket, stockMarket: StockMarket,
symbolToStockMap: SymbolToStockMap, symbolToStockMap: SymbolToStockMap,
}; };
}); });

@ -100,9 +100,11 @@ describe("Terminal Directory Tests", function () {
expect(isValidDirectoryName(".a1")).toEqual(true); expect(isValidDirectoryName(".a1")).toEqual(true);
expect(isValidDirectoryName("._foo")).toEqual(true); expect(isValidDirectoryName("._foo")).toEqual(true);
expect(isValidDirectoryName("_foo")).toEqual(true); expect(isValidDirectoryName("_foo")).toEqual(true);
expect(isValidDirectoryName("foo.dir")).toEqual(true); // the changes made to support this broke mv
expect(isValidDirectoryName("foov1.0.0.1")).toEqual(true); // see https://github.com/danielyxie/bitburner/pull/3653 if you try to re support
expect(isValidDirectoryName("foov1..0..0..1")).toEqual(true); // expect(isValidDirectoryName("foo.dir")).toEqual(true);
// expect(isValidDirectoryName("foov1.0.0.1")).toEqual(true);
// expect(isValidDirectoryName("foov1..0..0..1")).toEqual(true);
expect(isValidDirectoryName("foov1-0-0-1")).toEqual(true); expect(isValidDirectoryName("foov1-0-0-1")).toEqual(true);
expect(isValidDirectoryName("foov1-0-0-1-")).toEqual(true); expect(isValidDirectoryName("foov1-0-0-1-")).toEqual(true);
expect(isValidDirectoryName("foov1--0--0--1--")).toEqual(true); expect(isValidDirectoryName("foov1--0--0--1--")).toEqual(true);

4
tools/tsconfig.json Normal file

@ -0,0 +1,4 @@
{
"extends": "../tsconfig.json",
"include": ["**/*.js"]
}