Merge branch 'dev' of github.com:danielyxie/bitburner into dev

This commit is contained in:
Olivier Gagnon 2022-08-15 09:41:46 -04:00
commit 07538d6509
35 changed files with 3682 additions and 3602 deletions

@ -26,6 +26,10 @@ export const CorporationConstants: {
BaseMaxProducts: number; BaseMaxProducts: number;
AllCorporationStates: string[]; AllCorporationStates: string[];
AllMaterials: string[]; AllMaterials: string[];
AllIndustryTypes: string[];
AllUnlocks: string[];
AllUpgrades: string[];
AllResearch: string[];
FundingRoundShares: number[]; FundingRoundShares: number[];
FundingRoundMultiplier: number[]; FundingRoundMultiplier: number[];
AvgProfitLength: number; AvgProfitLength: number;
@ -82,6 +86,70 @@ export const CorporationConstants: {
"AI Cores", "AI Cores",
"Real Estate", "Real Estate",
], ],
AllIndustryTypes: [
"Energy",
"Utilities",
"Agriculture",
"Fishing",
"Mining",
"Food",
"Tobacco",
"Chemical",
"Pharmaceutical",
"Hardware",
"Robotics",
"Software",
"Healthcare",
"RealEstate",
],
AllUnlocks: [
"Export",
"Smart Supply",
"Market Research - Demand",
"Market Data - Competition",
"VeChain",
"Shady Accounting",
"Government Partnership",
"Warehouse API",
"Office API",
],
AllUpgrades: [
"Smart Factories",
"Smart Storage",
"DreamSense",
"Wilson Analytics",
"Nuoptimal Nootropic Injector Implants",
"Speech Processor Implants",
"Neural Accelerators",
"FocusWires",
"ABC SalesBots",
"Project Insight",
],
AllResearch: [
"Hi-Tech R&D Laboratory",
"AutoBrew",
"AutoPartyManager",
"Automatic Drug Administration",
"Bulk Purchasing",
"CPH4 Injections",
"Drones",
"Drones - Assembly",
"Drones - Transport",
"Go-Juice",
"HRBuddy-Recruitment",
"HRBuddy-Training",
"JoyWire",
"Market-TA.I",
"Market-TA.II",
"Overclock",
"Self-Correcting Assemblers",
"Sti.mu",
"sudo.Assist",
"uPgrade: Capacity.I",
"uPgrade: Capacity.II",
"uPgrade: Dashboard",
"uPgrade: Fulcrum",
],
FundingRoundShares: [0.1, 0.35, 0.25, 0.2], FundingRoundShares: [0.1, 0.35, 0.25, 0.2],
FundingRoundMultiplier: [4, 3, 3, 2.5], FundingRoundMultiplier: [4, 3, 3, 2.5],

@ -459,7 +459,7 @@ export function IndustryOffice(props: IProps): React.ReactElement {
{!division.hasResearch("AutoBrew") && ( {!division.hasResearch("AutoBrew") && (
<> <>
<Tooltip <Tooltip
title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>} title={<Typography>Provide your employees with coffee, increasing their energy by 5%</Typography>}
> >
<span> <span>
<Button <Button

@ -151,7 +151,7 @@ const positive = [
"patient", "patient",
"dynamic", "dynamic",
"loyal", "loyal",
"based", "straightforward",
]; ];
const negative = [ const negative = [

@ -1,22 +1,15 @@
import { getRamCost } from "./RamCostGenerator"; import { getRamCost } from "./RamCostGenerator";
import type { IPort } from "../NetscriptPort";
import type { BaseServer } from "../Server/BaseServer";
import type { WorkerScript } from "./WorkerScript"; import type { WorkerScript } from "./WorkerScript";
import { makeRuntimeRejectMsg } from "../NetscriptEvaluator";
import { Player } from "../Player"; import { Player } from "../Player";
import { CityName } from "../Locations/data/CityNames"; import { helpers } from "./NetscriptHelpers";
import { BasicHGWOptions } from "../ScriptEditor/NetscriptDefinitions";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Server } from "../Server/Server";
import { FormulaGang } from "../Gang/formulas/formulas";
import { INetscriptHelper, ScriptIdentifier } from "../NetscriptFunctions/INetscriptHelper";
import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask";
import { ScriptArg } from "./ScriptArg"; import { ScriptArg } from "./ScriptArg";
import { NSEnums } from "src/ScriptEditor/NetscriptDefinitions";
import { NSFull } from "src/NetscriptFunctions";
type ExternalFunction = (...args: unknown[]) => unknown; type ExternalFunction = (...args: unknown[]) => unknown;
export type ExternalAPI = {
[string: string]: ExternalAPI | ExternalFunction; export type ExternalAPILayer = {
[key: string]: ExternalAPILayer | ExternalFunction | ScriptArg[];
}; };
type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: NetscriptContext) => F; type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: NetscriptContext) => F;
@ -24,48 +17,23 @@ type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: Netscri
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 NSEnums
? NSEnums
: API[Property] extends ScriptArg[]
? ScriptArg[]
: API[Property] extends object : API[Property] extends object
? InternalAPI<API[Property]> ? InternalAPI<API[Property]>
: never; : never;
}; };
type WrappedNetscriptFunction = (...args: unknown[]) => unknown;
type WrappedNetscriptAPI = {
readonly [string: string]: WrappedNetscriptAPI | WrappedNetscriptFunction;
};
export type NetscriptContext = { export type NetscriptContext = {
makeRuntimeErrorMsg: (message: string) => string;
log: (message: () => string) => void;
workerScript: WorkerScript; workerScript: WorkerScript;
function: string; function: string;
helper: WrappedNetscriptHelpers; functionPath: string;
};
type WrappedNetscriptHelpers = {
makeRuntimeErrorMsg: (msg: string) => string;
string: (argName: string, v: unknown) => string;
number: (argName: string, v: unknown) => number;
ustring: (argName: string, v: unknown) => string | undefined;
unumber: (argName: string, v: unknown) => number | undefined;
scriptArgs(args: unknown): ScriptArg[];
scriptIdentifier: (fn: unknown, hostname: unknown, args: unknown) => ScriptIdentifier;
city: (argName: string, v: unknown) => CityName;
boolean: (v: unknown) => boolean;
getServer: (hostname: string) => BaseServer;
checkSingularityAccess: () => void;
hack: (hostname: string, manual: boolean, { threads: requestedThreads, stock }?: BasicHGWOptions) => Promise<number>;
getValidPort: (port: number) => IPort;
player(p: unknown): IPlayer;
server(s: unknown): Server;
gang(g: unknown): FormulaGang;
gangMember: (m: unknown) => GangMember;
gangTask: (t: unknown) => GangMemberTask;
}; };
function wrapFunction( function wrapFunction(
helpers: INetscriptHelper, wrappedAPI: ExternalAPILayer,
wrappedAPI: ExternalAPI,
workerScript: WorkerScript, workerScript: WorkerScript,
func: (_ctx: NetscriptContext) => (...args: unknown[]) => unknown, func: (_ctx: NetscriptContext) => (...args: unknown[]) => unknown,
...tree: string[] ...tree: string[]
@ -73,44 +41,19 @@ function wrapFunction(
const functionPath = tree.join("."); const functionPath = tree.join(".");
const functionName = tree.pop(); const functionName = tree.pop();
if (typeof functionName !== "string") { if (typeof functionName !== "string") {
throw makeRuntimeRejectMsg(workerScript, "Failure occured while wrapping netscript api"); throw helpers.makeRuntimeRejectMsg(workerScript, "Failure occured while wrapping netscript api");
} }
const ctx = { const ctx = {
makeRuntimeErrorMsg: (message: string) => {
return helpers.makeRuntimeErrorMsg(functionPath, message);
},
log: (message: () => string) => {
workerScript.log(functionPath, message);
},
workerScript, workerScript,
function: functionName, function: functionName,
helper: { functionPath,
makeRuntimeErrorMsg: (msg: string) => helpers.makeRuntimeErrorMsg(functionPath, msg),
string: (argName: string, v: unknown) => helpers.string(functionPath, argName, v),
number: (argName: string, v: unknown) => helpers.number(functionPath, argName, v),
ustring: (argName: string, v: unknown) => helpers.ustring(functionPath, argName, v),
unumber: (argName: string, v: unknown) => helpers.unumber(functionPath, argName, v),
scriptArgs: (v: unknown) => helpers.scriptArgs(functionPath, v),
scriptIdentifier: (fn: unknown, hostname: unknown, args: unknown) =>
helpers.scriptIdentifier(functionPath, fn, hostname, args),
city: (argName: string, v: unknown) => helpers.city(functionPath, argName, v),
boolean: helpers.boolean,
getServer: (hostname: string) => helpers.getServer(hostname, ctx),
checkSingularityAccess: () => helpers.checkSingularityAccess(functionName),
hack: (hostname: string, manual: boolean, extra?: BasicHGWOptions) => helpers.hack(ctx, hostname, manual, extra),
getValidPort: (port: number) => helpers.getValidPort(functionPath, port),
player: (p: unknown) => helpers.player(functionPath, p),
server: (s: unknown) => helpers.server(functionPath, s),
gang: (g: unknown) => helpers.gang(functionPath, g),
gangMember: (m: unknown) => helpers.gangMember(functionPath, m),
gangTask: (t: unknown) => helpers.gangTask(functionPath, t),
},
}; };
function wrappedFunction(...args: unknown[]): unknown { function wrappedFunction(...args: unknown[]): unknown {
helpers.updateDynamicRam(ctx.function, getRamCost(Player, ...tree, ctx.function)); helpers.checkEnvFlags(ctx);
helpers.updateDynamicRam(ctx, getRamCost(Player, ...tree, ctx.function));
return func(ctx)(...args); return func(ctx)(...args);
} }
const parent = getNestedProperty(wrappedAPI, ...tree); const parent = getNestedProperty(wrappedAPI, tree);
Object.defineProperty(parent, functionName, { Object.defineProperty(parent, functionName, {
value: wrappedFunction, value: wrappedFunction,
writable: true, writable: true,
@ -118,20 +61,25 @@ function wrapFunction(
}); });
} }
export function wrapAPI( export function wrapAPI(workerScript: WorkerScript, namespace: object, args: ScriptArg[]): NSFull {
helpers: INetscriptHelper, const wrappedAPI = wrapAPILayer({}, workerScript, namespace);
wrappedAPI: ExternalAPI, wrappedAPI.args = args;
return wrappedAPI as unknown as NSFull;
}
export function wrapAPILayer(
wrappedAPI: ExternalAPILayer,
workerScript: WorkerScript, workerScript: WorkerScript,
namespace: object, namespace: object,
...tree: string[] ...tree: string[]
): WrappedNetscriptAPI { ) {
for (const [key, value] of Object.entries(namespace)) { for (const [key, value] of Object.entries(namespace)) {
if (typeof value === "function") { if (typeof value === "function") {
wrapFunction(helpers, wrappedAPI, workerScript, value, ...tree, key); wrapFunction(wrappedAPI, workerScript, value, ...tree, key);
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
setNestedProperty(wrappedAPI, value, key); setNestedProperty(wrappedAPI, value.slice(), key);
} else if (typeof value === "object") { } else if (typeof value === "object") {
wrapAPI(helpers, wrappedAPI, workerScript, value, ...tree, key); wrapAPILayer(wrappedAPI, workerScript, value, ...tree, key);
} else { } else {
setNestedProperty(wrappedAPI, value, ...tree, key); setNestedProperty(wrappedAPI, value, ...tree, key);
} }
@ -139,28 +87,21 @@ export function wrapAPI(
return wrappedAPI; return wrappedAPI;
} }
// TODO: This doesn't even work properly. function setNestedProperty(root: any, value: unknown, ...tree: string[]): void {
function setNestedProperty(root: object, value: unknown, ...tree: string[]): void {
let target = root; let target = root;
const key = tree.pop(); const key = tree.pop();
if (!key) { if (!key) throw new Error("Failure occured while wrapping netscript api (setNestedProperty)");
throw new Error("Failure occured while wrapping netscript api (setNestedProperty)"); for (const branch of tree) {
target[branch] ??= {};
target = target[branch];
} }
for (let branch of Object.values(target)) { target[key] = value;
if (branch === undefined) {
branch = {};
}
target = branch;
}
Object.assign(target, { [key]: value });
} }
function getNestedProperty(root: any, ...tree: string[]): unknown { function getNestedProperty(root: any, tree: string[]): unknown {
let target = root; let target = root;
for (const branch of tree) { for (const branch of tree) {
if (target[branch] === undefined) { target[branch] ??= {};
target[branch] = {};
}
target = target[branch]; target = target[branch];
} }
return target; return target;

@ -10,6 +10,12 @@ export class Environment {
*/ */
stopFlag = false; stopFlag = false;
/**
* The currently running function
*/
runningFn = "";
/** /**
* Environment variables (currently only Netscript functions) * Environment variables (currently only Netscript functions)
*/ */

@ -0,0 +1,665 @@
import { NetscriptContext } from "./APIWrapper";
import { WorkerScript } from "./WorkerScript";
import { GetAllServers, GetServer } from "../Server/AllServers";
import { Player } from "../Player";
import { ScriptDeath } from "./ScriptDeath";
import { isString } from "../utils/helpers/isString";
import { numeralWrapper } from "../ui/numeralFormat";
import { ScriptArg } from "./ScriptArg";
import { CityName } from "../Locations/data/CityNames";
import { BasicHGWOptions } from "src/ScriptEditor/NetscriptDefinitions";
import { Server } from "../Server/Server";
import {
calculateHackingChance,
calculateHackingExpGain,
calculateHackingTime,
calculatePercentMoneyHacked,
} from "../Hacking";
import { netscriptCanHack } from "../Hacking/netscriptCanHack";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing";
import { IPort } from "../NetscriptPort";
import { NetscriptPorts } from "../NetscriptWorker";
import { IPlayer } from "../PersonObjects/IPlayer";
import { FormulaGang } from "../Gang/formulas/formulas";
import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask";
import { RunningScript } from "../Script/RunningScript";
import { toNative } from "../NetscriptFunctions/toNative";
import { ScriptIdentifier } from "./ScriptIdentifier";
import { findRunningScript, findRunningScriptByPid } from "../Script/ScriptHelpers";
import { RunningScript as IRunningScript } from "../ScriptEditor/NetscriptDefinitions";
import { arrayToString } from "../utils/helpers/arrayToString";
import { HacknetServer } from "../Hacknet/HacknetServer";
import { BaseServer } from "../Server/BaseServer";
export const helpers = {
string,
number,
scriptArgs,
argsToString,
isScriptErrorMessage,
makeRuntimeRejectMsg,
makeRuntimeErrorMsg,
resolveNetscriptRequestedThreads,
checkEnvFlags,
checkSingularityAccess,
netscriptDelay,
updateDynamicRam,
city,
getServer,
scriptIdentifier,
hack,
getValidPort,
player,
server,
gang,
gangMember,
gangTask,
log,
getFunctionNames,
getRunningScript,
getRunningScriptByArgs,
getCannotFindRunningScriptErrorMessage,
createPublicRunningScript,
failOnHacknetServer,
};
/** Convert a provided value v for argument argName to string. If it wasn't originally a string or number, throw. */
function string(ctx: NetscriptContext, argName: string, v: unknown): string {
if (typeof v === "string") return v;
if (typeof v === "number") return v + ""; // cast to string;
throw makeRuntimeErrorMsg(ctx, `'${argName}' should be a string.`);
}
/** Convert provided value v for argument argName to number. Throw if could not convert to a non-NaN number. */
function number(ctx: NetscriptContext, argName: string, v: unknown): number {
if (typeof v === "string") {
const x = parseFloat(v);
if (!isNaN(x)) return x; // otherwise it wasn't even a string representing a number.
} else if (typeof v === "number") {
if (isNaN(v)) throw makeRuntimeErrorMsg(ctx, `'${argName}' is NaN.`);
return v;
}
throw makeRuntimeErrorMsg(ctx, `'${argName}' should be a number.`);
}
/** Returns args back if it is a ScriptArg[]. Throws an error if it is not. */
function scriptArgs(ctx: NetscriptContext, args: unknown) {
if (!isScriptArgs(args)) throw makeRuntimeErrorMsg(ctx, "'args' is not an array of script args");
return args;
}
/** Determines if the given msg string is an error created by makeRuntimeRejectMsg. */
function isScriptErrorMessage(msg: string): boolean {
if (!isString(msg)) {
return false;
}
const splitMsg = msg.split("|DELIMITER|");
return splitMsg.length == 4;
}
/** Convert multiple arguments for tprint or print into a single string. */
function argsToString(args: unknown[]): string {
let out = "";
for (let arg of args) {
if (arg === null) {
out += "null";
continue;
}
if (arg === undefined) {
out += "undefined";
continue;
}
arg = toNative(arg);
out += typeof arg === "object" ? JSON.stringify(arg) : `${arg}`;
}
return out;
}
/** Creates an error message string containing hostname, scriptname, and the error message msg */
function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string): string {
for (const scriptUrl of workerScript.scriptRef.dependencies) {
msg = msg.replace(new RegExp(scriptUrl.url, "g"), scriptUrl.filename);
}
return "|DELIMITER|" + workerScript.hostname + "|DELIMITER|" + workerScript.name + "|DELIMITER|" + msg;
}
/** Creates an error message string with a stack trace. */
function makeRuntimeErrorMsg(ctx: NetscriptContext, msg: string): string {
const errstack = new Error().stack;
if (errstack === undefined) throw new Error("how did we not throw an error?");
const stack = errstack.split("\n").slice(1);
const workerScript = ctx.workerScript;
const caller = ctx.function;
const scripts = workerScript.getServer().scripts;
const userstack = [];
for (const stackline of stack) {
let filename;
for (const script of scripts) {
if (script.url && stackline.includes(script.url)) {
filename = script.filename;
}
for (const dependency of script.dependencies) {
if (stackline.includes(dependency.url)) {
filename = dependency.filename;
}
}
}
if (!filename) continue;
interface ILine {
line: string;
func: string;
}
function parseChromeStackline(line: string): ILine | null {
const lineRe = /.*:(\d+):\d+.*/;
const funcRe = /.*at (.+) \(.*/;
const lineMatch = line.match(lineRe);
const funcMatch = line.match(funcRe);
if (lineMatch && funcMatch) {
return { line: lineMatch[1], func: funcMatch[1] };
}
return null;
}
let call = { line: "-1", func: "unknown" };
const chromeCall = parseChromeStackline(stackline);
if (chromeCall) {
call = chromeCall;
}
function parseFirefoxStackline(line: string): ILine | null {
const lineRe = /.*:(\d+):\d+$/;
const lineMatch = line.match(lineRe);
const lio = line.lastIndexOf("@");
if (lineMatch && lio !== -1) {
return { line: lineMatch[1], func: line.slice(0, lio) };
}
return null;
}
const firefoxCall = parseFirefoxStackline(stackline);
if (firefoxCall) {
call = firefoxCall;
}
userstack.push(`${filename}:L${call.line}@${call.func}`);
}
workerScript.log(caller, () => msg);
let rejectMsg = `${caller}: ${msg}`;
if (userstack.length !== 0) rejectMsg += `<br><br>Stack:<br>${userstack.join("<br>")}`;
return makeRuntimeRejectMsg(workerScript, rejectMsg);
}
/** Validate requested number of threads for h/g/w options */
function resolveNetscriptRequestedThreads(ctx: NetscriptContext, requestedThreads?: number): number {
const threads = ctx.workerScript.scriptRef.threads;
if (!requestedThreads) {
return isNaN(threads) || threads < 1 ? 1 : threads;
}
const requestedThreadsAsInt = requestedThreads | 0;
if (isNaN(requestedThreads) || requestedThreadsAsInt < 1) {
throw makeRuntimeRejectMsg(
ctx.workerScript,
`Invalid thread count passed to ${ctx.function}: ${requestedThreads}. Threads must be a positive number.`,
);
}
if (requestedThreadsAsInt > threads) {
throw makeRuntimeRejectMsg(
ctx.workerScript,
`Too many threads requested by ${ctx.function}. Requested: ${requestedThreads}. Has: ${threads}.`,
);
}
return requestedThreadsAsInt;
}
/** Validate singularity access by throwing an error if the player does not have access. */
function checkSingularityAccess(ctx: NetscriptContext): void {
if (Player.bitNodeN !== 4 && Player.sourceFileLvl(4) === 0) {
throw makeRuntimeErrorMsg(
ctx,
`This singularity function requires Source-File 4 to run. A power up you obtain later in the game.
It will be very obvious when and how you can obtain it.`,
);
}
}
/** Create an error if a script is dead or if concurrent ns function calls are made */
function checkEnvFlags(ctx: NetscriptContext): void {
const ws = ctx.workerScript;
if (ws.env.stopFlag) throw new ScriptDeath(ws);
if (ws.env.runningFn && ctx.function !== "asleep") {
ws.errorMessage = makeRuntimeRejectMsg(
ws,
`Concurrent calls to Netscript functions are not allowed!
Did you forget to await hack(), grow(), or some other
promise-returning function?
Currently running: ${ws.env.runningFn} tried to run: ${ctx.function}`,
);
if (ws.delayReject) ws.delayReject(new ScriptDeath(ws));
throw new ScriptDeath(ws); //No idea if this is the right thing to throw
}
}
/** Set a timeout for performing a task, mark the script as busy in the meantime. */
function netscriptDelay(ctx: NetscriptContext, time: number): Promise<void> {
const ws = ctx.workerScript;
return new Promise(function (resolve, reject) {
ws.delay = window.setTimeout(() => {
ws.delay = null;
ws.delayReject = undefined;
ws.env.runningFn = "";
if (ws.env.stopFlag) reject(new ScriptDeath(ws));
else resolve();
}, time);
ws.delayReject = reject;
ws.env.runningFn = ctx.function;
});
}
/** Adds to dynamic ram cost when calling new ns functions from a script */
function updateDynamicRam(ctx: NetscriptContext, ramCost: number): void {
const ws = ctx.workerScript;
const fnName = ctx.function;
if (ws.dynamicLoadedFns[fnName]) return;
ws.dynamicLoadedFns[fnName] = true;
let threads = ws.scriptRef.threads;
if (typeof threads !== "number") {
console.warn(`WorkerScript detected NaN for threadcount for ${ws.name} on ${ws.hostname}`);
threads = 1;
}
ws.dynamicRamUsage += ramCost;
if (ws.dynamicRamUsage > 1.01 * ws.ramUsage) {
ws.errorMessage = makeRuntimeRejectMsg(
ws,
`Dynamic RAM usage calculated to be greater than initial RAM usage on fn: ${fnName}.
This is probably because you somehow circumvented the static RAM calculation.
Threads: ${threads}
Dynamic RAM Usage: ${numeralWrapper.formatRAM(ws.dynamicRamUsage)}
Static RAM Usage: ${numeralWrapper.formatRAM(ws.ramUsage)}
One of these could be the reason:
* Using eval() to get a reference to a ns function
&nbsp;&nbsp;const myScan = eval('ns.scan');
* Using map access to do the same
&nbsp;&nbsp;const myScan = ns['scan'];
Sorry :(`,
);
}
}
/** Validates the input v as being a CityName. Throws an error if it is not. */
function city(ctx: NetscriptContext, argName: string, v: unknown): CityName {
if (typeof v !== "string") throw makeRuntimeErrorMsg(ctx, `${argName} should be a city name.`);
const s = v as CityName;
if (!Object.values(CityName).includes(s)) throw makeRuntimeErrorMsg(ctx, `${argName} should be a city name.`);
return s;
}
function scriptIdentifier(
ctx: NetscriptContext,
scriptID: unknown,
_hostname: unknown,
_args: unknown,
): ScriptIdentifier {
const ws = ctx.workerScript;
// Provide the pid for the current script if no identifier provided
if (scriptID === undefined) return ws.pid;
if (typeof scriptID === "number") return scriptID;
if (typeof scriptID === "string") {
const hostname = _hostname === undefined ? ctx.workerScript.hostname : string(ctx, "hostname", _hostname);
const args = _args === undefined ? [] : scriptArgs(ctx, _args);
return {
scriptname: scriptID,
hostname,
args,
};
}
throw new Error("not implemented");
}
/**
* Gets the Server for a specific hostname/ip, throwing an error
* if the server doesn't exist.
* @param {NetscriptContext} ctx - Context from which getServer is being called. For logging purposes.
* @param {string} hostname - Hostname of the server
* @returns {BaseServer} The specified server as a BaseServer
*/
function getServer(ctx: NetscriptContext, hostname: string) {
const server = GetServer(hostname);
if (server == null) {
const str = hostname === "" ? "'' (empty string)" : "'" + hostname + "'";
throw makeRuntimeErrorMsg(ctx, `Invalid hostname: ${str}`);
}
return server;
}
function isScriptArgs(args: unknown): args is ScriptArg[] {
const isScriptArg = (arg: unknown) => typeof arg === "string" || typeof arg === "number" || typeof arg === "boolean";
return Array.isArray(args) && args.every(isScriptArg);
}
async function hack(
ctx: NetscriptContext,
hostname: string,
manual: boolean,
{ threads: requestedThreads, stock }: BasicHGWOptions = {},
): Promise<number> {
const ws = ctx.workerScript;
const threads = helpers.resolveNetscriptRequestedThreads(ctx, requestedThreads);
const server = getServer(ctx, hostname);
if (!(server instanceof Server)) {
throw makeRuntimeErrorMsg(ctx, "Cannot be executed on this server.");
}
// Calculate the hacking time
const hackingTime = calculateHackingTime(server, Player); // This is in seconds
// No root access or skill level too low
const canHack = netscriptCanHack(server, Player);
if (!canHack.res) {
throw makeRuntimeErrorMsg(ctx, canHack.msg || "");
}
log(
ctx,
() =>
`Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(
hackingTime * 1000,
true,
)} (t=${numeralWrapper.formatThreads(threads)})`,
);
return helpers.netscriptDelay(ctx, hackingTime * 1000).then(function () {
const hackChance = calculateHackingChance(server, Player);
const rand = Math.random();
let expGainedOnSuccess = calculateHackingExpGain(server, Player) * threads;
const expGainedOnFailure = expGainedOnSuccess / 4;
if (rand < hackChance) {
// Success!
const percentHacked = calculatePercentMoneyHacked(server, Player);
let maxThreadNeeded = Math.ceil(1 / percentHacked);
if (isNaN(maxThreadNeeded)) {
// Server has a 'max money' of 0 (probably). We'll set this to an arbitrarily large value
maxThreadNeeded = 1e6;
}
let moneyDrained = Math.floor(server.moneyAvailable * percentHacked) * threads;
// Over-the-top safety checks
if (moneyDrained <= 0) {
moneyDrained = 0;
expGainedOnSuccess = expGainedOnFailure;
}
if (moneyDrained > server.moneyAvailable) {
moneyDrained = server.moneyAvailable;
}
server.moneyAvailable -= moneyDrained;
if (server.moneyAvailable < 0) {
server.moneyAvailable = 0;
}
let moneyGained = moneyDrained * BitNodeMultipliers.ScriptHackMoneyGain;
if (manual) {
moneyGained = moneyDrained * BitNodeMultipliers.ManualHackMoney;
}
Player.gainMoney(moneyGained, "hacking");
ws.scriptRef.onlineMoneyMade += moneyGained;
Player.scriptProdSinceLastAug += moneyGained;
ws.scriptRef.recordHack(server.hostname, moneyGained, threads);
Player.gainHackingExp(expGainedOnSuccess);
if (manual) Player.gainIntelligenceExp(0.005);
ws.scriptRef.onlineExpGained += expGainedOnSuccess;
log(
ctx,
() =>
`Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney(
moneyGained,
)} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${numeralWrapper.formatThreads(threads)})`,
);
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
if (stock) {
influenceStockThroughServerHack(server, moneyDrained);
}
if (manual) {
server.backdoorInstalled = true;
}
return Promise.resolve(moneyGained);
} else {
// Player only gains 25% exp for failure?
Player.gainHackingExp(expGainedOnFailure);
ws.scriptRef.onlineExpGained += expGainedOnFailure;
log(
ctx,
() =>
`Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp(
expGainedOnFailure,
)} exp (t=${numeralWrapper.formatThreads(threads)})`,
);
return Promise.resolve(0);
}
});
}
function getValidPort(ctx: NetscriptContext, port: number): IPort {
if (isNaN(port)) {
throw makeRuntimeErrorMsg(
ctx,
`Invalid argument. Must be a port number between 1 and ${CONSTANTS.NumNetscriptPorts}, is ${port}`,
);
}
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
ctx,
`Trying to use an invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg(ctx, `Could not find port: ${port}. This is a bug. Report to dev.`);
}
return iport;
}
function player(ctx: NetscriptContext, p: unknown): IPlayer {
const fakePlayer = {
hp: undefined,
mults: undefined,
numPeopleKilled: undefined,
money: undefined,
city: undefined,
location: undefined,
bitNodeN: undefined,
totalPlaytime: undefined,
playtimeSinceLastAug: undefined,
playtimeSinceLastBitnode: undefined,
jobs: undefined,
factions: undefined,
tor: undefined,
inBladeburner: undefined,
hasCorporation: undefined,
entropy: undefined,
};
if (!roughlyIs(fakePlayer, p)) throw makeRuntimeErrorMsg(ctx, `player should be a Player.`);
return p as IPlayer;
}
function server(ctx: NetscriptContext, s: unknown): Server {
if (!roughlyIs(new Server(), s)) throw makeRuntimeErrorMsg(ctx, `server should be a Server.`);
return s as Server;
}
function roughlyIs(expect: object, actual: unknown): boolean {
if (typeof actual !== "object" || actual == null) return false;
const expects = Object.keys(expect);
const actuals = Object.keys(actual);
for (const expect of expects)
if (!actuals.includes(expect)) {
return false;
}
return true;
}
function gang(ctx: NetscriptContext, g: unknown): FormulaGang {
if (!roughlyIs({ respect: 0, territory: 0, wantedLevel: 0 }, g))
throw makeRuntimeErrorMsg(ctx, `gang should be a Gang.`);
return g as FormulaGang;
}
function gangMember(ctx: NetscriptContext, m: unknown): GangMember {
if (!roughlyIs(new GangMember(), m)) throw makeRuntimeErrorMsg(ctx, `member should be a GangMember.`);
return m as GangMember;
}
function gangTask(ctx: NetscriptContext, t: unknown): GangMemberTask {
if (!roughlyIs(new GangMemberTask("", "", false, false, {}), t))
throw makeRuntimeErrorMsg(ctx, `task should be a GangMemberTask.`);
return t as GangMemberTask;
}
function log(ctx: NetscriptContext, message: () => string) {
ctx.workerScript.log(ctx.functionPath, message);
}
/**
* Searches for and returns the RunningScript object for the specified script.
* If the 'fn' argument is not specified, this returns the current RunningScript.
* @param {string} fn - Filename of script
* @param {string} hostname - Hostname/ip of the server on which the script resides
* @param {any[]} scriptArgs - Running script's arguments
* @returns {RunningScript}
* Running script identified by the parameters, or null if no such script
* exists, or the current running script if the first argument 'fn'
* is not specified.
*/
function getRunningScriptByArgs(
ctx: NetscriptContext,
fn: string,
hostname: string,
scriptArgs: ScriptArg[],
): RunningScript | null {
if (!Array.isArray(scriptArgs)) {
throw helpers.makeRuntimeRejectMsg(
ctx.workerScript,
`Invalid scriptArgs argument passed into getRunningScript() from ${ctx.function}(). ` +
`This is probably a bug. Please report to game developer`,
);
}
if (fn != null && typeof fn === "string") {
// Get Logs of another script
if (hostname == null) {
hostname = ctx.workerScript.hostname;
}
const server = helpers.getServer(ctx, hostname);
return findRunningScript(fn, scriptArgs, server);
}
// If no arguments are specified, return the current RunningScript
return ctx.workerScript.scriptRef;
}
/** Provides an array of all function names on a nested object */
function getFunctionNames(obj: object, prefix: string): string[] {
const functionNames: string[] = [];
for (const [key, value] of Object.entries(obj)) {
if (key === "args") {
continue;
} else if (typeof value == "function") {
functionNames.push(prefix + key);
} else if (typeof value == "object") {
functionNames.push(...getFunctionNames(value, key + "."));
}
}
return functionNames;
}
function getRunningScriptByPid(pid: number): RunningScript | null {
for (const server of GetAllServers()) {
const runningScript = findRunningScriptByPid(pid, server);
if (runningScript) return runningScript;
}
return null;
}
function getRunningScript(ctx: NetscriptContext, ident: ScriptIdentifier): RunningScript | null {
if (typeof ident === "number") {
return getRunningScriptByPid(ident);
} else {
return getRunningScriptByArgs(ctx, ident.scriptname, ident.hostname, ident.args);
}
}
/**
* Helper function for getting the error log message when the user specifies
* a nonexistent running script
* @param {string} fn - Filename of script
* @param {string} hostname - Hostname/ip of the server on which the script resides
* @param {any[]} scriptArgs - Running script's arguments
* @returns {string} Error message to print to logs
*/
function getCannotFindRunningScriptErrorMessage(ident: ScriptIdentifier): string {
if (typeof ident === "number") return `Cannot find running script with pid: ${ident}`;
return `Cannot find running script ${ident.scriptname} on server ${ident.hostname} with args: ${arrayToString(
ident.args,
)}`;
}
/**
* Sanitizes a `RunningScript` to remove sensitive information, making it suitable for
* return through an NS function.
* @see NS.getRecentScripts
* @see NS.getRunningScript
* @param runningScript Existing, internal RunningScript
* @returns A sanitized, NS-facing copy of the RunningScript
*/
function createPublicRunningScript(runningScript: RunningScript): IRunningScript {
return {
args: runningScript.args.slice(),
filename: runningScript.filename,
logs: runningScript.logs.slice(),
offlineExpGained: runningScript.offlineExpGained,
offlineMoneyMade: runningScript.offlineMoneyMade,
offlineRunningTime: runningScript.offlineRunningTime,
onlineExpGained: runningScript.onlineExpGained,
onlineMoneyMade: runningScript.onlineMoneyMade,
onlineRunningTime: runningScript.onlineRunningTime,
pid: runningScript.pid,
ramUsage: runningScript.ramUsage,
server: runningScript.server,
threads: runningScript.threads,
};
}
/**
* Used to fail a function if the function's target is a Hacknet Server.
* This is used for functions that should run on normal Servers, but not Hacknet Servers
* @param {Server} server - Target server
* @param {string} callingFn - Name of calling function. For logging purposes
* @returns {boolean} True if the server is a Hacknet Server, false otherwise
*/
function failOnHacknetServer(ctx: NetscriptContext, server: BaseServer, callingFn = ""): boolean {
if (server instanceof HacknetServer) {
ctx.workerScript.log(callingFn, () => `Does not work on Hacknet Servers`);
return true;
} else {
return false;
}
}

@ -346,6 +346,11 @@ const grafting = {
}; };
const corporation = { const corporation = {
getMaterialNames: 0,
getIndustryTypes: 0,
getUnlockables: 0,
getUpgradeNames: 0,
getResearchNames: 0,
createCorporation: 0, createCorporation: 0,
hasUnlockUpgrade: 0, hasUnlockUpgrade: 0,
getUnlockUpgradeCost: 0, getUnlockUpgradeCost: 0,

@ -0,0 +1,9 @@
import { ScriptArg } from "./ScriptArg";
export type ScriptIdentifier = //This was previously in INetscriptHelper.ts, may move to its own file or a generic types file.
| number
| {
scriptname: string;
hostname: string;
args: ScriptArg[];
};

@ -10,7 +10,6 @@ import { WorkerScriptStartStopEventEmitter } from "./WorkerScriptStartStopEventE
import { RunningScript } from "../Script/RunningScript"; import { RunningScript } from "../Script/RunningScript";
import { GetServer } from "../Server/AllServers"; import { GetServer } from "../Server/AllServers";
import { compareArrays } from "../utils/helpers/compareArrays";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { AddRecentScript } from "./RecentScripts"; import { AddRecentScript } from "./RecentScripts";
import { Player } from "../Player"; import { Player } from "../Player";
@ -33,13 +32,8 @@ export function killWorkerScript(params: killScriptParams): boolean {
// If for some reason that doesn't work, we'll try the old way // If for some reason that doesn't work, we'll try the old way
for (const ws of workerScripts.values()) { for (const ws of workerScripts.values()) {
if ( if (ws.scriptRef === params.runningScript) {
ws.name == params.runningScript.filename &&
ws.hostname == params.hostname &&
compareArrays(ws.args, params.runningScript.args)
) {
stopAndCleanUpWorkerScript(ws); stopAndCleanUpWorkerScript(ws);
return true; return true;
} }
} }
@ -52,7 +46,6 @@ function killWorkerScriptByPid(pid: number): boolean {
const ws = workerScripts.get(pid); const ws = workerScripts.get(pid);
if (ws instanceof WorkerScript) { if (ws instanceof WorkerScript) {
stopAndCleanUpWorkerScript(ws); stopAndCleanUpWorkerScript(ws);
return true; return true;
} }
@ -86,7 +79,6 @@ function stopAndCleanUpWorkerScript(workerScript: WorkerScript): void {
*/ */
function removeWorkerScript(workerScript: WorkerScript): void { function removeWorkerScript(workerScript: WorkerScript): void {
const ip = workerScript.hostname; const ip = workerScript.hostname;
const name = workerScript.name;
// Get the server on which the script runs // Get the server on which the script runs
const server = GetServer(ip); const server = GetServer(ip);
@ -98,7 +90,7 @@ function removeWorkerScript(workerScript: WorkerScript): void {
// Delete the RunningScript object from that server // Delete the RunningScript object from that server
for (let i = 0; i < server.runningScripts.length; ++i) { for (let i = 0; i < server.runningScripts.length; ++i) {
const runningScript = server.runningScripts[i]; const runningScript = server.runningScripts[i];
if (runningScript.filename === name && compareArrays(runningScript.args, workerScript.args)) { if (runningScript === workerScript.scriptRef) {
server.runningScripts.splice(i, 1); server.runningScripts.splice(i, 1);
break; break;
} }

@ -1,65 +0,0 @@
import { isString } from "./utils/helpers/isString";
import { GetServer } from "./Server/AllServers";
import { ScriptDeath } from "./Netscript/ScriptDeath";
import { WorkerScript } from "./Netscript/WorkerScript";
import { NetscriptContext } from "./Netscript/APIWrapper";
export function netscriptDelay(time: number, workerScript: WorkerScript): Promise<void> {
// Cancel any pre-existing netscriptDelay'ed function call
// TODO: the rejection almost certainly ends up in the uncaught rejection handler.
// Maybe reject with a stack-trace'd error message?
if (workerScript.delayReject) workerScript.delayReject();
return new Promise(function (resolve, reject) {
workerScript.delay = window.setTimeout(() => {
workerScript.delay = null;
workerScript.delayReject = undefined;
if (workerScript.env.stopFlag) reject(new ScriptDeath(workerScript));
else resolve();
}, time);
workerScript.delayReject = reject;
});
}
export function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string): string {
const server = GetServer(workerScript.hostname);
if (server == null) {
throw new Error(`WorkerScript constructed with invalid server ip: ${workerScript.hostname}`);
}
for (const scriptUrl of workerScript.scriptRef.dependencies) {
// Return just the original msg if it's nullish so that we don't get a workerscript error
msg = msg?.replace(new RegExp(scriptUrl.url, "g"), scriptUrl.filename) ?? msg;
}
return "|DELIMITER|" + server.hostname + "|DELIMITER|" + workerScript.name + "|DELIMITER|" + msg;
}
export function resolveNetscriptRequestedThreads(ctx: NetscriptContext, requestedThreads?: number): number {
const threads = ctx.workerScript.scriptRef.threads;
if (!requestedThreads) {
return isNaN(threads) || threads < 1 ? 1 : threads;
}
const requestedThreadsAsInt = requestedThreads | 0;
if (isNaN(requestedThreads) || requestedThreadsAsInt < 1) {
throw makeRuntimeRejectMsg(
ctx.workerScript,
`Invalid thread count passed to ${ctx.function}: ${requestedThreads}. Threads must be a positive number.`,
);
}
if (requestedThreadsAsInt > threads) {
throw makeRuntimeRejectMsg(
ctx.workerScript,
`Too many threads requested by ${ctx.function}. Requested: ${requestedThreads}. Has: ${threads}.`,
);
}
return requestedThreadsAsInt;
}
export function isScriptErrorMessage(msg: string): boolean {
if (!isString(msg)) {
return false;
}
const splitMsg = msg.split("|DELIMITER|");
return splitMsg.length == 4;
}

File diff suppressed because it is too large Load Diff

@ -1,13 +1,13 @@
import { WorkerScript } from "../Netscript/WorkerScript"; import { Player as player } from "../Player";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Bladeburner } from "../Bladeburner/Bladeburner"; import { Bladeburner } from "../Bladeburner/Bladeburner";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Bladeburner as INetscriptBladeburner, BladeburnerCurAction } from "../ScriptEditor/NetscriptDefinitions"; import { Bladeburner as INetscriptBladeburner, BladeburnerCurAction } from "../ScriptEditor/NetscriptDefinitions";
import { IAction } from "src/Bladeburner/IAction"; import { IAction } from "src/Bladeburner/IAction";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
import { BlackOperation } from "../Bladeburner/BlackOperation"; import { BlackOperation } from "../Bladeburner/BlackOperation";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript): InternalAPI<INetscriptBladeburner> { export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const checkBladeburnerAccess = function (ctx: NetscriptContext, skipjoined = false): void { const checkBladeburnerAccess = function (ctx: NetscriptContext, skipjoined = false): void {
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Must have joined bladeburner"); if (bladeburner === null) throw new Error("Must have joined bladeburner");
@ -18,13 +18,13 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
}); });
if (!apiAccess) { if (!apiAccess) {
const apiDenied = `You do not currently have access to the Bladeburner API. You must either be in BitNode-7 or have Source-File 7.`; const apiDenied = `You do not currently have access to the Bladeburner API. You must either be in BitNode-7 or have Source-File 7.`;
throw ctx.makeRuntimeErrorMsg(apiDenied); throw helpers.makeRuntimeErrorMsg(ctx, apiDenied);
} }
if (!skipjoined) { if (!skipjoined) {
const bladeburnerAccess = bladeburner instanceof Bladeburner; const bladeburnerAccess = bladeburner instanceof Bladeburner;
if (!bladeburnerAccess) { if (!bladeburnerAccess) {
const bladeburnerDenied = `You must be a member of the Bladeburner division to use this API.`; const bladeburnerDenied = `You must be a member of the Bladeburner division to use this API.`;
throw ctx.makeRuntimeErrorMsg(bladeburnerDenied); throw helpers.makeRuntimeErrorMsg(ctx, bladeburnerDenied);
} }
} }
}; };
@ -33,7 +33,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Must have joined bladeburner"); if (bladeburner === null) throw new Error("Must have joined bladeburner");
if (!bladeburner.cities.hasOwnProperty(city)) { if (!bladeburner.cities.hasOwnProperty(city)) {
throw ctx.makeRuntimeErrorMsg(`Invalid city: ${city}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city: ${city}`);
} }
}; };
@ -42,11 +42,11 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
if (bladeburner === null) throw new Error("Must have joined bladeburner"); if (bladeburner === null) throw new Error("Must have joined bladeburner");
const actionId = bladeburner.getActionIdFromTypeAndName(type, name); const actionId = bladeburner.getActionIdFromTypeAndName(type, name);
if (!actionId) { if (!actionId) {
throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid action type='${type}', name='${name}'`);
} }
const actionObj = bladeburner.getActionObject(actionId); const actionObj = bladeburner.getActionObject(actionId);
if (!actionObj) { if (!actionObj) {
throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid action type='${type}', name='${name}'`);
} }
return actionObj; return actionObj;
@ -74,7 +74,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getBlackOpRank: getBlackOpRank:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_blackOpName: unknown): number => { (_blackOpName: unknown): number => {
const blackOpName = ctx.helper.string("blackOpName", _blackOpName); const blackOpName = helpers.string(ctx, "blackOpName", _blackOpName);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, "blackops", blackOpName); const action = getBladeburnerActionObject(ctx, "blackops", blackOpName);
if (!(action instanceof BlackOperation)) throw new Error("action was not a black operation"); if (!(action instanceof BlackOperation)) throw new Error("action was not a black operation");
@ -95,15 +95,15 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
startAction: startAction:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): boolean => { (_type: unknown, _name: unknown): boolean => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.startActionNetscriptFn(player, type, name, workerScript); return bladeburner.startActionNetscriptFn(player, type, name, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
stopBladeburnerAction: (ctx: NetscriptContext) => (): void => { stopBladeburnerAction: (ctx: NetscriptContext) => (): void => {
@ -121,8 +121,8 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionTime: getActionTime:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => { (_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@ -130,13 +130,13 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
const time = bladeburner.getActionTimeNetscriptFn(player, type, name); const time = bladeburner.getActionTimeNetscriptFn(player, type, name);
if (typeof time === "string") { if (typeof time === "string") {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
ctx.log(() => errorLogText); helpers.log(ctx, () => errorLogText);
return -1; return -1;
} else { } else {
return time; return time;
} }
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getActionCurrentTime: (ctx: NetscriptContext) => (): number => { getActionCurrentTime: (ctx: NetscriptContext) => (): number => {
@ -149,14 +149,14 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
1000; 1000;
return timecomputed; return timecomputed;
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getActionEstimatedSuccessChance: getActionEstimatedSuccessChance:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): [number, number] => { (_type: unknown, _name: unknown): [number, number] => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@ -164,21 +164,21 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name); const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name);
if (typeof chance === "string") { if (typeof chance === "string") {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
ctx.log(() => errorLogText); helpers.log(ctx, () => errorLogText);
return [-1, -1]; return [-1, -1];
} else { } else {
return chance; return chance;
} }
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getActionRepGain: getActionRepGain:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _level: unknown): number => { (_type: unknown, _name: unknown, _level: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
const level = ctx.helper.number("level", _level); const level = helpers.number(ctx, "level", _level);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name); const action = getBladeburnerActionObject(ctx, type, name);
let rewardMultiplier; let rewardMultiplier;
@ -193,22 +193,22 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionCountRemaining: getActionCountRemaining:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => { (_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.getActionCountRemainingNetscriptFn(type, name, workerScript); return bladeburner.getActionCountRemainingNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getActionMaxLevel: getActionMaxLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => { (_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name); const action = getBladeburnerActionObject(ctx, type, name);
return action.maxLevel; return action.maxLevel;
@ -216,8 +216,8 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionCurrentLevel: getActionCurrentLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => { (_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name); const action = getBladeburnerActionObject(ctx, type, name);
return action.level; return action.level;
@ -225,8 +225,8 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionAutolevel: getActionAutolevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): boolean => { (_type: unknown, _name: unknown): boolean => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name); const action = getBladeburnerActionObject(ctx, type, name);
return action.autoLevel; return action.autoLevel;
@ -234,9 +234,9 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
setActionAutolevel: setActionAutolevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _autoLevel: unknown = true): void => { (_type: unknown, _name: unknown, _autoLevel: unknown = true): void => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
const autoLevel = ctx.helper.boolean(_autoLevel); const autoLevel = !!_autoLevel;
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name); const action = getBladeburnerActionObject(ctx, type, name);
action.autoLevel = autoLevel; action.autoLevel = autoLevel;
@ -244,13 +244,13 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
setActionLevel: setActionLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _level: unknown = 1): void => { (_type: unknown, _name: unknown, _level: unknown = 1): void => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
const level = ctx.helper.number("level", _level); const level = helpers.number(ctx, "level", _level);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name); const action = getBladeburnerActionObject(ctx, type, name);
if (level < 1 || level > action.maxLevel) { if (level < 1 || level > action.maxLevel) {
ctx.helper.makeRuntimeErrorMsg(`Level must be between 1 and ${action.maxLevel}, is ${level}`); helpers.makeRuntimeErrorMsg(ctx, `Level must be between 1 and ${action.maxLevel}, is ${level}`);
} }
action.level = level; action.level = level;
}, },
@ -269,77 +269,77 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getSkillLevel: getSkillLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_skillName: unknown): number => { (_skillName: unknown): number => {
const skillName = ctx.helper.string("skillName", _skillName); const skillName = helpers.string(ctx, "skillName", _skillName);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.getSkillLevelNetscriptFn(skillName, workerScript); return bladeburner.getSkillLevelNetscriptFn(skillName, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getSkillUpgradeCost: getSkillUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_skillName: unknown, _count: unknown = 1): number => { (_skillName: unknown, _count: unknown = 1): number => {
const skillName = ctx.helper.string("skillName", _skillName); const skillName = helpers.string(ctx, "skillName", _skillName);
const count = ctx.helper.number("count", _count); const count = helpers.number(ctx, "count", _count);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, count, workerScript); return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, count, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
upgradeSkill: upgradeSkill:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_skillName: unknown, _count: unknown = 1): boolean => { (_skillName: unknown, _count: unknown = 1): boolean => {
const skillName = ctx.helper.string("skillName", _skillName); const skillName = helpers.string(ctx, "skillName", _skillName);
const count = ctx.helper.number("count", _count); const count = helpers.number(ctx, "count", _count);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.upgradeSkillNetscriptFn(skillName, count, workerScript); return bladeburner.upgradeSkillNetscriptFn(skillName, count, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getTeamSize: getTeamSize:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => { (_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.getTeamSizeNetscriptFn(type, name, workerScript); return bladeburner.getTeamSizeNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
setTeamSize: setTeamSize:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _size: unknown): number => { (_type: unknown, _name: unknown, _size: unknown): number => {
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const name = ctx.helper.string("name", _name); const name = helpers.string(ctx, "name", _name);
const size = ctx.helper.number("size", _size); const size = helpers.number(ctx, "size", _size);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try { try {
return bladeburner.setTeamSizeNetscriptFn(type, name, size, workerScript); return bladeburner.setTeamSizeNetscriptFn(type, name, size, ctx.workerScript);
} catch (e: unknown) { } catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e)); throw helpers.makeRuntimeErrorMsg(ctx, String(e));
} }
}, },
getCityEstimatedPopulation: getCityEstimatedPopulation:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_cityName: unknown): number => { (_cityName: unknown): number => {
const cityName = ctx.helper.string("cityName", _cityName); const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName); checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
@ -349,7 +349,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getCityCommunities: getCityCommunities:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_cityName: unknown): number => { (_cityName: unknown): number => {
const cityName = ctx.helper.string("cityName", _cityName); const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName); checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
@ -359,7 +359,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getCityChaos: getCityChaos:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_cityName: unknown): number => { (_cityName: unknown): number => {
const cityName = ctx.helper.string("cityName", _cityName); const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName); checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
@ -375,7 +375,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
switchCity: switchCity:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_cityName: unknown): boolean => { (_cityName: unknown): boolean => {
const cityName = ctx.helper.string("cityName", _cityName); const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName); checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
@ -393,7 +393,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
checkBladeburnerAccess(ctx, true); checkBladeburnerAccess(ctx, true);
const bladeburner = player.bladeburner; const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.joinBladeburnerFactionNetscriptFn(workerScript); return bladeburner.joinBladeburnerFactionNetscriptFn(ctx.workerScript);
}, },
joinBladeburnerDivision: (ctx: NetscriptContext) => (): boolean => { joinBladeburnerDivision: (ctx: NetscriptContext) => (): boolean => {
if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) { if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) {
@ -409,11 +409,11 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
player.skills.agility >= 100 player.skills.agility >= 100
) { ) {
player.bladeburner = new Bladeburner(player); player.bladeburner = new Bladeburner(player);
ctx.log(() => "You have been accepted into the Bladeburner division"); helpers.log(ctx, () => "You have been accepted into the Bladeburner division");
return true; return true;
} else { } else {
ctx.log(() => "You do not meet the requirements for joining the Bladeburner division"); helpers.log(ctx, () => "You do not meet the requirements for joining the Bladeburner division");
return false; return false;
} }
} }

@ -1,21 +1,21 @@
import { WorkerScript } from "../Netscript/WorkerScript"; import { Player as player } from "../Player";
import { IPlayer } from "../PersonObjects/IPlayer";
import { is2DArray } from "../utils/helpers/is2DArray"; import { is2DArray } from "../utils/helpers/is2DArray";
import { CodingContract } from "../CodingContracts"; import { CodingContract } from "../CodingContracts";
import { CodingAttemptOptions, CodingContract as ICodingContract } from "../ScriptEditor/NetscriptDefinitions"; import { CodingAttemptOptions, CodingContract as ICodingContract } from "../ScriptEditor/NetscriptDefinitions";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScript): InternalAPI<ICodingContract> { export function NetscriptCodingContract(): InternalAPI<ICodingContract> {
const getCodingContract = function ( const getCodingContract = function (
ctx: NetscriptContext, ctx: NetscriptContext,
func: string, func: string,
hostname: string, hostname: string,
filename: string, filename: string,
): CodingContract { ): CodingContract {
const server = ctx.helper.getServer(hostname); const server = helpers.getServer(ctx, hostname);
const contract = server.getContract(filename); const contract = server.getContract(filename);
if (contract == null) { if (contract == null) {
throw ctx.makeRuntimeErrorMsg(`Cannot find contract '${filename}' on server '${hostname}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Cannot find contract '${filename}' on server '${hostname}'`);
} }
return contract; return contract;
@ -27,11 +27,11 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
( (
answer: unknown, answer: unknown,
_filename: unknown, _filename: unknown,
_hostname: unknown = workerScript.hostname, _hostname: unknown = ctx.workerScript.hostname,
{ returnReward }: CodingAttemptOptions = { returnReward: false }, { returnReward }: CodingAttemptOptions = { returnReward: false },
): boolean | string => { ): boolean | string => {
const filename = ctx.helper.string("filename", _filename); const filename = helpers.string(ctx, "filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname); const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "attempt", hostname, filename); const contract = getCodingContract(ctx, "attempt", hostname, filename);
// Convert answer to string. If the answer is a 2D array, then we have to // Convert answer to string. If the answer is a 2D array, then we have to
@ -51,19 +51,20 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
const creward = contract.reward; const creward = contract.reward;
if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward"); if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward");
const serv = ctx.helper.getServer(hostname); const serv = helpers.getServer(ctx, hostname);
if (contract.isSolution(answerStr)) { if (contract.isSolution(answerStr)) {
const reward = player.gainCodingContractReward(creward, contract.getDifficulty()); const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
ctx.log(() => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`); helpers.log(ctx, () => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`);
serv.removeContract(filename); serv.removeContract(filename);
return returnReward ? reward : true; return returnReward ? reward : true;
} else { } else {
++contract.tries; ++contract.tries;
if (contract.tries >= contract.getMaxNumTries()) { if (contract.tries >= contract.getMaxNumTries()) {
ctx.log(() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`); helpers.log(ctx, () => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`);
serv.removeContract(filename); serv.removeContract(filename);
} else { } else {
ctx.log( helpers.log(
ctx,
() => () =>
`Coding Contract attempt '${filename}' failed. ${ `Coding Contract attempt '${filename}' failed. ${
contract.getMaxNumTries() - contract.tries contract.getMaxNumTries() - contract.tries
@ -76,17 +77,17 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
}, },
getContractType: getContractType:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => { (_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): string => {
const filename = ctx.helper.string("filename", _filename); const filename = helpers.string(ctx, "filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname); const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getContractType", hostname, filename); const contract = getCodingContract(ctx, "getContractType", hostname, filename);
return contract.getType(); return contract.getType();
}, },
getData: getData:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): unknown => { (_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): unknown => {
const filename = ctx.helper.string("filename", _filename); const filename = helpers.string(ctx, "filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname); const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getData", hostname, filename); const contract = getCodingContract(ctx, "getData", hostname, filename);
const data = contract.getData(); const data = contract.getData();
if (Array.isArray(data)) { if (Array.isArray(data)) {
@ -107,17 +108,17 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
}, },
getDescription: getDescription:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => { (_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): string => {
const filename = ctx.helper.string("filename", _filename); const filename = helpers.string(ctx, "filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname); const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getDescription", hostname, filename); const contract = getCodingContract(ctx, "getDescription", hostname, filename);
return contract.getDescription(); return contract.getDescription();
}, },
getNumTriesRemaining: getNumTriesRemaining:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): number => { (_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): number => {
const filename = ctx.helper.string("filename", _filename); const filename = helpers.string(ctx, "filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname); const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getNumTriesRemaining", hostname, filename); const contract = getCodingContract(ctx, "getNumTriesRemaining", hostname, filename);
return contract.getMaxNumTries() - contract.tries; return contract.getMaxNumTries() - contract.tries;
}, },

@ -1,4 +1,4 @@
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { OfficeSpace } from "../Corporation/OfficeSpace"; import { OfficeSpace } from "../Corporation/OfficeSpace";
import { Employee } from "../Corporation/Employee"; import { Employee } from "../Corporation/Employee";
@ -65,9 +65,10 @@ import { CorporationConstants } from "../Corporation/data/Constants";
import { ResearchMap } from "../Corporation/ResearchMap"; import { ResearchMap } from "../Corporation/ResearchMap";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation> { export function NetscriptCorporation(): InternalAPI<NSCorporation> {
function createCorporation(corporationName: string, selfFund = true): boolean { function createCorporation(corporationName: string, selfFund = true): boolean {
if (!player.canAccessCorporation() || player.hasCorporation()) return false; if (!player.canAccessCorporation() || player.hasCorporation()) return false;
if (!corporationName) return false; if (!corporationName) return false;
@ -101,7 +102,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
} }
function getUpgradeLevel(ctx: NetscriptContext, _upgradeName: string): number { function getUpgradeLevel(ctx: NetscriptContext, _upgradeName: string): number {
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation(); const corporation = getCorporation();
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName); const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`); if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
@ -110,7 +111,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
} }
function getUpgradeLevelCost(ctx: NetscriptContext, _upgradeName: string): number { function getUpgradeLevelCost(ctx: NetscriptContext, _upgradeName: string): number {
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation(); const corporation = getCorporation();
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName); const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`); if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
@ -274,10 +275,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
} }
function checkAccess(ctx: NetscriptContext, api?: number): void { function checkAccess(ctx: NetscriptContext, api?: number): void {
if (player.corporation === null) throw ctx.makeRuntimeErrorMsg("Must own a corporation."); if (player.corporation === null) throw helpers.makeRuntimeErrorMsg(ctx, "Must own a corporation.");
if (!api) return; if (!api) return;
if (!player.corporation.unlockUpgrades[api]) throw ctx.makeRuntimeErrorMsg("You do not have access to this API."); if (!player.corporation.unlockUpgrades[api])
throw helpers.makeRuntimeErrorMsg(ctx, "You do not have access to this API.");
} }
function getSafeDivision(division: Industry): NSDivision { function getSafeDivision(division: Industry): NSDivision {
@ -314,11 +316,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): number => { (_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): number => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const amt = ctx.helper.number("amount", _amt); const amt = helpers.number(ctx, "amount", _amt);
if (amt < 1) { if (amt < 1) {
throw ctx.makeRuntimeErrorMsg("You must provide a positive number"); throw helpers.makeRuntimeErrorMsg(ctx, "You must provide a positive number");
} }
const warehouse = getWarehouse(divisionName, cityName); const warehouse = getWarehouse(divisionName, cityName);
return UpgradeWarehouseCost(warehouse, amt); return UpgradeWarehouseCost(warehouse, amt);
@ -327,8 +329,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): boolean => { (_divisionName: unknown, _cityName: unknown): boolean => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const division = getDivision(divisionName); const division = getDivision(divisionName);
if (!(cityName in division.warehouses)) throw new Error(`Invalid city name '${cityName}'`); if (!(cityName in division.warehouses)) throw new Error(`Invalid city name '${cityName}'`);
const warehouse = division.warehouses[cityName]; const warehouse = division.warehouses[cityName];
@ -338,8 +340,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): NSWarehouse => { (_divisionName: unknown, _cityName: unknown): NSWarehouse => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const warehouse = getWarehouse(divisionName, cityName); const warehouse = getWarehouse(divisionName, cityName);
return { return {
level: warehouse.level, level: warehouse.level,
@ -353,9 +355,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown): NSMaterial => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown): NSMaterial => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const material = getMaterial(divisionName, cityName, materialName); const material = getMaterial(divisionName, cityName, materialName);
const corporation = getCorporation(); const corporation = getCorporation();
return { return {
@ -374,8 +376,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown): NSProduct => { (_divisionName: unknown, _productName: unknown): NSProduct => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
const product = getProduct(divisionName, productName); const product = getProduct(divisionName, productName);
const corporation = getCorporation(); const corporation = getCorporation();
return { return {
@ -401,8 +403,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): void => { (_divisionName: unknown, _cityName: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const corporation = getCorporation(); const corporation = getCorporation();
PurchaseWarehouse(corporation, getDivision(divisionName), cityName); PurchaseWarehouse(corporation, getDivision(divisionName), cityName);
}, },
@ -410,12 +412,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): void => { (_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const amt = ctx.helper.number("amount", _amt); const amt = helpers.number(ctx, "amount", _amt);
const corporation = getCorporation(); const corporation = getCorporation();
if (amt < 1) { if (amt < 1) {
throw ctx.makeRuntimeErrorMsg("You must provide a positive number"); throw helpers.makeRuntimeErrorMsg(ctx, "You must provide a positive number");
} }
UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName), amt); UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName), amt);
}, },
@ -423,11 +425,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown, _price: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown, _price: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = ctx.helper.string("amt", _amt); const amt = helpers.string(ctx, "amt", _amt);
const price = ctx.helper.string("price", _price); const price = helpers.string(ctx, "price", _price);
const material = getMaterial(divisionName, cityName, materialName); const material = getMaterial(divisionName, cityName, materialName);
SellMaterial(material, amt, price); SellMaterial(material, amt, price);
}, },
@ -442,12 +444,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_all: unknown, _all: unknown,
): void => { ): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
const amt = ctx.helper.string("amt", _amt); const amt = helpers.string(ctx, "amt", _amt);
const price = ctx.helper.string("price", _price); const price = helpers.string(ctx, "price", _price);
const all = ctx.helper.boolean(_all); const all = !!_all;
const product = getProduct(divisionName, productName); const product = getProduct(divisionName, productName);
SellProduct(product, cityName, amt, price, all); SellProduct(product, cityName, amt, price, all);
}, },
@ -455,44 +457,44 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown): void => { (_divisionName: unknown, _productName: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
getDivision(divisionName).discontinueProduct(getProduct(divisionName, productName)); getDivision(divisionName).discontinueProduct(getProduct(divisionName, productName));
}, },
setSmartSupply: setSmartSupply:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _enabled: unknown): void => { (_divisionName: unknown, _cityName: unknown, _enabled: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const enabled = ctx.helper.boolean(_enabled); const enabled = !!_enabled;
const warehouse = getWarehouse(divisionName, cityName); const warehouse = getWarehouse(divisionName, cityName);
if (!hasUnlockUpgrade("Smart Supply")) if (!hasUnlockUpgrade("Smart Supply"))
throw ctx.makeRuntimeErrorMsg(`You have not purchased the Smart Supply upgrade!`); throw helpers.makeRuntimeErrorMsg(ctx, `You have not purchased the Smart Supply upgrade!`);
SetSmartSupply(warehouse, enabled); SetSmartSupply(warehouse, enabled);
}, },
setSmartSupplyUseLeftovers: setSmartSupplyUseLeftovers:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _enabled: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _enabled: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const enabled = ctx.helper.boolean(_enabled); const enabled = !!_enabled;
const warehouse = getWarehouse(divisionName, cityName); const warehouse = getWarehouse(divisionName, cityName);
const material = getMaterial(divisionName, cityName, materialName); const material = getMaterial(divisionName, cityName, materialName);
if (!hasUnlockUpgrade("Smart Supply")) if (!hasUnlockUpgrade("Smart Supply"))
throw ctx.makeRuntimeErrorMsg(`You have not purchased the Smart Supply upgrade!`); throw helpers.makeRuntimeErrorMsg(ctx, `You have not purchased the Smart Supply upgrade!`);
SetSmartSupplyUseLeftovers(warehouse, material, enabled); SetSmartSupplyUseLeftovers(warehouse, material, enabled);
}, },
buyMaterial: buyMaterial:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = ctx.helper.number("amt", _amt); const amt = helpers.number(ctx, "amt", _amt);
if (amt < 0) throw new Error("Invalid value for amount field! Must be numeric and greater than 0"); if (amt < 0) throw new Error("Invalid value for amount field! Must be numeric and greater than 0");
const material = getMaterial(divisionName, cityName, materialName); const material = getMaterial(divisionName, cityName, materialName);
BuyMaterial(material, amt); BuyMaterial(material, amt);
@ -501,13 +503,13 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
if (!hasResearched(getDivision(divisionName), "Bulk Purchasing")) if (!hasResearched(getDivision(divisionName), "Bulk Purchasing"))
throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`); throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`);
const corporation = getCorporation(); const corporation = getCorporation();
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = ctx.helper.number("amt", _amt); const amt = helpers.number(ctx, "amt", _amt);
const warehouse = getWarehouse(divisionName, cityName); const warehouse = getWarehouse(divisionName, cityName);
const material = getMaterial(divisionName, cityName, materialName); const material = getMaterial(divisionName, cityName, materialName);
BulkPurchase(corporation, warehouse, material, amt); BulkPurchase(corporation, warehouse, material, amt);
@ -522,11 +524,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_marketingInvest: unknown, _marketingInvest: unknown,
): void => { ): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
const designInvest = ctx.helper.number("designInvest", _designInvest); const designInvest = helpers.number(ctx, "designInvest", _designInvest);
const marketingInvest = ctx.helper.number("marketingInvest", _marketingInvest); const marketingInvest = helpers.number(ctx, "marketingInvest", _marketingInvest);
const corporation = getCorporation(); const corporation = getCorporation();
MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest); MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest);
}, },
@ -534,10 +536,10 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown, _cityName: unknown, _qty: unknown): void => { (_divisionName: unknown, _productName: unknown, _cityName: unknown, _qty: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
const qty = ctx.helper.number("qty", _qty); const qty = helpers.number(ctx, "qty", _qty);
LimitProductProduction(getProduct(divisionName, productName), cityName, qty); LimitProductProduction(getProduct(divisionName, productName), cityName, qty);
}, },
exportMaterial: exportMaterial:
@ -551,12 +553,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_amt: unknown, _amt: unknown,
): void => { ): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const sourceDivision = ctx.helper.string("sourceDivision", _sourceDivision); const sourceDivision = helpers.string(ctx, "sourceDivision", _sourceDivision);
const sourceCity = ctx.helper.string("sourceCity", _sourceCity); const sourceCity = helpers.string(ctx, "sourceCity", _sourceCity);
const targetDivision = ctx.helper.string("targetDivision", _targetDivision); const targetDivision = helpers.string(ctx, "targetDivision", _targetDivision);
const targetCity = ctx.helper.string("targetCity", _targetCity); const targetCity = helpers.string(ctx, "targetCity", _targetCity);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = ctx.helper.string("amt", _amt); const amt = helpers.string(ctx, "amt", _amt);
ExportMaterial( ExportMaterial(
targetDivision, targetDivision,
targetCity, targetCity,
@ -576,12 +578,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_amt: unknown, _amt: unknown,
): void => { ): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const sourceDivision = ctx.helper.string("sourceDivision", _sourceDivision); const sourceDivision = helpers.string(ctx, "sourceDivision", _sourceDivision);
const sourceCity = ctx.helper.string("sourceCity", _sourceCity); const sourceCity = helpers.string(ctx, "sourceCity", _sourceCity);
const targetDivision = ctx.helper.string("targetDivision", _targetDivision); const targetDivision = helpers.string(ctx, "targetDivision", _targetDivision);
const targetCity = ctx.helper.string("targetCity", _targetCity); const targetCity = helpers.string(ctx, "targetCity", _targetCity);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = ctx.helper.string("amt", _amt); const amt = helpers.string(ctx, "amt", _amt);
CancelExportMaterial( CancelExportMaterial(
targetDivision, targetDivision,
targetCity, targetCity,
@ -593,56 +595,56 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _qty: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _qty: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const qty = ctx.helper.number("qty", _qty); const qty = helpers.number(ctx, "qty", _qty);
LimitMaterialProduction(getMaterial(divisionName, cityName, materialName), qty); LimitMaterialProduction(getMaterial(divisionName, cityName, materialName), qty);
}, },
setMaterialMarketTA1: setMaterialMarketTA1:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _on: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _on: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const on = ctx.helper.boolean(_on); const on = !!_on;
if (!getDivision(divisionName).hasResearch("Market-TA.I")) if (!getDivision(divisionName).hasResearch("Market-TA.I"))
throw ctx.makeRuntimeErrorMsg(`You have not researched MarketTA.I for division: ${divisionName}`); throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.I for division: ${divisionName}`);
SetMaterialMarketTA1(getMaterial(divisionName, cityName, materialName), on); SetMaterialMarketTA1(getMaterial(divisionName, cityName, materialName), on);
}, },
setMaterialMarketTA2: setMaterialMarketTA2:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _on: unknown): void => { (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _on: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName); const materialName = helpers.string(ctx, "materialName", _materialName);
const on = ctx.helper.boolean(_on); const on = !!_on;
if (!getDivision(divisionName).hasResearch("Market-TA.II")) if (!getDivision(divisionName).hasResearch("Market-TA.II"))
throw ctx.makeRuntimeErrorMsg(`You have not researched MarketTA.II for division: ${divisionName}`); throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.II for division: ${divisionName}`);
SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on); SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on);
}, },
setProductMarketTA1: setProductMarketTA1:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown, _on: unknown): void => { (_divisionName: unknown, _productName: unknown, _on: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
const on = ctx.helper.boolean(_on); const on = !!_on;
if (!getDivision(divisionName).hasResearch("Market-TA.I")) if (!getDivision(divisionName).hasResearch("Market-TA.I"))
throw ctx.makeRuntimeErrorMsg(`You have not researched MarketTA.I for division: ${divisionName}`); throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.I for division: ${divisionName}`);
SetProductMarketTA1(getProduct(divisionName, productName), on); SetProductMarketTA1(getProduct(divisionName, productName), on);
}, },
setProductMarketTA2: setProductMarketTA2:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown, _on: unknown): void => { (_divisionName: unknown, _productName: unknown, _on: unknown): void => {
checkAccess(ctx, 7); checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName); const productName = helpers.string(ctx, "productName", _productName);
const on = ctx.helper.boolean(_on); const on = !!_on;
if (!getDivision(divisionName).hasResearch("Market-TA.II")) if (!getDivision(divisionName).hasResearch("Market-TA.II"))
throw ctx.makeRuntimeErrorMsg(`You have not researched MarketTA.II for division: ${divisionName}`); throw helpers.makeRuntimeErrorMsg(ctx, `You have not researched MarketTA.II for division: ${divisionName}`);
SetProductMarketTA2(getProduct(divisionName, productName), on); SetProductMarketTA2(getProduct(divisionName, productName), on);
}, },
}; };
@ -652,7 +654,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown): number => { (_divisionName: unknown): number => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const division = getDivision(divisionName); const division = getDivision(divisionName);
return division.getAdVertCost(); return division.getAdVertCost();
}, },
@ -660,7 +662,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown): number => { (_divisionName: unknown): number => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const division = getDivision(divisionName); const division = getDivision(divisionName);
return division.numAdVerts; return division.numAdVerts;
}, },
@ -668,25 +670,25 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _researchName: unknown): number => { (_divisionName: unknown, _researchName: unknown): number => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const researchName = ctx.helper.string("researchName", _researchName); const researchName = helpers.string(ctx, "researchName", _researchName);
return getResearchCost(getDivision(divisionName), researchName); return getResearchCost(getDivision(divisionName), researchName);
}, },
hasResearched: hasResearched:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _researchName: unknown): boolean => { (_divisionName: unknown, _researchName: unknown): boolean => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const researchName = ctx.helper.string("researchName", _researchName); const researchName = helpers.string(ctx, "researchName", _researchName);
return hasResearched(getDivision(divisionName), researchName); return hasResearched(getDivision(divisionName), researchName);
}, },
getOfficeSizeUpgradeCost: getOfficeSizeUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): number => { (_divisionName: unknown, _cityName: unknown, _size: unknown): number => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const size = ctx.helper.number("size", _size); const size = helpers.number(ctx, "size", _size);
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0"); if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0");
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
const initialPriceMult = Math.round(office.size / CorporationConstants.OfficeInitialSize); const initialPriceMult = Math.round(office.size / CorporationConstants.OfficeInitialSize);
@ -701,10 +703,10 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): void => { (_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): void => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName); const employeeName = helpers.string(ctx, "employeeName", _employeeName);
const job = ctx.helper.string("job", _job); const job = helpers.string(ctx, "job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
@ -715,10 +717,10 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): boolean => { (_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): boolean => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const amount = ctx.helper.number("amount", _amount); const amount = helpers.number(ctx, "amount", _amount);
const job = ctx.helper.string("job", _job); const job = helpers.string(ctx, "job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
@ -729,8 +731,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): NSEmployee | undefined => { (_divisionName: unknown, _cityName: unknown): NSEmployee | undefined => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
const employee = office.hireRandomEmployee(); const employee = office.hireRandomEmployee();
if (employee === undefined) return undefined; if (employee === undefined) return undefined;
@ -753,9 +755,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): void => { (_divisionName: unknown, _cityName: unknown, _size: unknown): void => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const size = ctx.helper.number("size", _size); const size = helpers.number(ctx, "size", _size);
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0"); if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0");
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
const corporation = getCorporation(); const corporation = getCorporation();
@ -765,9 +767,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): number => { (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): number => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const costPerEmployee = ctx.helper.number("costPerEmployee", _costPerEmployee); const costPerEmployee = helpers.number(ctx, "costPerEmployee", _costPerEmployee);
if (costPerEmployee < 0) { if (costPerEmployee < 0) {
throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0"); throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0");
@ -782,8 +784,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): boolean => { (_divisionName: unknown, _cityName: unknown): boolean => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const corporation = getCorporation(); const corporation = getCorporation();
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
@ -794,7 +796,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown): void => { (_divisionName: unknown): void => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const corporation = getCorporation(); const corporation = getCorporation();
HireAdVert(corporation, getDivision(divisionName)); HireAdVert(corporation, getDivision(divisionName));
}, },
@ -802,16 +804,16 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _researchName: unknown): void => { (_divisionName: unknown, _researchName: unknown): void => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const researchName = ctx.helper.string("researchName", _researchName); const researchName = helpers.string(ctx, "researchName", _researchName);
Research(getDivision(divisionName), researchName); Research(getDivision(divisionName), researchName);
}, },
getOffice: getOffice:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): NSOffice => { (_divisionName: unknown, _cityName: unknown): NSOffice => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const office = getOffice(divisionName, cityName); const office = getOffice(divisionName, cityName);
return { return {
loc: office.loc, loc: office.loc,
@ -847,9 +849,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown): NSEmployee => { (_divisionName: unknown, _cityName: unknown, _employeeName: unknown): NSEmployee => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName); const employeeName = helpers.string(ctx, "employeeName", _employeeName);
const employee = getEmployee(divisionName, cityName, employeeName); const employee = getEmployee(divisionName, cityName, employeeName);
return { return {
name: employee.name, name: employee.name,
@ -871,12 +873,27 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
return { return {
...warehouseAPI, ...warehouseAPI,
...officeAPI, ...officeAPI,
getMaterialNames: () => (): string[] => {
return CorporationConstants.AllMaterials;
},
getIndustryTypes: () => (): string[] => {
return CorporationConstants.AllIndustryTypes;
},
getUnlockables: () => (): string[] => {
return CorporationConstants.AllUnlocks;
},
getUpgradeNames: () => (): string[] => {
return CorporationConstants.AllUpgrades;
},
getResearchNames: () => (): string[] => {
return CorporationConstants.AllResearch;
},
expandIndustry: expandIndustry:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_industryName: unknown, _divisionName: unknown): void => { (_industryName: unknown, _divisionName: unknown): void => {
checkAccess(ctx); checkAccess(ctx);
const industryName = ctx.helper.string("industryName", _industryName); const industryName = helpers.string(ctx, "industryName", _industryName);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const corporation = getCorporation(); const corporation = getCorporation();
NewIndustry(corporation, industryName, divisionName); NewIndustry(corporation, industryName, divisionName);
}, },
@ -884,8 +901,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): void => { (_divisionName: unknown, _cityName: unknown): void => {
checkAccess(ctx); checkAccess(ctx);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = helpers.city(ctx, "cityName", _cityName);
if (!CorporationConstants.Cities.includes(cityName)) throw new Error("Invalid city name"); if (!CorporationConstants.Cities.includes(cityName)) throw new Error("Invalid city name");
const corporation = getCorporation(); const corporation = getCorporation();
const division = getDivision(divisionName); const division = getDivision(divisionName);
@ -895,7 +912,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgradeName: unknown): void => { (_upgradeName: unknown): void => {
checkAccess(ctx); checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation(); const corporation = getCorporation();
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade.name === upgradeName); const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade.name === upgradeName);
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`); if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
@ -905,7 +922,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgradeName: unknown): void => { (_upgradeName: unknown): void => {
checkAccess(ctx); checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation(); const corporation = getCorporation();
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName); const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`); if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
@ -915,12 +932,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_rate: unknown): void => { (_rate: unknown): void => {
checkAccess(ctx); checkAccess(ctx);
const rate = ctx.helper.number("rate", _rate); const rate = helpers.number(ctx, "rate", _rate);
const max = CorporationConstants.DividendMaxRate; const max = CorporationConstants.DividendMaxRate;
if (rate < 0 || rate > max) if (rate < 0 || rate > max)
throw new Error(`Invalid value for rate field! Must be numeric, greater than 0, and less than ${max}`); throw new Error(`Invalid value for rate field! Must be numeric, greater than 0, and less than ${max}`);
const corporation = getCorporation(); const corporation = getCorporation();
if (!corporation.public) throw ctx.makeRuntimeErrorMsg(`Your company has not gone public!`); if (!corporation.public) throw helpers.makeRuntimeErrorMsg(ctx, `Your company has not gone public!`);
IssueDividends(corporation, rate); IssueDividends(corporation, rate);
}, },
@ -930,7 +947,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown): NSDivision => { (_divisionName: unknown): NSDivision => {
checkAccess(ctx); checkAccess(ctx);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const division = getDivision(divisionName); const division = getDivision(divisionName);
return getSafeDivision(division); return getSafeDivision(division);
}, },
@ -958,43 +975,43 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
createCorporation: createCorporation:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_corporationName: unknown, _selfFund: unknown = true): boolean => { (_corporationName: unknown, _selfFund: unknown = true): boolean => {
const corporationName = ctx.helper.string("corporationName", _corporationName); const corporationName = helpers.string(ctx, "corporationName", _corporationName);
const selfFund = ctx.helper.boolean(_selfFund); const selfFund = !_selfFund;
return createCorporation(corporationName, selfFund); return createCorporation(corporationName, selfFund);
}, },
hasUnlockUpgrade: hasUnlockUpgrade:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgradeName: unknown): boolean => { (_upgradeName: unknown): boolean => {
checkAccess(ctx); checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return hasUnlockUpgrade(upgradeName); return hasUnlockUpgrade(upgradeName);
}, },
getUnlockUpgradeCost: getUnlockUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgradeName: unknown): number => { (_upgradeName: unknown): number => {
checkAccess(ctx); checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return getUnlockUpgradeCost(upgradeName); return getUnlockUpgradeCost(upgradeName);
}, },
getUpgradeLevel: getUpgradeLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgradeName: unknown): number => { (_upgradeName: unknown): number => {
checkAccess(ctx); checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return getUpgradeLevel(ctx, upgradeName); return getUpgradeLevel(ctx, upgradeName);
}, },
getUpgradeLevelCost: getUpgradeLevelCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgradeName: unknown): number => { (_upgradeName: unknown): number => {
checkAccess(ctx); checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName); const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return getUpgradeLevelCost(ctx, upgradeName); return getUpgradeLevelCost(ctx, upgradeName);
}, },
getExpandIndustryCost: getExpandIndustryCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_industryName: unknown): number => { (_industryName: unknown): number => {
checkAccess(ctx); checkAccess(ctx);
const industryName = ctx.helper.string("industryName", _industryName); const industryName = helpers.string(ctx, "industryName", _industryName);
return getExpandIndustryCost(industryName); return getExpandIndustryCost(industryName);
}, },
getExpandCityCost: (ctx: NetscriptContext) => (): number => { getExpandCityCost: (ctx: NetscriptContext) => (): number => {
@ -1013,29 +1030,29 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_numShares: unknown): boolean => { (_numShares: unknown): boolean => {
checkAccess(ctx); checkAccess(ctx);
const numShares = ctx.helper.number("numShares", _numShares); const numShares = helpers.number(ctx, "numShares", _numShares);
return goPublic(numShares); return goPublic(numShares);
}, },
sellShares: sellShares:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_numShares: unknown): number => { (_numShares: unknown): number => {
checkAccess(ctx); checkAccess(ctx);
const numShares = ctx.helper.number("numShares", _numShares); const numShares = helpers.number(ctx, "numShares", _numShares);
return SellShares(getCorporation(), player, numShares); return SellShares(getCorporation(), player, numShares);
}, },
buyBackShares: buyBackShares:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_numShares: unknown): boolean => { (_numShares: unknown): boolean => {
checkAccess(ctx); checkAccess(ctx);
const numShares = ctx.helper.number("numShares", _numShares); const numShares = helpers.number(ctx, "numShares", _numShares);
return BuyBackShares(getCorporation(), player, numShares); return BuyBackShares(getCorporation(), player, numShares);
}, },
bribe: bribe:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_factionName: unknown, _amountCash: unknown): boolean => { (_factionName: unknown, _amountCash: unknown): boolean => {
checkAccess(ctx); checkAccess(ctx);
const factionName = ctx.helper.string("factionName", _factionName); const factionName = helpers.string(ctx, "factionName", _factionName);
const amountCash = ctx.helper.number("amountCash", _amountCash); const amountCash = helpers.number(ctx, "amountCash", _amountCash);
return bribe(factionName, amountCash); return bribe(factionName, amountCash);
}, },
getBonusTime: (ctx: NetscriptContext) => (): number => { getBonusTime: (ctx: NetscriptContext) => (): number => {

@ -1,8 +1,9 @@
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { Exploit } from "../Exploits/Exploit"; import { Exploit } from "../Exploits/Exploit";
import * as bcrypt from "bcryptjs"; import * as bcrypt from "bcryptjs";
import { Apr1Events as devMenu } from "../ui/Apr1"; import { Apr1Events as devMenu } from "../ui/Apr1";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export interface INetscriptExtra { export interface INetscriptExtra {
heart: { heart: {
@ -15,7 +16,7 @@ export interface INetscriptExtra {
rainbow(guess: string): void; rainbow(guess: string): void;
} }
export function NetscriptExtra(player: IPlayer): InternalAPI<INetscriptExtra> { export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
return { return {
heart: { heart: {
// Easter egg function // Easter egg function
@ -67,7 +68,7 @@ export function NetscriptExtra(player: IPlayer): InternalAPI<INetscriptExtra> {
function tryGuess(): boolean { function tryGuess(): boolean {
// eslint-disable-next-line no-sync // eslint-disable-next-line no-sync
const verified = bcrypt.compareSync( const verified = bcrypt.compareSync(
ctx.helper.string("guess", guess), helpers.string(ctx, "guess", guess),
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO", "$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO",
); );
if (verified) { if (verified) {

@ -1,41 +1,42 @@
import { toNative } from "./toNative"; import { toNative } from "./toNative";
import libarg from "arg"; import libarg from "arg";
import { ScriptArg } from "../Netscript/ScriptArg"; import { ScriptArg } from "../Netscript/ScriptArg";
import { NetscriptContext } from "../Netscript/APIWrapper";
type FlagType = StringConstructor | NumberConstructor | BooleanConstructor | StringConstructor[]; type FlagType = StringConstructor | NumberConstructor | BooleanConstructor | StringConstructor[];
type FlagsRet = { [key: string]: ScriptArg }; type FlagsRet = { [key: string]: ScriptArg };
export function Flags(vargs: string[]): () => (data: unknown) => FlagsRet { export function Flags(ctx: NetscriptContext | string[]): (data: unknown) => FlagsRet {
return (/* ctx: NetscriptContext */) => const vargs = Array.isArray(ctx) ? ctx : ctx.workerScript.args;
(schema: unknown): FlagsRet => { return (schema: unknown): FlagsRet => {
schema = toNative(schema); schema = toNative(schema);
if (!Array.isArray(schema)) throw new Error("flags schema passed in is invalid."); if (!Array.isArray(schema)) throw new Error("flags schema passed in is invalid.");
const args: { const args: {
[key: string]: FlagType; [key: string]: FlagType;
} = {}; } = {};
for (const d of schema) { for (const d of schema) {
let t: FlagType = String; let t: FlagType = 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 ret: FlagsRet = libarg(args, { argv: vargs }); const numDashes = d[0].length > 1 ? 2 : 1;
for (const d of schema) { args["-".repeat(numDashes) + d[0]] = t;
if (!ret.hasOwnProperty("--" + d[0]) || !ret.hasOwnProperty("-" + d[0])) ret[d[0]] = d[1]; }
} const ret: FlagsRet = libarg(args, { argv: vargs });
for (const key of Object.keys(ret)) { for (const d of schema) {
if (!key.startsWith("-")) continue; if (!ret.hasOwnProperty("--" + d[0]) || !ret.hasOwnProperty("-" + d[0])) ret[d[0]] = d[1];
const value = ret[key]; }
delete ret[key]; for (const key of Object.keys(ret)) {
const numDashes = key.length === 2 ? 1 : 2; if (!key.startsWith("-")) continue;
ret[key.slice(numDashes)] = value; const value = ret[key];
} delete ret[key];
return ret; const numDashes = key.length === 2 ? 1 : 2;
}; ret[key.slice(numDashes)] = value;
}
return ret;
};
} }

@ -1,5 +1,4 @@
import { INetscriptHelper } from "./INetscriptHelper"; import { Player as player } from "../Player";
import { IPlayer } from "../PersonObjects/IPlayer";
import { calculateServerGrowth } from "../Server/formulas/grow"; import { calculateServerGrowth } from "../Server/formulas/grow";
import { import {
calculateMoneyGainRate, calculateMoneyGainRate,
@ -43,11 +42,12 @@ import {
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"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): InternalAPI<IFormulas> { export function NetscriptFormulas(): InternalAPI<IFormulas> {
const checkFormulasAccess = function (ctx: NetscriptContext): void { const checkFormulasAccess = function (ctx: NetscriptContext): void {
if (!player.hasProgram(Programs.Formulas.name)) { if (!player.hasProgram(Programs.Formulas.name)) {
throw helper.makeRuntimeErrorMsg(`formulas.${ctx.function}`, `Requires Formulas.exe to run.`); throw helpers.makeRuntimeErrorMsg(ctx, `Requires Formulas.exe to run.`);
} }
}; };
return { return {
@ -55,22 +55,22 @@ export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): In
calculateFavorToRep: calculateFavorToRep:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_favor: unknown): number => { (_favor: unknown): number => {
const favor = ctx.helper.number("favor", _favor); const favor = helpers.number(ctx, "favor", _favor);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateFavorToRep(favor); return calculateFavorToRep(favor);
}, },
calculateRepToFavor: calculateRepToFavor:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_rep: unknown): number => { (_rep: unknown): number => {
const rep = ctx.helper.number("rep", _rep); const rep = helpers.number(ctx, "rep", _rep);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateRepToFavor(rep); return calculateRepToFavor(rep);
}, },
repFromDonation: repFromDonation:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_amount: unknown, _player: unknown): number => { (_amount: unknown, _player: unknown): number => {
const amount = ctx.helper.number("amount", _amount); const amount = helpers.number(ctx, "amount", _amount);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return repFromDonation(amount, player); return repFromDonation(amount, player);
}, },
@ -79,16 +79,16 @@ export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): In
calculateSkill: calculateSkill:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_exp: unknown, _mult: unknown = 1): number => { (_exp: unknown, _mult: unknown = 1): number => {
const exp = ctx.helper.number("exp", _exp); const exp = helpers.number(ctx, "exp", _exp);
const mult = ctx.helper.number("mult", _mult); const mult = helpers.number(ctx, "mult", _mult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateSkill(exp, mult); return calculateSkill(exp, mult);
}, },
calculateExp: calculateExp:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_skill: unknown, _mult: unknown = 1): number => { (_skill: unknown, _mult: unknown = 1): number => {
const skill = ctx.helper.number("skill", _skill); const skill = helpers.number(ctx, "skill", _skill);
const mult = ctx.helper.number("mult", _mult); const mult = helpers.number(ctx, "mult", _mult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateExp(skill, mult); return calculateExp(skill, mult);
}, },
@ -97,58 +97,58 @@ export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): In
hackChance: hackChance:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _player: unknown): number => { (_server: unknown, _player: unknown): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateHackingChance(server, player); return calculateHackingChance(server, player);
}, },
hackExp: hackExp:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _player: unknown): number => { (_server: unknown, _player: unknown): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateHackingExpGain(server, player); return calculateHackingExpGain(server, player);
}, },
hackPercent: hackPercent:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _player: unknown): number => { (_server: unknown, _player: unknown): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculatePercentMoneyHacked(server, player); return calculatePercentMoneyHacked(server, player);
}, },
growPercent: growPercent:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _threads: unknown, _player: unknown, _cores: unknown = 1): number => { (_server: unknown, _threads: unknown, _player: unknown, _cores: unknown = 1): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
const threads = ctx.helper.number("threads", _threads); const threads = helpers.number(ctx, "threads", _threads);
const cores = ctx.helper.number("cores", _cores); const cores = helpers.number(ctx, "cores", _cores);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateServerGrowth(server, threads, player, cores); return calculateServerGrowth(server, threads, player, cores);
}, },
hackTime: hackTime:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _player: unknown): number => { (_server: unknown, _player: unknown): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateHackingTime(server, player) * 1000; return calculateHackingTime(server, player) * 1000;
}, },
growTime: growTime:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _player: unknown): number => { (_server: unknown, _player: unknown): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateGrowTime(server, player) * 1000; return calculateGrowTime(server, player) * 1000;
}, },
weakenTime: weakenTime:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_server: unknown, _player: unknown): number => { (_server: unknown, _player: unknown): number => {
const server = ctx.helper.server(_server); const server = helpers.server(ctx, _server);
const player = ctx.helper.player(_player); const player = helpers.player(ctx, _player);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateWeakenTime(server, player) * 1000; return calculateWeakenTime(server, player) * 1000;
}, },
@ -157,45 +157,45 @@ export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): In
moneyGainRate: moneyGainRate:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_level: unknown, _ram: unknown, _cores: unknown, _mult: unknown = 1): number => { (_level: unknown, _ram: unknown, _cores: unknown, _mult: unknown = 1): number => {
const level = ctx.helper.number("level", _level); const level = helpers.number(ctx, "level", _level);
const ram = ctx.helper.number("ram", _ram); const ram = helpers.number(ctx, "ram", _ram);
const cores = ctx.helper.number("cores", _cores); const cores = helpers.number(ctx, "cores", _cores);
const mult = ctx.helper.number("mult", _mult); const mult = helpers.number(ctx, "mult", _mult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateMoneyGainRate(level, ram, cores, mult); return calculateMoneyGainRate(level, ram, cores, mult);
}, },
levelUpgradeCost: levelUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => { (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
const startingLevel = ctx.helper.number("startingLevel", _startingLevel); const startingLevel = helpers.number(ctx, "startingLevel", _startingLevel);
const extraLevels = ctx.helper.number("extraLevels", _extraLevels); const extraLevels = helpers.number(ctx, "extraLevels", _extraLevels);
const costMult = ctx.helper.number("costMult", _costMult); const costMult = helpers.number(ctx, "costMult", _costMult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateLevelUpgradeCost(startingLevel, extraLevels, costMult); return calculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
}, },
ramUpgradeCost: ramUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => { (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
const startingRam = ctx.helper.number("startingRam", _startingRam); const startingRam = helpers.number(ctx, "startingRam", _startingRam);
const extraLevels = ctx.helper.number("extraLevels", _extraLevels); const extraLevels = helpers.number(ctx, "extraLevels", _extraLevels);
const costMult = ctx.helper.number("costMult", _costMult); const costMult = helpers.number(ctx, "costMult", _costMult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateRamUpgradeCost(startingRam, extraLevels, costMult); return calculateRamUpgradeCost(startingRam, extraLevels, costMult);
}, },
coreUpgradeCost: coreUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number => { (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number => {
const startingCore = ctx.helper.number("startingCore", _startingCore); const startingCore = helpers.number(ctx, "startingCore", _startingCore);
const extraCores = ctx.helper.number("extraCores", _extraCores); const extraCores = helpers.number(ctx, "extraCores", _extraCores);
const costMult = ctx.helper.number("costMult", _costMult); const costMult = helpers.number(ctx, "costMult", _costMult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateCoreUpgradeCost(startingCore, extraCores, costMult); return calculateCoreUpgradeCost(startingCore, extraCores, costMult);
}, },
hacknetNodeCost: hacknetNodeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_n: unknown, _mult: unknown): number => { (_n: unknown, _mult: unknown): number => {
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const mult = ctx.helper.number("mult", _mult); const mult = helpers.number(ctx, "mult", _mult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateNodeCost(n, mult); return calculateNodeCost(n, mult);
}, },
@ -208,69 +208,66 @@ export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): In
hashGainRate: hashGainRate:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_level: unknown, _ramUsed: unknown, _maxRam: unknown, _cores: unknown, _mult: unknown = 1): number => { (_level: unknown, _ramUsed: unknown, _maxRam: unknown, _cores: unknown, _mult: unknown = 1): number => {
const level = ctx.helper.number("level", _level); const level = helpers.number(ctx, "level", _level);
const ramUsed = ctx.helper.number("ramUsed", _ramUsed); const ramUsed = helpers.number(ctx, "ramUsed", _ramUsed);
const maxRam = ctx.helper.number("maxRam", _maxRam); const maxRam = helpers.number(ctx, "maxRam", _maxRam);
const cores = ctx.helper.number("cores", _cores); const cores = helpers.number(ctx, "cores", _cores);
const mult = ctx.helper.number("mult", _mult); const mult = helpers.number(ctx, "mult", _mult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult); return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult);
}, },
levelUpgradeCost: levelUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => { (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
const startingLevel = ctx.helper.number("startingLevel", _startingLevel); const startingLevel = helpers.number(ctx, "startingLevel", _startingLevel);
const extraLevels = ctx.helper.number("extraLevels", _extraLevels); const extraLevels = helpers.number(ctx, "extraLevels", _extraLevels);
const costMult = ctx.helper.number("costMult", _costMult); const costMult = helpers.number(ctx, "costMult", _costMult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return HScalculateLevelUpgradeCost(startingLevel, extraLevels, costMult); return HScalculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
}, },
ramUpgradeCost: ramUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => { (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number => {
const startingRam = ctx.helper.number("startingRam", _startingRam); const startingRam = helpers.number(ctx, "startingRam", _startingRam);
const extraLevels = ctx.helper.number("extraLevels", _extraLevels); const extraLevels = helpers.number(ctx, "extraLevels", _extraLevels);
const costMult = ctx.helper.number("costMult", _costMult); const costMult = helpers.number(ctx, "costMult", _costMult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return HScalculateRamUpgradeCost(startingRam, extraLevels, costMult); return HScalculateRamUpgradeCost(startingRam, extraLevels, costMult);
}, },
coreUpgradeCost: coreUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number => { (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number => {
const startingCore = ctx.helper.number("startingCore", _startingCore); const startingCore = helpers.number(ctx, "startingCore", _startingCore);
const extraCores = ctx.helper.number("extraCores", _extraCores); const extraCores = helpers.number(ctx, "extraCores", _extraCores);
const costMult = ctx.helper.number("costMult", _costMult); const costMult = helpers.number(ctx, "costMult", _costMult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return HScalculateCoreUpgradeCost(startingCore, extraCores, costMult); return HScalculateCoreUpgradeCost(startingCore, extraCores, costMult);
}, },
cacheUpgradeCost: cacheUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_startingCache: unknown, _extraCache: unknown = 1): number => { (_startingCache: unknown, _extraCache: unknown = 1): number => {
const startingCache = ctx.helper.number("startingCache", _startingCache); const startingCache = helpers.number(ctx, "startingCache", _startingCache);
const extraCache = ctx.helper.number("extraCache", _extraCache); const extraCache = helpers.number(ctx, "extraCache", _extraCache);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return HScalculateCacheUpgradeCost(startingCache, extraCache); return HScalculateCacheUpgradeCost(startingCache, extraCache);
}, },
hashUpgradeCost: hashUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgName: unknown, _level: unknown): number => { (_upgName: unknown, _level: unknown): number => {
const upgName = helper.string("hashUpgradeCost", "upgName", _upgName); const upgName = helpers.string(ctx, "upgName", _upgName);
const level = ctx.helper.number("level", _level); const level = helpers.number(ctx, "level", _level);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
const upg = player.hashManager.getUpgrade(upgName); const upg = player.hashManager.getUpgrade(upgName);
if (!upg) { if (!upg) {
throw helper.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(ctx, `Invalid Hash Upgrade: ${upgName}`);
"formulas.hacknetServers.calculateHashUpgradeCost",
`Invalid Hash Upgrade: ${upgName}`,
);
} }
return upg.getCost(level); return upg.getCost(level);
}, },
hacknetServerCost: hacknetServerCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_n: unknown, _mult: unknown = 1): number => { (_n: unknown, _mult: unknown = 1): number => {
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const mult = ctx.helper.number("mult", _mult); const mult = helpers.number(ctx, "mult", _mult);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return HScalculateServerCost(n, mult); return HScalculateServerCost(n, mult);
}, },
@ -283,48 +280,48 @@ export function NetscriptFormulas(player: IPlayer, helper: INetscriptHelper): In
wantedPenalty: wantedPenalty:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_gang: unknown): number => { (_gang: unknown): number => {
const gang = ctx.helper.gang(_gang); const gang = helpers.gang(ctx, _gang);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateWantedPenalty(gang); return calculateWantedPenalty(gang);
}, },
respectGain: respectGain:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_gang: unknown, _member: unknown, _task: unknown): number => { (_gang: unknown, _member: unknown, _task: unknown): number => {
const gang = ctx.helper.gang(_gang); const gang = helpers.gang(ctx, _gang);
const member = ctx.helper.gangMember(_member); const member = helpers.gangMember(ctx, _member);
const task = ctx.helper.gangTask(_task); const task = helpers.gangTask(ctx, _task);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateRespectGain(gang, member, task); return calculateRespectGain(gang, member, task);
}, },
wantedLevelGain: wantedLevelGain:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_gang: unknown, _member: unknown, _task: unknown): number => { (_gang: unknown, _member: unknown, _task: unknown): number => {
const gang = ctx.helper.gang(_gang); const gang = helpers.gang(ctx, _gang);
const member = ctx.helper.gangMember(_member); const member = helpers.gangMember(ctx, _member);
const task = ctx.helper.gangTask(_task); const task = helpers.gangTask(ctx, _task);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateWantedLevelGain(gang, member, task); return calculateWantedLevelGain(gang, member, task);
}, },
moneyGain: moneyGain:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_gang: unknown, _member: unknown, _task: unknown): number => { (_gang: unknown, _member: unknown, _task: unknown): number => {
const gang = ctx.helper.gang(_gang); const gang = helpers.gang(ctx, _gang);
const member = ctx.helper.gangMember(_member); const member = helpers.gangMember(ctx, _member);
const task = ctx.helper.gangTask(_task); const task = helpers.gangTask(ctx, _task);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateMoneyGain(gang, member, task); return calculateMoneyGain(gang, member, task);
}, },
ascensionPointsGain: ascensionPointsGain:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_exp: unknown): number => { (_exp: unknown): number => {
const exp = ctx.helper.number("exp", _exp); const exp = helpers.number(ctx, "exp", _exp);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateAscensionPointsGain(exp); return calculateAscensionPointsGain(exp);
}, },
ascensionMultiplier: ascensionMultiplier:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_points: unknown): number => { (_points: unknown): number => {
const points = ctx.helper.number("points", _points); const points = helpers.number(ctx, "points", _points);
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
return calculateAscensionMult(points); return calculateAscensionMult(points);
}, },

@ -1,13 +1,13 @@
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { GangConstants } from "../Gang/data/Constants"; import { GangConstants } from "../Gang/data/Constants";
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { Gang } from "../Gang/Gang"; import { Gang } from "../Gang/Gang";
import { AllGangs } from "../Gang/AllGangs"; import { AllGangs } from "../Gang/AllGangs";
import { GangMemberTasks } from "../Gang/GangMemberTasks"; import { GangMemberTasks } from "../Gang/GangMemberTasks";
import { GangMemberUpgrades } from "../Gang/GangMemberUpgrades"; import { GangMemberUpgrades } from "../Gang/GangMemberUpgrades";
import { WorkerScript } from "../Netscript/WorkerScript";
import { GangMember } from "../Gang/GangMember"; import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask"; import { GangMemberTask } from "../Gang/GangMemberTask";
import { helpers } from "../Netscript/NetscriptHelpers";
import { import {
Gang as IGang, Gang as IGang,
@ -21,13 +21,13 @@ import {
} from "../ScriptEditor/NetscriptDefinitions"; } from "../ScriptEditor/NetscriptDefinitions";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): InternalAPI<IGang> { export function NetscriptGang(): InternalAPI<IGang> {
const checkGangApiAccess = function (ctx: NetscriptContext): void { const checkGangApiAccess = function (ctx: NetscriptContext): void {
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Must have joined gang"); if (gang === null) throw new Error("Must have joined gang");
const hasAccess = gang instanceof Gang; const hasAccess = gang instanceof Gang;
if (!hasAccess) { if (!hasAccess) {
throw ctx.makeRuntimeErrorMsg(`You do not currently have a Gang`); throw helpers.makeRuntimeErrorMsg(ctx, `You do not currently have a Gang`);
} }
}; };
@ -35,13 +35,13 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Must have joined gang"); if (gang === null) throw new Error("Must have joined gang");
for (const member of gang.members) if (member.name === name) return member; for (const member of gang.members) if (member.name === name) return member;
throw ctx.makeRuntimeErrorMsg(`Invalid gang member: '${name}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid gang member: '${name}'`);
}; };
const getGangTask = function (ctx: NetscriptContext, name: string): GangMemberTask { const getGangTask = function (ctx: NetscriptContext, name: string): GangMemberTask {
const task = GangMemberTasks[name]; const task = GangMemberTasks[name];
if (!task) { if (!task) {
throw ctx.makeRuntimeErrorMsg(`Invalid task: '${name}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid task: '${name}'`);
} }
return task; return task;
@ -51,7 +51,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
createGang: createGang:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_faction: unknown): boolean => { (_faction: unknown): boolean => {
const faction = ctx.helper.string("faction", _faction); const faction = helpers.string(ctx, "faction", _faction);
// this list is copied from Faction/ui/Root.tsx // this list is copied from Faction/ui/Root.tsx
if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false; if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false;
@ -102,7 +102,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
getMemberInformation: getMemberInformation:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_memberName: unknown): GangMemberInfo => { (_memberName: unknown): GangMemberInfo => {
const memberName = ctx.helper.string("memberName", _memberName); const memberName = helpers.string(ctx, "memberName", _memberName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
@ -163,15 +163,15 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
recruitMember: recruitMember:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_memberName: unknown): boolean => { (_memberName: unknown): boolean => {
const memberName = ctx.helper.string("memberName", _memberName); const memberName = helpers.string(ctx, "memberName", _memberName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
const recruited = gang.recruitMember(memberName); const recruited = gang.recruitMember(memberName);
if (recruited) { if (recruited) {
workerScript.log("gang.recruitMember", () => `Successfully recruited Gang Member '${memberName}'`); ctx.workerScript.log("gang.recruitMember", () => `Successfully recruited Gang Member '${memberName}'`);
} else { } else {
workerScript.log("gang.recruitMember", () => `Failed to recruit Gang Member '${memberName}'`); ctx.workerScript.log("gang.recruitMember", () => `Failed to recruit Gang Member '${memberName}'`);
} }
return recruited; return recruited;
@ -187,14 +187,14 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
setMemberTask: setMemberTask:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_memberName: unknown, _taskName: unknown): boolean => { (_memberName: unknown, _taskName: unknown): boolean => {
const memberName = ctx.helper.string("memberName", _memberName); const memberName = helpers.string(ctx, "memberName", _memberName);
const taskName = ctx.helper.string("taskName", _taskName); const taskName = helpers.string(ctx, "taskName", _taskName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const member = getGangMember(ctx, memberName); const member = getGangMember(ctx, memberName);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
if (!gang.getAllTaskNames().includes(taskName)) { if (!gang.getAllTaskNames().includes(taskName)) {
workerScript.log( ctx.workerScript.log(
"gang.setMemberTask", "gang.setMemberTask",
() => () =>
`Failed to assign Gang Member '${memberName}' to Invalid task '${taskName}'. '${memberName}' is now Unassigned`, `Failed to assign Gang Member '${memberName}' to Invalid task '${taskName}'. '${memberName}' is now Unassigned`,
@ -203,12 +203,12 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
} }
const success = member.assignToTask(taskName); const success = member.assignToTask(taskName);
if (success) { if (success) {
workerScript.log( ctx.workerScript.log(
"gang.setMemberTask", "gang.setMemberTask",
() => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`, () => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`,
); );
} else { } else {
workerScript.log( ctx.workerScript.log(
"gang.setMemberTask", "gang.setMemberTask",
() => () =>
`Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`, `Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`,
@ -220,7 +220,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
getTaskStats: getTaskStats:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_taskName: unknown): GangTaskStats => { (_taskName: unknown): GangTaskStats => {
const taskName = ctx.helper.string("taskName", _taskName); const taskName = helpers.string(ctx, "taskName", _taskName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const task = getGangTask(ctx, taskName); const task = getGangTask(ctx, taskName);
const copy = Object.assign({}, task); const copy = Object.assign({}, task);
@ -234,7 +234,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
getEquipmentCost: getEquipmentCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_equipName: unknown): number => { (_equipName: unknown): number => {
const equipName = ctx.helper.string("equipName", _equipName); const equipName = helpers.string(ctx, "equipName", _equipName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
@ -245,7 +245,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
getEquipmentType: getEquipmentType:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_equipName: unknown): string => { (_equipName: unknown): string => {
const equipName = ctx.helper.string("equipName", _equipName); const equipName = helpers.string(ctx, "equipName", _equipName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const upg = GangMemberUpgrades[equipName]; const upg = GangMemberUpgrades[equipName];
if (upg == null) return ""; if (upg == null) return "";
@ -254,11 +254,11 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
getEquipmentStats: getEquipmentStats:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_equipName: unknown): EquipmentStats => { (_equipName: unknown): EquipmentStats => {
const equipName = ctx.helper.string("equipName", _equipName); const equipName = helpers.string(ctx, "equipName", _equipName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const equipment = GangMemberUpgrades[equipName]; const equipment = GangMemberUpgrades[equipName];
if (!equipment) { if (!equipment) {
throw ctx.makeRuntimeErrorMsg(`Invalid equipment: ${equipName}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid equipment: ${equipName}`);
} }
const typecheck: EquipmentStats = equipment.mults; const typecheck: EquipmentStats = equipment.mults;
return Object.assign({}, typecheck) as any; return Object.assign({}, typecheck) as any;
@ -266,8 +266,8 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
purchaseEquipment: purchaseEquipment:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_memberName: unknown, _equipName: unknown): boolean => { (_memberName: unknown, _equipName: unknown): boolean => {
const memberName = ctx.helper.string("memberName", _memberName); const memberName = helpers.string(ctx, "memberName", _memberName);
const equipName = ctx.helper.string("equipName", _equipName); const equipName = helpers.string(ctx, "equipName", _equipName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
@ -276,9 +276,12 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
if (!equipment) return false; if (!equipment) return false;
const res = member.buyUpgrade(equipment, player, gang); const res = member.buyUpgrade(equipment, player, gang);
if (res) { if (res) {
workerScript.log("gang.purchaseEquipment", () => `Purchased '${equipName}' for Gang member '${memberName}'`); ctx.workerScript.log(
"gang.purchaseEquipment",
() => `Purchased '${equipName}' for Gang member '${memberName}'`,
);
} else { } else {
workerScript.log( ctx.workerScript.log(
"gang.purchaseEquipment", "gang.purchaseEquipment",
() => `Failed to purchase '${equipName}' for Gang member '${memberName}'`, () => `Failed to purchase '${equipName}' for Gang member '${memberName}'`,
); );
@ -289,18 +292,18 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
ascendMember: ascendMember:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_memberName: unknown): GangMemberAscension | undefined => { (_memberName: unknown): GangMemberAscension | undefined => {
const memberName = ctx.helper.string("memberName", _memberName); const memberName = helpers.string(ctx, "memberName", _memberName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
const member = getGangMember(ctx, memberName); const member = getGangMember(ctx, memberName);
if (!member.canAscend()) return; if (!member.canAscend()) return;
return gang.ascendMember(member, workerScript); return gang.ascendMember(member, ctx.workerScript);
}, },
getAscensionResult: getAscensionResult:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_memberName: unknown): GangMemberAscension | undefined => { (_memberName: unknown): GangMemberAscension | undefined => {
const memberName = ctx.helper.string("memberName", _memberName); const memberName = helpers.string(ctx, "memberName", _memberName);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
@ -314,27 +317,27 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): Inte
setTerritoryWarfare: setTerritoryWarfare:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_engage: unknown): void => { (_engage: unknown): void => {
const engage = ctx.helper.boolean(_engage); const engage = !!_engage;
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
if (engage) { if (engage) {
gang.territoryWarfareEngaged = true; gang.territoryWarfareEngaged = true;
workerScript.log("gang.setTerritoryWarfare", () => "Engaging in Gang Territory Warfare"); ctx.workerScript.log("gang.setTerritoryWarfare", () => "Engaging in Gang Territory Warfare");
} else { } else {
gang.territoryWarfareEngaged = false; gang.territoryWarfareEngaged = false;
workerScript.log("gang.setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare"); ctx.workerScript.log("gang.setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare");
} }
}, },
getChanceToWinClash: getChanceToWinClash:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_otherGang: unknown): number => { (_otherGang: unknown): number => {
const otherGang = ctx.helper.string("otherGang", _otherGang); const otherGang = helpers.string(ctx, "otherGang", _otherGang);
checkGangApiAccess(ctx); checkGangApiAccess(ctx);
const gang = player.gang; const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
if (AllGangs[otherGang] == null) { if (AllGangs[otherGang] == null) {
throw ctx.makeRuntimeErrorMsg(`Invalid gang: ${otherGang}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid gang: ${otherGang}`);
} }
const playerPower = AllGangs[gang.facName].power; const playerPower = AllGangs[gang.facName].power;

@ -4,15 +4,17 @@ import { hasAugmentationPrereqs } from "../Faction/FactionHelpers";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation"; import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation";
import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../PersonObjects/Grafting/GraftingHelpers"; import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../PersonObjects/Grafting/GraftingHelpers";
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions"; import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { GraftingWork } from "../Work/GraftingWork"; import { GraftingWork } from "../Work/GraftingWork";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> { export function NetscriptGrafting(): InternalAPI<IGrafting> {
const checkGraftingAPIAccess = (ctx: NetscriptContext): void => { const checkGraftingAPIAccess = (ctx: NetscriptContext): void => {
if (!player.canAccessGrafting()) { if (!player.canAccessGrafting()) {
throw ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
"You do not currently have access to the Grafting API. This is either because you are not in BitNode 10 or because you do not have Source-File 10", "You do not currently have access to the Grafting API. This is either because you are not in BitNode 10 or because you do not have Source-File 10",
); );
} }
@ -22,10 +24,10 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
getAugmentationGraftPrice: getAugmentationGraftPrice:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_augName: unknown): number => { (_augName: unknown): number => {
const augName = ctx.helper.string("augName", _augName); const augName = helpers.string(ctx, "augName", _augName);
checkGraftingAPIAccess(ctx); checkGraftingAPIAccess(ctx);
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
} }
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]); const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
return graftableAug.cost; return graftableAug.cost;
@ -34,10 +36,10 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
getAugmentationGraftTime: getAugmentationGraftTime:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_augName: string): number => { (_augName: string): number => {
const augName = ctx.helper.string("augName", _augName); const augName = helpers.string(ctx, "augName", _augName);
checkGraftingAPIAccess(ctx); checkGraftingAPIAccess(ctx);
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
} }
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]); const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
return calculateGraftingTimeWithBonus(player, graftableAug); return calculateGraftingTimeWithBonus(player, graftableAug);
@ -52,14 +54,14 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
graftAugmentation: graftAugmentation:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_augName: string, _focus: unknown = true): boolean => { (_augName: string, _focus: unknown = true): boolean => {
const augName = ctx.helper.string("augName", _augName); const augName = helpers.string(ctx, "augName", _augName);
const focus = ctx.helper.boolean(_focus); const focus = !!_focus;
checkGraftingAPIAccess(ctx); checkGraftingAPIAccess(ctx);
if (player.city !== CityName.NewTokyo) { if (player.city !== CityName.NewTokyo) {
throw ctx.makeRuntimeErrorMsg("You must be in New Tokyo to begin grafting an Augmentation."); throw helpers.makeRuntimeErrorMsg(ctx, "You must be in New Tokyo to begin grafting an Augmentation.");
} }
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
ctx.log(() => `Invalid aug: ${augName}`); helpers.log(ctx, () => `Invalid aug: ${augName}`);
return false; return false;
} }
@ -67,12 +69,12 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]); const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
if (player.money < craftableAug.cost) { if (player.money < craftableAug.cost) {
ctx.log(() => `You don't have enough money to craft ${augName}`); helpers.log(ctx, () => `You don't have enough money to craft ${augName}`);
return false; return false;
} }
if (!hasAugmentationPrereqs(craftableAug.augmentation)) { if (!hasAugmentationPrereqs(craftableAug.augmentation)) {
ctx.log(() => `You don't have the pre-requisites for ${augName}`); helpers.log(ctx, () => `You don't have the pre-requisites for ${augName}`);
return false; return false;
} }
@ -92,7 +94,7 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
Router.toTerminal(); Router.toTerminal();
} }
ctx.log(() => `Began grafting Augmentation ${augName}.`); helpers.log(ctx, () => `Began grafting Augmentation ${augName}.`);
return true; return true;
}, },
}; };

@ -1,5 +1,4 @@
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { WorkerScript } from "../Netscript/WorkerScript";
import { HacknetServerConstants } from "../Hacknet/data/Constants"; import { HacknetServerConstants } from "../Hacknet/data/Constants";
import { import {
getCostOfNextHacknetNode, getCostOfNextHacknetNode,
@ -21,12 +20,13 @@ import { GetServer } from "../Server/AllServers";
import { Hacknet as IHacknet, NodeStats } from "../ScriptEditor/NetscriptDefinitions"; import { Hacknet as IHacknet, NodeStats } from "../ScriptEditor/NetscriptDefinitions";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): InternalAPI<IHacknet> { export function NetscriptHacknet(): InternalAPI<IHacknet> {
// Utility function to get Hacknet Node object // Utility function to get Hacknet Node object
const getHacknetNode = function (ctx: NetscriptContext, i: number): HacknetNode | HacknetServer { const getHacknetNode = function (ctx: NetscriptContext, i: number): HacknetNode | HacknetServer {
if (i < 0 || i >= player.hacknetNodes.length) { if (i < 0 || i >= player.hacknetNodes.length) {
throw ctx.makeRuntimeErrorMsg("Index specified for Hacknet Node is out-of-bounds: " + i); throw helpers.makeRuntimeErrorMsg(ctx, "Index specified for Hacknet Node is out-of-bounds: " + i);
} }
if (hasHacknetServers(player)) { if (hasHacknetServers(player)) {
@ -35,7 +35,8 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
const hserver = GetServer(hi); const hserver = GetServer(hi);
if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server"); if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server");
if (hserver == null) { if (hserver == null) {
throw ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
`Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`, `Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`,
); );
} }
@ -71,7 +72,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
getNodeStats: getNodeStats:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown): NodeStats => { (_i: unknown): NodeStats => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
const hasUpgraded = hasHacknetServers(player); const hasUpgraded = hasHacknetServers(player);
const res: NodeStats = { const res: NodeStats = {
@ -95,38 +96,38 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
upgradeLevel: upgradeLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => { (_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
return purchaseLevelUpgrade(player, node, n); return purchaseLevelUpgrade(player, node, n);
}, },
upgradeRam: upgradeRam:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => { (_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
return purchaseRamUpgrade(player, node, n); return purchaseRamUpgrade(player, node, n);
}, },
upgradeCore: upgradeCore:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => { (_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
return purchaseCoreUpgrade(player, node, n); return purchaseCoreUpgrade(player, node, n);
}, },
upgradeCache: upgradeCache:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => { (_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
if (!hasHacknetServers(player)) { if (!hasHacknetServers(player)) {
return false; return false;
} }
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
if (!(node instanceof HacknetServer)) { if (!(node instanceof HacknetServer)) {
workerScript.log("hacknet.upgradeCache", () => "Can only be called on hacknet servers"); helpers.log(ctx, () => "Can only be called on hacknet servers");
return false; return false;
} }
const res = purchaseCacheUpgrade(player, node, n); const res = purchaseCacheUpgrade(player, node, n);
@ -138,38 +139,38 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
getLevelUpgradeCost: getLevelUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => { (_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
return node.calculateLevelUpgradeCost(n, player.mults.hacknet_node_level_cost); return node.calculateLevelUpgradeCost(n, player.mults.hacknet_node_level_cost);
}, },
getRamUpgradeCost: getRamUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => { (_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
return node.calculateRamUpgradeCost(n, player.mults.hacknet_node_ram_cost); return node.calculateRamUpgradeCost(n, player.mults.hacknet_node_ram_cost);
}, },
getCoreUpgradeCost: getCoreUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => { (_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
return node.calculateCoreUpgradeCost(n, player.mults.hacknet_node_core_cost); return node.calculateCoreUpgradeCost(n, player.mults.hacknet_node_core_cost);
}, },
getCacheUpgradeCost: getCacheUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => { (_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i); const i = helpers.number(ctx, "i", _i);
const n = ctx.helper.number("n", _n); const n = helpers.number(ctx, "n", _n);
if (!hasHacknetServers(player)) { if (!hasHacknetServers(player)) {
return Infinity; return Infinity;
} }
const node = getHacknetNode(ctx, i); const node = getHacknetNode(ctx, i);
if (!(node instanceof HacknetServer)) { if (!(node instanceof HacknetServer)) {
workerScript.log("hacknet.getCacheUpgradeCost", () => "Can only be called on hacknet servers"); helpers.log(ctx, () => "Can only be called on hacknet servers");
return -1; return -1;
} }
return node.calculateCacheUpgradeCost(n); return node.calculateCacheUpgradeCost(n);
@ -189,8 +190,8 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
hashCost: hashCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgName: unknown, _count: unknown = 1): number => { (_upgName: unknown, _count: unknown = 1): number => {
const upgName = ctx.helper.string("upgName", _upgName); const upgName = helpers.string(ctx, "upgName", _upgName);
const count = ctx.helper.number("count", _count); const count = helpers.number(ctx, "count", _count);
if (!hasHacknetServers(player)) { if (!hasHacknetServers(player)) {
return Infinity; return Infinity;
} }
@ -200,9 +201,9 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
spendHashes: spendHashes:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgName: unknown, _upgTarget: unknown = "", _count: unknown = 1): boolean => { (_upgName: unknown, _upgTarget: unknown = "", _count: unknown = 1): boolean => {
const upgName = ctx.helper.string("upgName", _upgName); const upgName = helpers.string(ctx, "upgName", _upgName);
const upgTarget = ctx.helper.string("upgTarget", _upgTarget); const upgTarget = helpers.string(ctx, "upgTarget", _upgTarget);
const count = ctx.helper.number("count", _count); const count = helpers.number(ctx, "count", _count);
if (!hasHacknetServers(player)) { if (!hasHacknetServers(player)) {
return false; return false;
} }
@ -217,10 +218,10 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
getHashUpgradeLevel: getHashUpgradeLevel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_upgName: unknown): number => { (_upgName: unknown): number => {
const upgName = ctx.helper.string("upgName", _upgName); const upgName = helpers.string(ctx, "upgName", _upgName);
const level = player.hashManager.upgrades[upgName]; const level = player.hashManager.upgrades[upgName];
if (level === undefined) { if (level === undefined) {
throw ctx.makeRuntimeErrorMsg(`Invalid Hash Upgrade: ${upgName}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid Hash Upgrade: ${upgName}`);
} }
return level; return level;
}, },

@ -1,41 +0,0 @@
import { CityName } from "../Locations/data/CityNames";
import { NetscriptContext } from "../Netscript/APIWrapper";
import { IPort } from "../NetscriptPort";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Server } from "../Server/Server";
import { BaseServer } from "../Server/BaseServer";
import { FormulaGang } from "../Gang/formulas/formulas";
import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask";
import { BasicHGWOptions } from "../ScriptEditor/NetscriptDefinitions";
import { ScriptArg } from "../Netscript/ScriptArg";
export type ScriptIdentifier =
| number
| {
fn: string;
hostname: string;
args: ScriptArg[];
};
export interface INetscriptHelper {
updateDynamicRam(functionName: string, ram: number): void;
makeRuntimeErrorMsg(functionName: string, message: string): string;
string(funcName: string, argName: string, v: unknown): string;
number(funcName: string, argName: string, v: unknown): number;
ustring(funcName: string, argName: string, v: unknown): string | undefined;
unumber(funcName: string, argName: string, v: unknown): number | undefined;
scriptArgs(funcName: string, args: unknown): ScriptArg[];
scriptIdentifier(funcName: string, fn: unknown, hostname: unknown, args: unknown): ScriptIdentifier;
city(funcName: string, argName: string, v: unknown): CityName;
boolean(v: unknown): boolean;
getServer(ip: string, ctx: NetscriptContext): BaseServer;
checkSingularityAccess(func: string): void;
hack(ctx: NetscriptContext, hostname: string, manual: boolean, extra?: BasicHGWOptions): Promise<number>;
getValidPort(funcName: string, port: number): IPort;
player(funcName: string, p: unknown): IPlayer;
server(funcName: string, s: unknown): Server;
gang(funcName: string, g: unknown): FormulaGang;
gangMember(funcName: string, m: unknown): GangMember;
gangTask(funcName: string, m: unknown): GangMemberTask;
}

@ -1,4 +1,4 @@
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { import {
Infiltration as IInfiltration, Infiltration as IInfiltration,
@ -18,8 +18,9 @@ import { Factions } from "../Faction/Factions";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/checkEnum";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptInfiltration(player: IPlayer): InternalAPI<IInfiltration> { export function NetscriptInfiltration(): InternalAPI<IInfiltration> {
const getLocationsWithInfiltrations = Object.values(Locations).filter( const getLocationsWithInfiltrations = Object.values(Locations).filter(
(location: Location) => location.infiltrationData, (location: Location) => location.infiltrationData,
); );
@ -27,9 +28,9 @@ export function NetscriptInfiltration(player: IPlayer): InternalAPI<IInfiltratio
const calculateInfiltrationData = (ctx: NetscriptContext, locationName: string): InfiltrationLocation => { const calculateInfiltrationData = (ctx: NetscriptContext, locationName: string): InfiltrationLocation => {
if (!checkEnum(LocationName, locationName)) throw new Error(`Location '${locationName}' does not exists.`); if (!checkEnum(LocationName, locationName)) throw new Error(`Location '${locationName}' does not exists.`);
const location = Locations[locationName]; const location = Locations[locationName];
if (location === undefined) throw ctx.makeRuntimeErrorMsg(`Location '${location}' does not exists.`); if (location === undefined) throw helpers.makeRuntimeErrorMsg(ctx, `Location '${location}' does not exists.`);
if (location.infiltrationData === undefined) if (location.infiltrationData === undefined)
throw ctx.makeRuntimeErrorMsg(`Location '${location}' does not provide infiltrations.`); throw helpers.makeRuntimeErrorMsg(ctx, `Location '${location}' does not provide infiltrations.`);
const startingSecurityLevel = location.infiltrationData.startingSecurityLevel; const startingSecurityLevel = location.infiltrationData.startingSecurityLevel;
const difficulty = calculateDifficulty(player, startingSecurityLevel); const difficulty = calculateDifficulty(player, startingSecurityLevel);
const reward = calculateReward(player, startingSecurityLevel); const reward = calculateReward(player, startingSecurityLevel);
@ -54,7 +55,7 @@ export function NetscriptInfiltration(player: IPlayer): InternalAPI<IInfiltratio
getInfiltration: getInfiltration:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_location: unknown): InfiltrationLocation => { (_location: unknown): InfiltrationLocation => {
const location = ctx.helper.string("location", _location); const location = helpers.string(ctx, "location", _location);
return calculateInfiltrationData(ctx, location); return calculateInfiltrationData(ctx, location);
}, },
}; };

File diff suppressed because it is too large Load Diff

@ -1,4 +1,4 @@
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player as player } from "../Player";
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers"; import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
import { StaticAugmentations } from "../Augmentation/StaticAugmentations"; import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
@ -17,11 +17,13 @@ import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork"; import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork";
import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork"; import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork";
import { isSleeveCompanyWork } from "../PersonObjects/Sleeve/Work/SleeveCompanyWork"; import { isSleeveCompanyWork } from "../PersonObjects/Sleeve/Work/SleeveCompanyWork";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> { export function NetscriptSleeve(): InternalAPI<ISleeve> {
const checkSleeveAPIAccess = function (ctx: NetscriptContext): void { const checkSleeveAPIAccess = function (ctx: NetscriptContext): void {
if (player.bitNodeN !== 10 && !player.sourceFileLvl(10)) { if (player.bitNodeN !== 10 && !player.sourceFileLvl(10)) {
throw ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
"You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10", "You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10",
); );
} }
@ -30,8 +32,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
const checkSleeveNumber = function (ctx: NetscriptContext, sleeveNumber: number): void { const checkSleeveNumber = function (ctx: NetscriptContext, sleeveNumber: number): void {
if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) { if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) {
const msg = `Invalid sleeve number: ${sleeveNumber}`; const msg = `Invalid sleeve number: ${sleeveNumber}`;
ctx.log(() => msg); helpers.log(ctx, () => msg);
throw ctx.makeRuntimeErrorMsg(msg); throw helpers.makeRuntimeErrorMsg(ctx, msg);
} }
}; };
@ -58,7 +60,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToShockRecovery: setToShockRecovery:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): boolean => { (_sleeveNumber: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].shockRecovery(player); return player.sleeves[sleeveNumber].shockRecovery(player);
@ -66,7 +68,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToSynchronize: setToSynchronize:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): boolean => { (_sleeveNumber: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].synchronize(player); return player.sleeves[sleeveNumber].synchronize(player);
@ -74,8 +76,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToCommitCrime: setToCommitCrime:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _crimeRoughName: unknown): boolean => { (_sleeveNumber: unknown, _crimeRoughName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const crimeRoughName = ctx.helper.string("crimeName", _crimeRoughName); const crimeRoughName = helpers.string(ctx, "crimeName", _crimeRoughName);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
const crime = findCrime(crimeRoughName); const crime = findCrime(crimeRoughName);
@ -87,9 +89,9 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToUniversityCourse: setToUniversityCourse:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _universityName: unknown, _className: unknown): boolean => { (_sleeveNumber: unknown, _universityName: unknown, _className: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const universityName = ctx.helper.string("universityName", _universityName); const universityName = helpers.string(ctx, "universityName", _universityName);
const className = ctx.helper.string("className", _className); const className = helpers.string(ctx, "className", _className);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className); return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
@ -97,21 +99,21 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
travel: travel:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _cityName: unknown): boolean => { (_sleeveNumber: unknown, _cityName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const cityName = ctx.helper.string("cityName", _cityName); const cityName = helpers.string(ctx, "cityName", _cityName);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
if (checkEnum(CityName, cityName)) { if (checkEnum(CityName, cityName)) {
return player.sleeves[sleeveNumber].travel(player, cityName); return player.sleeves[sleeveNumber].travel(player, cityName);
} else { } else {
throw ctx.makeRuntimeErrorMsg(`Invalid city name: '${cityName}'.`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city name: '${cityName}'.`);
} }
}, },
setToCompanyWork: setToCompanyWork:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, acompanyName: unknown): boolean => { (_sleeveNumber: unknown, acompanyName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const companyName = ctx.helper.string("companyName", acompanyName); const companyName = helpers.string(ctx, "companyName", acompanyName);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -122,7 +124,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
} }
const other = player.sleeves[i]; const other = player.sleeves[i];
if (isSleeveCompanyWork(other.currentWork) && other.currentWork.companyName === companyName) { if (isSleeveCompanyWork(other.currentWork) && other.currentWork.companyName === companyName) {
throw ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`, `Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
); );
} }
@ -133,9 +136,9 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToFactionWork: setToFactionWork:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _factionName: unknown, _workType: unknown): boolean | undefined => { (_sleeveNumber: unknown, _factionName: unknown, _workType: unknown): boolean | undefined => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const factionName = ctx.helper.string("factionName", _factionName); const factionName = helpers.string(ctx, "factionName", _factionName);
const workType = ctx.helper.string("workType", _workType); const workType = helpers.string(ctx, "workType", _workType);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -146,14 +149,16 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
} }
const other = player.sleeves[i]; const other = player.sleeves[i];
if (isSleeveFactionWork(other.currentWork) && other.currentWork.factionName === factionName) { if (isSleeveFactionWork(other.currentWork) && other.currentWork.factionName === factionName) {
throw ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`, `Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
); );
} }
} }
if (player.gang && player.gang.facName == factionName) { if (player.gang && player.gang.facName == factionName) {
throw ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`, `Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`,
); );
} }
@ -163,9 +168,9 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToGymWorkout: setToGymWorkout:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _gymName: unknown, _stat: unknown): boolean => { (_sleeveNumber: unknown, _gymName: unknown, _stat: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const gymName = ctx.helper.string("gymName", _gymName); const gymName = helpers.string(ctx, "gymName", _gymName);
const stat = ctx.helper.string("stat", _stat); const stat = helpers.string(ctx, "stat", _stat);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -174,7 +179,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getSleeveStats: getSleeveStats:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): SleeveSkills => { (_sleeveNumber: unknown): SleeveSkills => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
return getSleeveStats(sleeveNumber); return getSleeveStats(sleeveNumber);
@ -182,7 +187,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getTask: getTask:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): SleeveTask | null => { (_sleeveNumber: unknown): SleeveTask | null => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -193,7 +198,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getInformation: getInformation:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): SleeveInformation => { (_sleeveNumber: unknown): SleeveInformation => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -229,7 +234,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getSleeveAugmentations: getSleeveAugmentations:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): string[] => { (_sleeveNumber: unknown): string[] => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -242,7 +247,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getSleevePurchasableAugs: getSleevePurchasableAugs:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown): AugmentPair[] => { (_sleeveNumber: unknown): AugmentPair[] => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -261,18 +266,18 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
purchaseSleeveAug: purchaseSleeveAug:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _augName: unknown): boolean => { (_sleeveNumber: unknown, _augName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const augName = ctx.helper.string("augName", _augName); const augName = helpers.string(ctx, "augName", _augName);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
if (getSleeveStats(sleeveNumber).shock > 0) { if (getSleeveStats(sleeveNumber).shock > 0) {
throw ctx.makeRuntimeErrorMsg(`Sleeve shock too high: Sleeve ${sleeveNumber}`); throw helpers.makeRuntimeErrorMsg(ctx, `Sleeve shock too high: Sleeve ${sleeveNumber}`);
} }
const aug = StaticAugmentations[augName]; const aug = StaticAugmentations[augName];
if (!aug) { if (!aug) {
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
} }
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug); return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
@ -281,7 +286,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_augName: unknown): number => { (_augName: unknown): number => {
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
const augName = ctx.helper.string("augName", _augName); const augName = helpers.string(ctx, "augName", _augName);
const aug: Augmentation = StaticAugmentations[augName]; const aug: Augmentation = StaticAugmentations[augName];
return aug.baseCost; return aug.baseCost;
}, },
@ -289,20 +294,20 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_augName: unknown): number => { (_augName: unknown): number => {
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
const augName = ctx.helper.string("augName", _augName); const augName = helpers.string(ctx, "augName", _augName);
const aug: Augmentation = StaticAugmentations[augName]; const aug: Augmentation = StaticAugmentations[augName];
return aug.getCost(player).repCost; return aug.getCost(player).repCost;
}, },
setToBladeburnerAction: setToBladeburnerAction:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _action: unknown, _contract?: unknown): boolean => { (_sleeveNumber: unknown, _action: unknown, _contract?: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const action = ctx.helper.string("action", _action); const action = helpers.string(ctx, "action", _action);
let contract: string; let contract: string;
if (typeof _contract === "undefined") { if (typeof _contract === "undefined") {
contract = "------"; contract = "------";
} else { } else {
contract = ctx.helper.string("contract", _contract); contract = helpers.string(ctx, "contract", _contract);
} }
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
@ -315,7 +320,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
} }
const other = player.sleeves[i]; const other = player.sleeves[i];
if (isSleeveBladeburnerWork(other.currentWork) && other.currentWork.actionName === contract) { if (isSleeveBladeburnerWork(other.currentWork) && other.currentWork.actionName === contract) {
throw ctx.helper.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
`Sleeve ${sleeveNumber} cannot take on contracts because Sleeve ${i} is already performing that action.`, `Sleeve ${sleeveNumber} cannot take on contracts because Sleeve ${i} is already performing that action.`,
); );
} }

@ -1,7 +1,4 @@
import { INetscriptHelper } from "./INetscriptHelper"; import { Player as player } from "../Player";
import { IPlayer } from "../PersonObjects/IPlayer";
import { WorkerScript } from "../Netscript/WorkerScript";
import { netscriptDelay } from "../NetscriptEvaluator";
import { staneksGift } from "../CotMG/Helper"; import { staneksGift } from "../CotMG/Helper";
import { Fragments, FragmentById } from "../CotMG/Fragment"; import { Fragments, FragmentById } from "../CotMG/Fragment";
@ -18,111 +15,109 @@ import { applyAugmentation } from "../Augmentation/AugmentationHelpers";
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { joinFaction } from "../Faction/FactionHelpers"; import { joinFaction } from "../Faction/FactionHelpers";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptStanek( export function NetscriptStanek(): InternalAPI<IStanek> {
player: IPlayer, function checkStanekAPIAccess(ctx: NetscriptContext): void {
workerScript: WorkerScript,
helper: INetscriptHelper,
): InternalAPI<IStanek> {
function checkStanekAPIAccess(func: string): void {
if (!player.hasAugmentation(AugmentationNames.StaneksGift1, true)) { if (!player.hasAugmentation(AugmentationNames.StaneksGift1, true)) {
throw helper.makeRuntimeErrorMsg(func, "Stanek's Gift is not installed"); throw helpers.makeRuntimeErrorMsg(ctx, "Stanek's Gift is not installed");
} }
} }
return { return {
giftWidth: () => giftWidth: (ctx: NetscriptContext) =>
function (): number { function (): number {
checkStanekAPIAccess("giftWidth"); checkStanekAPIAccess(ctx);
return staneksGift.width(); return staneksGift.width();
}, },
giftHeight: () => giftHeight: (ctx: NetscriptContext) =>
function (): number { function (): number {
checkStanekAPIAccess("giftHeight"); checkStanekAPIAccess(ctx);
return staneksGift.height(); return staneksGift.height();
}, },
chargeFragment: (_ctx: NetscriptContext) => chargeFragment: (ctx: NetscriptContext) =>
function (_rootX: unknown, _rootY: unknown): Promise<void> { function (_rootX: unknown, _rootY: unknown): Promise<void> {
//Get the fragment object using the given coordinates //Get the fragment object using the given coordinates
const rootX = _ctx.helper.number("rootX", _rootX); const rootX = helpers.number(ctx, "rootX", _rootX);
const rootY = _ctx.helper.number("rootY", _rootY); const rootY = helpers.number(ctx, "rootY", _rootY);
checkStanekAPIAccess("chargeFragment"); checkStanekAPIAccess(ctx);
const fragment = staneksGift.findFragment(rootX, rootY); const fragment = staneksGift.findFragment(rootX, rootY);
//Check whether the selected fragment can ge charged //Check whether the selected fragment can ge charged
if (!fragment) throw _ctx.makeRuntimeErrorMsg(`No fragment with root (${rootX}, ${rootY}).`); if (!fragment) throw helpers.makeRuntimeErrorMsg(ctx, `No fragment with root (${rootX}, ${rootY}).`);
if (fragment.fragment().type == FragmentType.Booster) { if (fragment.fragment().type == FragmentType.Booster) {
throw _ctx.makeRuntimeErrorMsg( throw helpers.makeRuntimeErrorMsg(
ctx,
`The fragment with root (${rootX}, ${rootY}) is a Booster Fragment and thus cannot be charged.`, `The fragment with root (${rootX}, ${rootY}) is a Booster Fragment and thus cannot be charged.`,
); );
} }
//Charge the fragment //Charge the fragment
const time = staneksGift.inBonus() ? 200 : 1000; const time = staneksGift.inBonus() ? 200 : 1000;
return netscriptDelay(time, workerScript).then(function () { return helpers.netscriptDelay(ctx, time).then(function () {
staneksGift.charge(player, fragment, workerScript.scriptRef.threads); staneksGift.charge(player, fragment, ctx.workerScript.scriptRef.threads);
_ctx.log(() => `Charged fragment with ${_ctx.workerScript.scriptRef.threads} threads.`); helpers.log(ctx, () => `Charged fragment with ${ctx.workerScript.scriptRef.threads} threads.`);
return Promise.resolve(); return Promise.resolve();
}); });
}, },
fragmentDefinitions: (_ctx: NetscriptContext) => fragmentDefinitions: (ctx: NetscriptContext) =>
function (): IFragment[] { function (): IFragment[] {
checkStanekAPIAccess("fragmentDefinitions"); checkStanekAPIAccess(ctx);
_ctx.log(() => `Returned ${Fragments.length} fragments`); helpers.log(ctx, () => `Returned ${Fragments.length} fragments`);
return Fragments.map((f) => f.copy()); return Fragments.map((f) => f.copy());
}, },
activeFragments: (_ctx: NetscriptContext) => activeFragments: (ctx: NetscriptContext) =>
function (): IActiveFragment[] { function (): IActiveFragment[] {
checkStanekAPIAccess("activeFragments"); checkStanekAPIAccess(ctx);
_ctx.log(() => `Returned ${staneksGift.fragments.length} fragments`); helpers.log(ctx, () => `Returned ${staneksGift.fragments.length} fragments`);
return staneksGift.fragments.map((af) => { return staneksGift.fragments.map((af) => {
return { ...af.copy(), ...af.fragment().copy() }; return { ...af.copy(), ...af.fragment().copy() };
}); });
}, },
clearGift: (_ctx: NetscriptContext) => clearGift: (ctx: NetscriptContext) =>
function (): void { function (): void {
checkStanekAPIAccess("clearGift"); checkStanekAPIAccess(ctx);
_ctx.log(() => `Cleared Stanek's Gift.`); helpers.log(ctx, () => `Cleared Stanek's Gift.`);
staneksGift.clear(); staneksGift.clear();
}, },
canPlaceFragment: (_ctx: NetscriptContext) => canPlaceFragment: (ctx: NetscriptContext) =>
function (_rootX: unknown, _rootY: unknown, _rotation: unknown, _fragmentId: unknown): boolean { function (_rootX: unknown, _rootY: unknown, _rotation: unknown, _fragmentId: unknown): boolean {
const rootX = _ctx.helper.number("rootX", _rootX); const rootX = helpers.number(ctx, "rootX", _rootX);
const rootY = _ctx.helper.number("rootY", _rootY); const rootY = helpers.number(ctx, "rootY", _rootY);
const rotation = _ctx.helper.number("rotation", _rotation); const rotation = helpers.number(ctx, "rotation", _rotation);
const fragmentId = _ctx.helper.number("fragmentId", _fragmentId); const fragmentId = helpers.number(ctx, "fragmentId", _fragmentId);
checkStanekAPIAccess("canPlaceFragment"); checkStanekAPIAccess(ctx);
const fragment = FragmentById(fragmentId); const fragment = FragmentById(fragmentId);
if (!fragment) throw _ctx.makeRuntimeErrorMsg(`Invalid fragment id: ${fragmentId}`); if (!fragment) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid fragment id: ${fragmentId}`);
const can = staneksGift.canPlace(rootX, rootY, rotation, fragment); const can = staneksGift.canPlace(rootX, rootY, rotation, fragment);
return can; return can;
}, },
placeFragment: (_ctx: NetscriptContext) => placeFragment: (ctx: NetscriptContext) =>
function (_rootX: unknown, _rootY: unknown, _rotation: unknown, _fragmentId: unknown): boolean { function (_rootX: unknown, _rootY: unknown, _rotation: unknown, _fragmentId: unknown): boolean {
const rootX = _ctx.helper.number("rootX", _rootX); const rootX = helpers.number(ctx, "rootX", _rootX);
const rootY = _ctx.helper.number("rootY", _rootY); const rootY = helpers.number(ctx, "rootY", _rootY);
const rotation = _ctx.helper.number("rotation", _rotation); const rotation = helpers.number(ctx, "rotation", _rotation);
const fragmentId = _ctx.helper.number("fragmentId", _fragmentId); const fragmentId = helpers.number(ctx, "fragmentId", _fragmentId);
checkStanekAPIAccess("placeFragment"); checkStanekAPIAccess(ctx);
const fragment = FragmentById(fragmentId); const fragment = FragmentById(fragmentId);
if (!fragment) throw _ctx.makeRuntimeErrorMsg(`Invalid fragment id: ${fragmentId}`); if (!fragment) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid fragment id: ${fragmentId}`);
return staneksGift.place(rootX, rootY, rotation, fragment); return staneksGift.place(rootX, rootY, rotation, fragment);
}, },
getFragment: (_ctx: NetscriptContext) => getFragment: (ctx: NetscriptContext) =>
function (_rootX: unknown, _rootY: unknown): IActiveFragment | undefined { function (_rootX: unknown, _rootY: unknown): IActiveFragment | undefined {
const rootX = _ctx.helper.number("rootX", _rootX); const rootX = helpers.number(ctx, "rootX", _rootX);
const rootY = _ctx.helper.number("rootY", _rootY); const rootY = helpers.number(ctx, "rootY", _rootY);
checkStanekAPIAccess("getFragment"); checkStanekAPIAccess(ctx);
const fragment = staneksGift.findFragment(rootX, rootY); const fragment = staneksGift.findFragment(rootX, rootY);
if (fragment !== undefined) return fragment.copy(); if (fragment !== undefined) return fragment.copy();
return undefined; return undefined;
}, },
removeFragment: (_ctx: NetscriptContext) => removeFragment: (ctx: NetscriptContext) =>
function (_rootX: unknown, _rootY: unknown): boolean { function (_rootX: unknown, _rootY: unknown): boolean {
const rootX = _ctx.helper.number("rootX", _rootX); const rootX = helpers.number(ctx, "rootX", _rootX);
const rootY = _ctx.helper.number("rootY", _rootY); const rootY = helpers.number(ctx, "rootY", _rootY);
checkStanekAPIAccess("removeFragment"); checkStanekAPIAccess(ctx);
return staneksGift.delete(rootX, rootY); return staneksGift.delete(rootX, rootY);
}, },
acceptGift: (_ctx: NetscriptContext) => acceptGift: (ctx: NetscriptContext) =>
function (): boolean { function (): boolean {
//Check if the player is eligible to join the church //Check if the player is eligible to join the church
if ( if (
@ -138,7 +133,8 @@ export function NetscriptStanek(
!player.queuedAugmentations.some((a) => a.name === AugmentationNames.StaneksGift1) !player.queuedAugmentations.some((a) => a.name === AugmentationNames.StaneksGift1)
) { ) {
applyAugmentation({ name: AugmentationNames.StaneksGift1, level: 1 }); applyAugmentation({ name: AugmentationNames.StaneksGift1, level: 1 });
_ctx.log( helpers.log(
ctx,
() => `'${FactionNames.ChurchOfTheMachineGod}' joined and '${AugmentationNames.StaneksGift1}' installed.`, () => `'${FactionNames.ChurchOfTheMachineGod}' joined and '${AugmentationNames.StaneksGift1}' installed.`,
); );
} }

@ -1,5 +1,4 @@
import { WorkerScript } from "../Netscript/WorkerScript"; import { Player as player } from "../Player";
import { IPlayer } from "../PersonObjects/IPlayer";
import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling"; import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling";
import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder, initStockMarketFn } from "../StockMarket/StockMarket"; import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder, initStockMarketFn } from "../StockMarket/StockMarket";
import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers"; import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers";
@ -14,25 +13,26 @@ import {
} from "../StockMarket/StockMarketCosts"; } from "../StockMarket/StockMarketCosts";
import { Stock } from "../StockMarket/Stock"; import { Stock } from "../StockMarket/Stock";
import { StockOrder, TIX } from "../ScriptEditor/NetscriptDefinitions"; import { StockOrder, TIX } from "../ScriptEditor/NetscriptDefinitions";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript): InternalAPI<TIX> { export function NetscriptStockMarket(): InternalAPI<TIX> {
/** /**
* Checks if the player has TIX API access. Throws an error if the player does not * Checks if the player has TIX API access. Throws an error if the player does not
*/ */
const checkTixApiAccess = function (ctx: NetscriptContext): void { const checkTixApiAccess = function (ctx: NetscriptContext): void {
if (!player.hasWseAccount) { if (!player.hasWseAccount) {
throw ctx.makeRuntimeErrorMsg(`You don't have WSE Access! Cannot use ${ctx.function}()`); throw helpers.makeRuntimeErrorMsg(ctx, `You don't have WSE Access! Cannot use ${ctx.function}()`);
} }
if (!player.hasTixApiAccess) { if (!player.hasTixApiAccess) {
throw ctx.makeRuntimeErrorMsg(`You don't have TIX API Access! Cannot use ${ctx.function}()`); throw helpers.makeRuntimeErrorMsg(ctx, `You don't have TIX API Access! Cannot use ${ctx.function}()`);
} }
}; };
const getStockFromSymbol = function (ctx: NetscriptContext, symbol: string): Stock { const getStockFromSymbol = function (ctx: NetscriptContext, symbol: string): Stock {
const stock = SymbolToStockMap[symbol]; const stock = SymbolToStockMap[symbol];
if (stock == null) { if (stock == null) {
throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: '${symbol}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid stock symbol: '${symbol}'`);
} }
return stock; return stock;
@ -58,7 +58,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getPrice: getPrice:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): number => { (_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -67,7 +67,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getAskPrice: getAskPrice:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): number => { (_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -76,7 +76,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getBidPrice: getBidPrice:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): number => { (_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -85,18 +85,18 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getPosition: getPosition:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): [number, number, number, number] => { (_symbol: unknown): [number, number, number, number] => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = SymbolToStockMap[symbol]; const stock = SymbolToStockMap[symbol];
if (stock == null) { if (stock == null) {
throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: ${symbol}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid stock symbol: ${symbol}`);
} }
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx]; return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
}, },
getMaxShares: getMaxShares:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): number => { (_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -105,9 +105,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getPurchaseCost: getPurchaseCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _posType: unknown): number => { (_symbol: unknown, _shares: unknown, _posType: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
let shares = ctx.helper.number("shares", _shares); let shares = helpers.number(ctx, "shares", _shares);
const posType = ctx.helper.string("posType", _posType); const posType = helpers.string(ctx, "posType", _posType);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
shares = Math.round(shares); shares = Math.round(shares);
@ -132,9 +132,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getSaleGain: getSaleGain:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _posType: unknown): number => { (_symbol: unknown, _shares: unknown, _posType: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
let shares = ctx.helper.number("shares", _shares); let shares = helpers.number(ctx, "shares", _shares);
const posType = ctx.helper.string("posType", _posType); const posType = helpers.string(ctx, "posType", _posType);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
shares = Math.round(shares); shares = Math.round(shares);
@ -159,68 +159,77 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
buyStock: buyStock:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => { (_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = ctx.helper.number("shares", _shares); const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
const res = buyStock(stock, shares, workerScript, {}); const res = buyStock(stock, shares, ctx.workerScript, {});
return res ? stock.getAskPrice() : 0; return res ? stock.getAskPrice() : 0;
}, },
sellStock: sellStock:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => { (_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = ctx.helper.number("shares", _shares); const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
const res = sellStock(stock, shares, workerScript, {}); const res = sellStock(stock, shares, ctx.workerScript, {});
return res ? stock.getBidPrice() : 0; return res ? stock.getBidPrice() : 0;
}, },
buyShort: buyShort:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => { (_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = ctx.helper.number("shares", _shares); const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) { if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 1) { if (player.sourceFileLvl(8) <= 1) {
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 2."); throw helpers.makeRuntimeErrorMsg(
ctx,
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
);
} }
} }
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
const res = shortStock(stock, shares, workerScript, {}); const res = shortStock(stock, shares, ctx.workerScript, {});
return res ? stock.getBidPrice() : 0; return res ? stock.getBidPrice() : 0;
}, },
sellShort: sellShort:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => { (_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = ctx.helper.number("shares", _shares); const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) { if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 1) { if (player.sourceFileLvl(8) <= 1) {
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 2."); throw helpers.makeRuntimeErrorMsg(
ctx,
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
);
} }
} }
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
const res = sellShort(stock, shares, workerScript, {}); const res = sellShort(stock, shares, ctx.workerScript, {});
return res ? stock.getAskPrice() : 0; return res ? stock.getAskPrice() : 0;
}, },
placeOrder: placeOrder:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => { (_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = ctx.helper.number("shares", _shares); const shares = helpers.number(ctx, "shares", _shares);
const price = ctx.helper.number("price", _price); const price = helpers.number(ctx, "price", _price);
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const pos = ctx.helper.string("pos", _pos); const pos = helpers.string(ctx, "pos", _pos);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) { if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 2) { if (player.sourceFileLvl(8) <= 2) {
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 3."); throw helpers.makeRuntimeErrorMsg(
ctx,
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
);
} }
} }
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -237,7 +246,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (ltype.includes("stop") && ltype.includes("sell")) { } else if (ltype.includes("stop") && ltype.includes("sell")) {
orderType = OrderTypes.StopSell; orderType = OrderTypes.StopSell;
} else { } else {
throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid order type: ${type}`);
} }
const lpos = pos.toLowerCase(); const lpos = pos.toLowerCase();
@ -246,28 +255,34 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (lpos.includes("s")) { } else if (lpos.includes("s")) {
orderPos = PositionTypes.Short; orderPos = PositionTypes.Short;
} else { } else {
throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid position type: ${pos}`);
} }
return placeOrder(stock, shares, price, orderType, orderPos, workerScript); return placeOrder(stock, shares, price, orderType, orderPos, ctx.workerScript);
}, },
cancelOrder: cancelOrder:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => { (_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = ctx.helper.number("shares", _shares); const shares = helpers.number(ctx, "shares", _shares);
const price = ctx.helper.number("price", _price); const price = helpers.number(ctx, "price", _price);
const type = ctx.helper.string("type", _type); const type = helpers.string(ctx, "type", _type);
const pos = ctx.helper.string("pos", _pos); const pos = helpers.string(ctx, "pos", _pos);
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) { if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 2) { if (player.sourceFileLvl(8) <= 2) {
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 3."); throw helpers.makeRuntimeErrorMsg(
ctx,
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
);
} }
} }
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
if (isNaN(shares) || isNaN(price)) { if (isNaN(shares) || isNaN(price)) {
throw ctx.makeRuntimeErrorMsg(`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`); throw helpers.makeRuntimeErrorMsg(
ctx,
`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`,
);
} }
let orderType; let orderType;
let orderPos; let orderPos;
@ -281,7 +296,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (ltype.includes("stop") && ltype.includes("sell")) { } else if (ltype.includes("stop") && ltype.includes("sell")) {
orderType = OrderTypes.StopSell; orderType = OrderTypes.StopSell;
} else { } else {
throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid order type: ${type}`);
} }
const lpos = pos.toLowerCase(); const lpos = pos.toLowerCase();
@ -290,7 +305,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (lpos.includes("s")) { } else if (lpos.includes("s")) {
orderPos = PositionTypes.Short; orderPos = PositionTypes.Short;
} else { } else {
throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid position type: ${pos}`);
} }
const params = { const params = {
stock: stock, stock: stock,
@ -299,13 +314,13 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
type: orderType, type: orderType,
pos: orderPos, pos: orderPos,
}; };
return cancelOrder(params, workerScript); return cancelOrder(params, ctx.workerScript);
}, },
getOrders: (ctx: NetscriptContext) => (): StockOrder => { getOrders: (ctx: NetscriptContext) => (): StockOrder => {
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) { if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 2) { if (player.sourceFileLvl(8) <= 2) {
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or have Source-File 8 Level 3."); throw helpers.makeRuntimeErrorMsg(ctx, "You must either be in BitNode-8 or have Source-File 8 Level 3.");
} }
} }
@ -332,9 +347,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getVolatility: getVolatility:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): number => { (_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
if (!player.has4SDataTixApi) { if (!player.has4SDataTixApi) {
throw ctx.makeRuntimeErrorMsg("You don't have 4S Market Data TIX API Access!"); throw helpers.makeRuntimeErrorMsg(ctx, "You don't have 4S Market Data TIX API Access!");
} }
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -343,9 +358,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getForecast: getForecast:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_symbol: unknown): number => { (_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol); const symbol = helpers.string(ctx, "symbol", _symbol);
if (!player.has4SDataTixApi) { if (!player.has4SDataTixApi) {
throw ctx.makeRuntimeErrorMsg("You don't have 4S Market Data TIX API Access!"); throw helpers.makeRuntimeErrorMsg(ctx, "You don't have 4S Market Data TIX API Access!");
} }
const stock = getStockFromSymbol(ctx, symbol); const stock = getStockFromSymbol(ctx, symbol);
@ -355,69 +370,69 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
}, },
purchase4SMarketData: (ctx: NetscriptContext) => (): boolean => { purchase4SMarketData: (ctx: NetscriptContext) => (): boolean => {
if (player.has4SData) { if (player.has4SData) {
ctx.log(() => "Already purchased 4S Market Data."); helpers.log(ctx, () => "Already purchased 4S Market Data.");
return true; return true;
} }
if (player.money < getStockMarket4SDataCost()) { if (player.money < getStockMarket4SDataCost()) {
ctx.log(() => "Not enough money to purchase 4S Market Data."); helpers.log(ctx, () => "Not enough money to purchase 4S Market Data.");
return false; return false;
} }
player.has4SData = true; player.has4SData = true;
player.loseMoney(getStockMarket4SDataCost(), "stock"); player.loseMoney(getStockMarket4SDataCost(), "stock");
ctx.log(() => "Purchased 4S Market Data"); helpers.log(ctx, () => "Purchased 4S Market Data");
return true; return true;
}, },
purchase4SMarketDataTixApi: (ctx: NetscriptContext) => (): boolean => { purchase4SMarketDataTixApi: (ctx: NetscriptContext) => (): boolean => {
checkTixApiAccess(ctx); checkTixApiAccess(ctx);
if (player.has4SDataTixApi) { if (player.has4SDataTixApi) {
ctx.log(() => "Already purchased 4S Market Data TIX API"); helpers.log(ctx, () => "Already purchased 4S Market Data TIX API");
return true; return true;
} }
if (player.money < getStockMarket4STixApiCost()) { if (player.money < getStockMarket4STixApiCost()) {
ctx.log(() => "Not enough money to purchase 4S Market Data TIX API"); helpers.log(ctx, () => "Not enough money to purchase 4S Market Data TIX API");
return false; return false;
} }
player.has4SDataTixApi = true; player.has4SDataTixApi = true;
player.loseMoney(getStockMarket4STixApiCost(), "stock"); player.loseMoney(getStockMarket4STixApiCost(), "stock");
ctx.log(() => "Purchased 4S Market Data TIX API"); helpers.log(ctx, () => "Purchased 4S Market Data TIX API");
return true; return true;
}, },
purchaseWseAccount: (ctx: NetscriptContext) => (): boolean => { purchaseWseAccount: (ctx: NetscriptContext) => (): boolean => {
if (player.hasWseAccount) { if (player.hasWseAccount) {
ctx.log(() => "Already purchased WSE Account"); helpers.log(ctx, () => "Already purchased WSE Account");
return true; return true;
} }
if (player.money < getStockMarketWseCost()) { if (player.money < getStockMarketWseCost()) {
ctx.log(() => "Not enough money to purchase WSE Account Access"); helpers.log(ctx, () => "Not enough money to purchase WSE Account Access");
return false; return false;
} }
player.hasWseAccount = true; player.hasWseAccount = true;
initStockMarketFn(); initStockMarketFn();
player.loseMoney(getStockMarketWseCost(), "stock"); player.loseMoney(getStockMarketWseCost(), "stock");
ctx.log(() => "Purchased WSE Account Access"); helpers.log(ctx, () => "Purchased WSE Account Access");
return true; return true;
}, },
purchaseTixApi: (ctx: NetscriptContext) => (): boolean => { purchaseTixApi: (ctx: NetscriptContext) => (): boolean => {
if (player.hasTixApiAccess) { if (player.hasTixApiAccess) {
ctx.log(() => "Already purchased TIX API"); helpers.log(ctx, () => "Already purchased TIX API");
return true; return true;
} }
if (player.money < getStockMarketTixApiCost()) { if (player.money < getStockMarketTixApiCost()) {
ctx.log(() => "Not enough money to purchase TIX API Access"); helpers.log(ctx, () => "Not enough money to purchase TIX API Access");
return false; return false;
} }
player.hasTixApiAccess = true; player.hasTixApiAccess = true;
player.loseMoney(getStockMarketTixApiCost(), "stock"); player.loseMoney(getStockMarketTixApiCost(), "stock");
ctx.log(() => "Purchased TIX API"); helpers.log(ctx, () => "Purchased TIX API");
return true; return true;
}, },
}; };

@ -10,8 +10,9 @@ import { defaultTheme } from "../Themes/Themes";
import { defaultStyles } from "../Themes/Styles"; import { defaultStyles } from "../Themes/Styles";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { hash } from "../hash/hash"; import { hash } from "../hash/hash";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { Terminal } from "../../src/Terminal"; import { Terminal } from "../../src/Terminal";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptUserInterface(): InternalAPI<IUserInterface> { export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
return { return {
@ -43,9 +44,9 @@ export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
if (errors.length === 0) { if (errors.length === 0) {
Object.assign(Settings.theme, currentTheme); Object.assign(Settings.theme, currentTheme);
ThemeEvents.emit(); ThemeEvents.emit();
ctx.log(() => `Successfully set theme`); helpers.log(ctx, () => `Successfully set theme`);
} else { } else {
ctx.log(() => `Failed to set theme. Errors: ${errors.join(", ")}`); helpers.log(ctx, () => `Failed to set theme. Errors: ${errors.join(", ")}`);
} }
}, },
@ -66,22 +67,22 @@ export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
if (errors.length === 0) { if (errors.length === 0) {
Object.assign(Settings.styles, currentStyles); Object.assign(Settings.styles, currentStyles);
ThemeEvents.emit(); ThemeEvents.emit();
ctx.log(() => `Successfully set styles`); helpers.log(ctx, () => `Successfully set styles`);
} else { } else {
ctx.log(() => `Failed to set styles. Errors: ${errors.join(", ")}`); helpers.log(ctx, () => `Failed to set styles. Errors: ${errors.join(", ")}`);
} }
}, },
resetTheme: (ctx: NetscriptContext) => (): void => { resetTheme: (ctx: NetscriptContext) => (): void => {
Settings.theme = { ...defaultTheme }; Settings.theme = { ...defaultTheme };
ThemeEvents.emit(); ThemeEvents.emit();
ctx.log(() => `Reinitialized theme to default`); helpers.log(ctx, () => `Reinitialized theme to default`);
}, },
resetStyles: (ctx: NetscriptContext) => (): void => { resetStyles: (ctx: NetscriptContext) => (): void => {
Settings.styles = { ...defaultStyles }; Settings.styles = { ...defaultStyles };
ThemeEvents.emit(); ThemeEvents.emit();
ctx.log(() => `Reinitialized styles to default`); helpers.log(ctx, () => `Reinitialized styles to default`);
}, },
getGameInfo: () => (): GameInfo => { getGameInfo: () => (): GameInfo => {
@ -99,7 +100,7 @@ export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
}, },
clearTerminal: (ctx: NetscriptContext) => (): void => { clearTerminal: (ctx: NetscriptContext) => (): void => {
ctx.log(() => `Clearing terminal`); helpers.log(ctx, () => `Clearing terminal`);
Terminal.clear(); Terminal.clear();
}, },
}; };

@ -5,7 +5,7 @@
import * as walk from "acorn-walk"; import * as walk from "acorn-walk";
import { parse } from "acorn"; import { parse } from "acorn";
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator"; import { helpers } from "./Netscript/NetscriptHelpers";
import { ScriptUrl } from "./Script/ScriptUrl"; import { ScriptUrl } from "./Script/ScriptUrl";
import { WorkerScript } from "./Netscript/WorkerScript"; import { WorkerScript } from "./Netscript/WorkerScript";
import { Script } from "./Script/Script"; import { Script } from "./Script/Script";
@ -74,18 +74,21 @@ export async function executeJSScript(
const ns = workerScript.env.vars; const ns = workerScript.env.vars;
if (!loadedModule) { if (!loadedModule) {
throw makeRuntimeRejectMsg(workerScript, `${script.filename} cannot be run because the script module won't load`); throw helpers.makeRuntimeRejectMsg(
workerScript,
`${script.filename} cannot be run because the script module won't load`,
);
} }
// TODO: putting await in a non-async function yields unhelpful // TODO: putting await in a non-async function yields unhelpful
// "SyntaxError: unexpected reserved word" with no line number information. // "SyntaxError: unexpected reserved word" with no line number information.
if (!loadedModule.main) { if (!loadedModule.main) {
throw makeRuntimeRejectMsg( throw helpers.makeRuntimeRejectMsg(
workerScript, workerScript,
`${script.filename} cannot be run because it does not have a main function.`, `${script.filename} cannot be run because it does not have a main function.`,
); );
} }
if (!ns) { if (!ns) {
throw makeRuntimeRejectMsg( throw helpers.makeRuntimeRejectMsg(
workerScript, workerScript,
`${script.filename} cannot be run because the NS object hasn't been constructed properly.`, `${script.filename} cannot be run because the NS object hasn't been constructed properly.`,
); );

@ -11,7 +11,6 @@ import { generateNextPid } from "./Netscript/Pid";
import { CONSTANTS } from "./Constants"; import { CONSTANTS } from "./Constants";
import { Interpreter } from "./ThirdParty/JSInterpreter"; import { Interpreter } from "./ThirdParty/JSInterpreter";
import { isScriptErrorMessage, makeRuntimeRejectMsg } from "./NetscriptEvaluator";
import { NetscriptFunctions } from "./NetscriptFunctions"; import { NetscriptFunctions } from "./NetscriptFunctions";
import { executeJSScript, Node } from "./NetscriptJSEvaluator"; import { executeJSScript, Node } from "./NetscriptJSEvaluator";
import { NetscriptPort, IPort } from "./NetscriptPort"; import { NetscriptPort, IPort } from "./NetscriptPort";
@ -29,7 +28,6 @@ import { dialogBoxCreate } from "./ui/React/DialogBox";
import { arrayToString } from "./utils/helpers/arrayToString"; import { arrayToString } from "./utils/helpers/arrayToString";
import { roundToTwo } from "./utils/helpers/roundToTwo"; import { roundToTwo } from "./utils/helpers/roundToTwo";
import { isString } from "./utils/helpers/isString"; import { isString } from "./utils/helpers/isString";
import { sprintf } from "sprintf-js";
import { parse } from "acorn"; import { parse } from "acorn";
import { simple as walksimple } from "acorn-walk"; import { simple as walksimple } from "acorn-walk";
@ -38,6 +36,8 @@ import { Player } from "./Player";
import { Terminal } from "./Terminal"; import { Terminal } from "./Terminal";
import { IPlayer } from "./PersonObjects/IPlayer"; import { IPlayer } from "./PersonObjects/IPlayer";
import { ScriptArg } from "./Netscript/ScriptArg"; import { ScriptArg } from "./Netscript/ScriptArg";
import { helpers } from "./Netscript/NetscriptHelpers";
import { NS } from "./ScriptEditor/NetscriptDefinitions";
// Netscript Ports are instantiated here // Netscript Ports are instantiated here
export const NetscriptPorts: IPort[] = []; export const NetscriptPorts: IPort[] = [];
@ -63,83 +63,6 @@ export function prestigeWorkerScripts(): void {
// that resolves or rejects when the corresponding worker script is done. // that resolves or rejects when the corresponding worker script is done.
function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Promise<void> { function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Promise<void> {
workerScript.running = true; workerScript.running = true;
// The name of the currently running netscript function, to prevent concurrent
// calls to hack, grow, etc.
let runningFn: string | null = null;
// We need to go through the environment and wrap each function in such a way that it
// can be called at most once at a time. This will prevent situations where multiple
// hack promises are outstanding, for example.
function wrap(propName: string, f: (...args: unknown[]) => Promise<void>): (...args: unknown[]) => Promise<void> {
// This function unfortunately cannot be an async function, because we don't
// know if the original one was, and there's no way to tell.
return function (...args: unknown[]) {
// Wrap every netscript function with a check for the stop flag.
// This prevents cases where we never stop because we are only calling
// netscript functions that don't check this.
// This is not a problem for legacy Netscript because it also checks the
// stop flag in the evaluator.
if (workerScript.env.stopFlag) {
throw new ScriptDeath(workerScript);
}
if (propName === "asleep") return f(...args); // OK for multiple simultaneous calls to sleep.
const msg =
"Concurrent calls to Netscript functions are not allowed! " +
"Did you forget to await hack(), grow(), or some other " +
"promise-returning function? (Currently running: %s tried to run: %s)";
if (runningFn) {
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, sprintf(msg, runningFn, propName));
throw new ScriptDeath(workerScript);
}
runningFn = propName;
// If the function throws an error, clear the runningFn flag first, and then re-throw it
// This allows people to properly catch errors thrown by NS functions without getting
// the concurrent call error above
let result;
try {
result = f(...args);
} catch (e: unknown) {
runningFn = null;
throw e;
}
if (result && result.finally !== undefined) {
return result.finally(function () {
runningFn = null;
});
} else {
runningFn = null;
return result;
}
};
}
function wrapObject(vars: unknown, ...tree: string[]): void {
const isObject = (x: unknown): x is { [key: string]: unknown } => typeof x === "object";
if (!isObject(vars)) throw new Error("wrong argument sent to wrapObject");
for (const prop of Object.keys(vars)) {
let e = vars[prop];
switch (typeof e) {
case "function": {
e = wrap([...tree, prop].join("."), e as any);
break;
}
case "object": {
if (Array.isArray(e)) continue;
wrapObject(e, ...tree, prop);
break;
}
}
}
}
wrapObject(workerScript.env.vars);
// Note: the environment that we pass to the JS script only needs to contain the functions visible
// to that script, which env.vars does at this point.
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
executeJSScript(player, workerScript.getServer().scripts, workerScript) executeJSScript(player, workerScript.getServer().scripts, workerScript)
.then(() => { .then(() => {
@ -149,15 +72,18 @@ function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Pro
}).catch((e) => { }).catch((e) => {
if (e instanceof Error) { if (e instanceof Error) {
if (e instanceof SyntaxError) { if (e instanceof SyntaxError) {
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, e.message + " (sorry we can't be more helpful)"); workerScript.errorMessage = helpers.makeRuntimeRejectMsg(
workerScript,
e.message + " (sorry we can't be more helpful)",
);
} else { } else {
workerScript.errorMessage = makeRuntimeRejectMsg( workerScript.errorMessage = helpers.makeRuntimeRejectMsg(
workerScript, workerScript,
e.message + ((e.stack && "\nstack:\n" + e.stack.toString()) || ""), e.message + ((e.stack && "\nstack:\n" + e.stack.toString()) || ""),
); );
} }
throw new ScriptDeath(workerScript); throw new ScriptDeath(workerScript);
} else if (isScriptErrorMessage(e)) { } else if (helpers.isScriptErrorMessage(e)) {
workerScript.errorMessage = e; workerScript.errorMessage = e;
throw new ScriptDeath(workerScript); throw new ScriptDeath(workerScript);
} else if (e instanceof ScriptDeath) { } else if (e instanceof ScriptDeath) {
@ -165,7 +91,7 @@ function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Pro
} }
// Don't know what to do with it, let's try making an error message out of it // Don't know what to do with it, let's try making an error message out of it
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, "" + e); workerScript.errorMessage = helpers.makeRuntimeRejectMsg(workerScript, "" + e);
throw new ScriptDeath(workerScript); throw new ScriptDeath(workerScript);
}); });
} }
@ -189,8 +115,11 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
} }
const interpreterInitialization = function (int: Interpreter, scope: unknown): void { const interpreterInitialization = function (int: Interpreter, scope: unknown): void {
interface NS1 extends NS {
[key: string]: any;
}
//Add the Netscript environment //Add the Netscript environment
const ns = NetscriptFunctions(workerScript); const ns = NetscriptFunctions(workerScript) as NS1;
for (const name of Object.keys(ns)) { for (const name of Object.keys(ns)) {
const entry = ns[name]; const entry = ns[name];
if (typeof entry === "function") { if (typeof entry === "function") {
@ -242,7 +171,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
name === "vsprintf" || name === "vsprintf" ||
name === "scp" || name === "scp" ||
name == "write" || name == "write" ||
name === "tryWrite" || name === "tryWritePort" ||
name === "run" || name === "run" ||
name === "exec" name === "exec"
) { ) {
@ -319,8 +248,8 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
} }
} catch (_e: unknown) { } catch (_e: unknown) {
let e = String(_e); let e = String(_e);
if (!isScriptErrorMessage(e)) { if (!helpers.isScriptErrorMessage(e)) {
e = makeRuntimeRejectMsg(workerScript, e); e = helpers.makeRuntimeRejectMsg(workerScript, e);
} }
workerScript.errorMessage = e; workerScript.errorMessage = e;
return reject(new ScriptDeath(workerScript)); return reject(new ScriptDeath(workerScript));
@ -598,7 +527,7 @@ function createAndAddWorkerScript(
console.error("Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + e.toString()); console.error("Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + e.toString());
return; return;
} else if (e instanceof ScriptDeath) { } else if (e instanceof ScriptDeath) {
if (isScriptErrorMessage(workerScript.errorMessage)) { if (helpers.isScriptErrorMessage(workerScript.errorMessage)) {
const errorTextArray = workerScript.errorMessage.split("|DELIMITER|"); const errorTextArray = workerScript.errorMessage.split("|DELIMITER|");
if (errorTextArray.length != 4) { if (errorTextArray.length != 4) {
console.error("ERROR: Something wrong with Error text in evaluator..."); console.error("ERROR: Something wrong with Error text in evaluator...");
@ -622,7 +551,7 @@ function createAndAddWorkerScript(
workerScript.log("", () => "Script killed"); workerScript.log("", () => "Script killed");
return; // Already killed, so stop here return; // Already killed, so stop here
} }
} else if (isScriptErrorMessage(e)) { } else if (helpers.isScriptErrorMessage(e)) {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
console.error( console.error(
"ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN: " + "ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN: " +

@ -4281,7 +4281,7 @@ export interface InfiltrationReward {
* @public * @public
*/ */
export interface ILocation { export interface ILocation {
city: CityName | null; city: string;
name: string; name: string;
} }
@ -6920,6 +6920,31 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
* @returns An offer of investment * @returns An offer of investment
*/ */
getInvestmentOffer(): InvestmentOffer; getInvestmentOffer(): InvestmentOffer;
/**
* Get list of materials
* @returns material names
*/
getMaterialNames(): string[];
/**
* Get list of industry types
* @returns industry names
*/
getIndustryTypes(): string[];
/**
* Get list of one-time unlockable upgrades
* @returns unlockable upgrades names
*/
getUnlockables(): string[];
/**
* Get list of upgrade names
* @returns upgrade names
*/
getUpgradeNames(): string[];
/**
* Get list of research names
* @returns research names
*/
getResearchNames(): string[];
/** /**
* Accept investment based on you companies current valuation * Accept investment based on you companies current valuation
* @remarks * @remarks

@ -309,7 +309,7 @@ export async function determineAllPossibilitiesForTabCompletion(
return "--" + f[0]; return "--" + f[0];
}); });
try { try {
return flagFunc()(schema); return flagFunc(schema);
} catch (err) { } catch (err) {
return {}; return {};
} }

@ -1,10 +1,10 @@
import { ScriptDeath } from "./Netscript/ScriptDeath"; import { ScriptDeath } from "./Netscript/ScriptDeath";
import { isScriptErrorMessage } from "./NetscriptEvaluator"; import { helpers } from "./Netscript/NetscriptHelpers";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
export function setupUncaughtPromiseHandler(): void { export function setupUncaughtPromiseHandler(): void {
window.addEventListener("unhandledrejection", function (e) { window.addEventListener("unhandledrejection", function (e) {
if (isScriptErrorMessage(e.reason)) { if (helpers.isScriptErrorMessage(e.reason)) {
const errorTextArray = e.reason.split("|DELIMITER|"); const errorTextArray = e.reason.split("|DELIMITER|");
const hostname = errorTextArray[1]; const hostname = errorTextArray[1];
const scriptName = errorTextArray[2]; const scriptName = errorTextArray[2];

@ -381,7 +381,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
<Typography> <Typography>
Scripts must end with the {tutorialScriptExtension} extension. Let's make a script now by entering{" "} Scripts must end with the {tutorialScriptExtension} extension. Let's make a script now by entering{" "}
</Typography> </Typography>
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> nano ${tutorialScriptName}`}</Typography> <Typography classes={{ root: classes.textfield }}>{`[n00dles ~/]> nano ${tutorialScriptName}`}</Typography>
<Typography> <Typography>
after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early) after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early)
@ -439,7 +439,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
<br /> <br />
To check how much RAM is available on this machine, enter To check how much RAM is available on this machine, enter
</Typography> </Typography>
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> free"}</Typography> <Typography classes={{ root: classes.textfield }}>{"[n00dles ~/]> free"}</Typography>
</> </>
), ),
canNext: false, canNext: false,
@ -448,9 +448,9 @@ export function InteractiveTutorialRoot(): React.ReactElement {
content: ( content: (
<> <>
<Typography> <Typography>
We have 8GB of free RAM on this machine, which is enough to run our script. Let's run our script using We have 4GB of free RAM on this machine, which is enough to run our script. Let's run our script using
</Typography> </Typography>
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> run ${tutorialScriptName}`}</Typography> <Typography classes={{ root: classes.textfield }}>{`[n00dles ~/]> run ${tutorialScriptName}`}</Typography>
</> </>
), ),
canNext: false, canNext: false,
@ -497,7 +497,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
One last thing about scripts, each active script contains logs that detail what it's doing. We can check One last thing about scripts, each active script contains logs that detail what it's doing. We can check
these logs using the tail command. Do that now for the script we just ran by typing{" "} these logs using the tail command. Do that now for the script we just ran by typing{" "}
</Typography> </Typography>
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> tail ${tutorialScriptName}`}</Typography> <Typography classes={{ root: classes.textfield }}>{`[n00dles ~/]> tail ${tutorialScriptName}`}</Typography>
</> </>
), ),
canNext: false, canNext: false,

@ -139,6 +139,10 @@ function PromptMenuSelect({ prompt, resolve }: IContentProps): React.ReactElemen
return content; return content;
}; };
if (!Array.isArray(prompt?.options?.choices)) {
return <Typography>Error: Please provide an array of string choices</Typography>;
}
return ( return (
<> <>
<div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}> <div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>

@ -60,7 +60,7 @@ describe("tutorial", () => {
cy.findByText(/now we'll run the script/i); cy.findByText(/now we'll run the script/i);
cy.findByRole("textbox").type("free{enter}"); cy.findByRole("textbox").type("free{enter}");
cy.findByText(/We have 8GB of free RAM on this machine/i); cy.findByText(/We have 4GB of free RAM on this machine/i);
cy.findByRole("textbox").type("run n00dles.script{enter}"); cy.findByRole("textbox").type("run n00dles.script{enter}");
cy.findByText(/Your script is now running/i); cy.findByText(/Your script is now running/i);