Merge pull request #3967 from Snarling/performance

NETSCRIPT: Improve real life CPU and memory performance of scripts.
This commit is contained in:
hydroflame 2022-08-15 10:26:53 -03:00 committed by GitHub
commit 2abc5687e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 3575 additions and 3609 deletions

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

@ -1,22 +1,15 @@
import { getRamCost } from "./RamCostGenerator";
import type { IPort } from "../NetscriptPort";
import type { BaseServer } from "../Server/BaseServer";
import type { WorkerScript } from "./WorkerScript";
import { makeRuntimeRejectMsg } from "../NetscriptEvaluator";
import { Player } from "../Player";
import { CityName } from "../Locations/data/CityNames";
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 { helpers } from "./NetscriptHelpers";
import { ScriptArg } from "./ScriptArg";
import { NSEnums } from "src/ScriptEditor/NetscriptDefinitions";
import { NSFull } from "src/NetscriptFunctions";
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;
@ -24,48 +17,23 @@ type InternalFunction<F extends (...args: unknown[]) => unknown> = (ctx: Netscri
export type InternalAPI<API> = {
[Property in keyof API]: API[Property] extends ExternalFunction
? InternalFunction<API[Property]>
: API[Property] extends NSEnums
? NSEnums
: API[Property] extends ScriptArg[]
? ScriptArg[]
: API[Property] extends object
? InternalAPI<API[Property]>
: never;
};
type WrappedNetscriptFunction = (...args: unknown[]) => unknown;
type WrappedNetscriptAPI = {
readonly [string: string]: WrappedNetscriptAPI | WrappedNetscriptFunction;
};
export type NetscriptContext = {
makeRuntimeErrorMsg: (message: string) => string;
log: (message: () => string) => void;
workerScript: WorkerScript;
function: string;
helper: WrappedNetscriptHelpers;
};
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;
functionPath: string;
};
function wrapFunction(
helpers: INetscriptHelper,
wrappedAPI: ExternalAPI,
wrappedAPI: ExternalAPILayer,
workerScript: WorkerScript,
func: (_ctx: NetscriptContext) => (...args: unknown[]) => unknown,
...tree: string[]
@ -73,44 +41,19 @@ function wrapFunction(
const functionPath = tree.join(".");
const functionName = tree.pop();
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 = {
makeRuntimeErrorMsg: (message: string) => {
return helpers.makeRuntimeErrorMsg(functionPath, message);
},
log: (message: () => string) => {
workerScript.log(functionPath, message);
},
workerScript,
function: functionName,
helper: {
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),
},
functionPath,
};
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);
}
const parent = getNestedProperty(wrappedAPI, ...tree);
const parent = getNestedProperty(wrappedAPI, tree);
Object.defineProperty(parent, functionName, {
value: wrappedFunction,
writable: true,
@ -118,20 +61,25 @@ function wrapFunction(
});
}
export function wrapAPI(
helpers: INetscriptHelper,
wrappedAPI: ExternalAPI,
export function wrapAPI(workerScript: WorkerScript, namespace: object, args: ScriptArg[]): NSFull {
const wrappedAPI = wrapAPILayer({}, workerScript, namespace);
wrappedAPI.args = args;
return wrappedAPI as unknown as NSFull;
}
export function wrapAPILayer(
wrappedAPI: ExternalAPILayer,
workerScript: WorkerScript,
namespace: object,
...tree: string[]
): WrappedNetscriptAPI {
) {
for (const [key, value] of Object.entries(namespace)) {
if (typeof value === "function") {
wrapFunction(helpers, wrappedAPI, workerScript, value, ...tree, key);
wrapFunction(wrappedAPI, workerScript, value, ...tree, key);
} else if (Array.isArray(value)) {
setNestedProperty(wrappedAPI, value, key);
setNestedProperty(wrappedAPI, value.slice(), key);
} else if (typeof value === "object") {
wrapAPI(helpers, wrappedAPI, workerScript, value, ...tree, key);
wrapAPILayer(wrappedAPI, workerScript, value, ...tree, key);
} else {
setNestedProperty(wrappedAPI, value, ...tree, key);
}
@ -139,28 +87,21 @@ export function wrapAPI(
return wrappedAPI;
}
// TODO: This doesn't even work properly.
function setNestedProperty(root: object, value: unknown, ...tree: string[]): void {
function setNestedProperty(root: any, value: unknown, ...tree: string[]): void {
let target = root;
const key = tree.pop();
if (!key) {
throw new Error("Failure occured while wrapping netscript api (setNestedProperty)");
if (!key) 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)) {
if (branch === undefined) {
branch = {};
}
target = branch;
}
Object.assign(target, { [key]: value });
target[key] = value;
}
function getNestedProperty(root: any, ...tree: string[]): unknown {
function getNestedProperty(root: any, tree: string[]): unknown {
let target = root;
for (const branch of tree) {
if (target[branch] === undefined) {
target[branch] = {};
}
target[branch] ??= {};
target = target[branch];
}
return target;

@ -10,6 +10,12 @@ export class Environment {
*/
stopFlag = false;
/**
* The currently running function
*/
runningFn = "";
/**
* 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 = {
getMaterialNames: 0,
getIndustryTypes: 0,
getUnlockables: 0,
getUpgradeNames: 0,
getResearchNames: 0,
createCorporation: 0,
hasUnlockUpgrade: 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[];
};

@ -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 { IPlayer } from "../PersonObjects/IPlayer";
import { Player as player } from "../Player";
import { Bladeburner } from "../Bladeburner/Bladeburner";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Bladeburner as INetscriptBladeburner, BladeburnerCurAction } from "../ScriptEditor/NetscriptDefinitions";
import { IAction } from "src/Bladeburner/IAction";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
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 bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Must have joined bladeburner");
@ -18,13 +18,13 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
});
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.`;
throw ctx.makeRuntimeErrorMsg(apiDenied);
throw helpers.makeRuntimeErrorMsg(ctx, apiDenied);
}
if (!skipjoined) {
const bladeburnerAccess = bladeburner instanceof Bladeburner;
if (!bladeburnerAccess) {
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;
if (bladeburner === null) throw new Error("Must have joined bladeburner");
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");
const actionId = bladeburner.getActionIdFromTypeAndName(type, name);
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);
if (!actionObj) {
throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid action type='${type}', name='${name}'`);
}
return actionObj;
@ -74,7 +74,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getBlackOpRank:
(ctx: NetscriptContext) =>
(_blackOpName: unknown): number => {
const blackOpName = ctx.helper.string("blackOpName", _blackOpName);
const blackOpName = helpers.string(ctx, "blackOpName", _blackOpName);
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, "blackops", blackOpName);
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:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): boolean => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.startActionNetscriptFn(player, type, name, workerScript);
return bladeburner.startActionNetscriptFn(player, type, name, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
stopBladeburnerAction: (ctx: NetscriptContext) => (): void => {
@ -121,8 +121,8 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionTime:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.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);
if (typeof time === "string") {
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
ctx.log(() => errorLogText);
helpers.log(ctx, () => errorLogText);
return -1;
} else {
return time;
}
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getActionCurrentTime: (ctx: NetscriptContext) => (): number => {
@ -149,14 +149,14 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
1000;
return timecomputed;
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getActionEstimatedSuccessChance:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): [number, number] => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.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);
if (typeof chance === "string") {
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
ctx.log(() => errorLogText);
helpers.log(ctx, () => errorLogText);
return [-1, -1];
} else {
return chance;
}
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getActionRepGain:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _level: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const level = ctx.helper.number("level", _level);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
const level = helpers.number(ctx, "level", _level);
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name);
let rewardMultiplier;
@ -193,22 +193,22 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionCountRemaining:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.getActionCountRemainingNetscriptFn(type, name, workerScript);
return bladeburner.getActionCountRemainingNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getActionMaxLevel:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name);
return action.maxLevel;
@ -216,8 +216,8 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionCurrentLevel:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name);
return action.level;
@ -225,8 +225,8 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getActionAutolevel:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): boolean => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name);
return action.autoLevel;
@ -234,9 +234,9 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
setActionAutolevel:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _autoLevel: unknown = true): void => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const autoLevel = ctx.helper.boolean(_autoLevel);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
const autoLevel = !!_autoLevel;
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name);
action.autoLevel = autoLevel;
@ -244,13 +244,13 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
setActionLevel:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _level: unknown = 1): void => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const level = ctx.helper.number("level", _level);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
const level = helpers.number(ctx, "level", _level);
checkBladeburnerAccess(ctx);
const action = getBladeburnerActionObject(ctx, type, name);
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;
},
@ -269,77 +269,77 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getSkillLevel:
(ctx: NetscriptContext) =>
(_skillName: unknown): number => {
const skillName = ctx.helper.string("skillName", _skillName);
const skillName = helpers.string(ctx, "skillName", _skillName);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.getSkillLevelNetscriptFn(skillName, workerScript);
return bladeburner.getSkillLevelNetscriptFn(skillName, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getSkillUpgradeCost:
(ctx: NetscriptContext) =>
(_skillName: unknown, _count: unknown = 1): number => {
const skillName = ctx.helper.string("skillName", _skillName);
const count = ctx.helper.number("count", _count);
const skillName = helpers.string(ctx, "skillName", _skillName);
const count = helpers.number(ctx, "count", _count);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, count, workerScript);
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, count, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
upgradeSkill:
(ctx: NetscriptContext) =>
(_skillName: unknown, _count: unknown = 1): boolean => {
const skillName = ctx.helper.string("skillName", _skillName);
const count = ctx.helper.number("count", _count);
const skillName = helpers.string(ctx, "skillName", _skillName);
const count = helpers.number(ctx, "count", _count);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.upgradeSkillNetscriptFn(skillName, count, workerScript);
return bladeburner.upgradeSkillNetscriptFn(skillName, count, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getTeamSize:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.getTeamSizeNetscriptFn(type, name, workerScript);
return bladeburner.getTeamSizeNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
setTeamSize:
(ctx: NetscriptContext) =>
(_type: unknown, _name: unknown, _size: unknown): number => {
const type = ctx.helper.string("type", _type);
const name = ctx.helper.string("name", _name);
const size = ctx.helper.number("size", _size);
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
const size = helpers.number(ctx, "size", _size);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
try {
return bladeburner.setTeamSizeNetscriptFn(type, name, size, workerScript);
return bladeburner.setTeamSizeNetscriptFn(type, name, size, ctx.workerScript);
} catch (e: unknown) {
throw ctx.makeRuntimeErrorMsg(String(e));
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
getCityEstimatedPopulation:
(ctx: NetscriptContext) =>
(_cityName: unknown): number => {
const cityName = ctx.helper.string("cityName", _cityName);
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
@ -349,7 +349,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getCityCommunities:
(ctx: NetscriptContext) =>
(_cityName: unknown): number => {
const cityName = ctx.helper.string("cityName", _cityName);
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
@ -359,7 +359,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
getCityChaos:
(ctx: NetscriptContext) =>
(_cityName: unknown): number => {
const cityName = ctx.helper.string("cityName", _cityName);
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
@ -375,7 +375,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
switchCity:
(ctx: NetscriptContext) =>
(_cityName: unknown): boolean => {
const cityName = ctx.helper.string("cityName", _cityName);
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
@ -393,7 +393,7 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
checkBladeburnerAccess(ctx, true);
const bladeburner = player.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 => {
if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) {
@ -409,11 +409,11 @@ export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript
player.skills.agility >= 100
) {
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;
} 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;
}
}

@ -1,21 +1,21 @@
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player as player } from "../Player";
import { is2DArray } from "../utils/helpers/is2DArray";
import { CodingContract } from "../CodingContracts";
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 (
ctx: NetscriptContext,
func: string,
hostname: string,
filename: string,
): CodingContract {
const server = ctx.helper.getServer(hostname);
const server = helpers.getServer(ctx, hostname);
const contract = server.getContract(filename);
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;
@ -27,11 +27,11 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
(
answer: unknown,
_filename: unknown,
_hostname: unknown = workerScript.hostname,
_hostname: unknown = ctx.workerScript.hostname,
{ returnReward }: CodingAttemptOptions = { returnReward: false },
): boolean | string => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
const filename = helpers.string(ctx, "filename", _filename);
const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "attempt", hostname, filename);
// 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;
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)) {
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);
return returnReward ? reward : true;
} else {
++contract.tries;
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);
} else {
ctx.log(
helpers.log(
ctx,
() =>
`Coding Contract attempt '${filename}' failed. ${
contract.getMaxNumTries() - contract.tries
@ -76,17 +77,17 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
},
getContractType:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
(_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): string => {
const filename = helpers.string(ctx, "filename", _filename);
const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getContractType", hostname, filename);
return contract.getType();
},
getData:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): unknown => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
(_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): unknown => {
const filename = helpers.string(ctx, "filename", _filename);
const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getData", hostname, filename);
const data = contract.getData();
if (Array.isArray(data)) {
@ -107,17 +108,17 @@ export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScr
},
getDescription:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
(_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): string => {
const filename = helpers.string(ctx, "filename", _filename);
const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getDescription", hostname, filename);
return contract.getDescription();
},
getNumTriesRemaining:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): number => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
(_filename: unknown, _hostname: unknown = ctx.workerScript.hostname): number => {
const filename = helpers.string(ctx, "filename", _filename);
const hostname = helpers.string(ctx, "hostname", _hostname);
const contract = getCodingContract(ctx, "getNumTriesRemaining", hostname, filename);
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 { Employee } from "../Corporation/Employee";
@ -65,9 +65,10 @@ import { CorporationConstants } from "../Corporation/data/Constants";
import { ResearchMap } from "../Corporation/ResearchMap";
import { Factions } from "../Faction/Factions";
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 {
if (!player.canAccessCorporation() || player.hasCorporation()) return false;
if (!corporationName) return false;
@ -101,7 +102,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
}
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 upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === 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 {
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation();
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === 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 {
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 (!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 {
@ -314,11 +316,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): number => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const amt = ctx.helper.number("amount", _amt);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const amt = helpers.number(ctx, "amount", _amt);
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);
return UpgradeWarehouseCost(warehouse, amt);
@ -327,8 +329,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): boolean => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const division = getDivision(divisionName);
if (!(cityName in division.warehouses)) throw new Error(`Invalid city name '${cityName}'`);
const warehouse = division.warehouses[cityName];
@ -338,8 +340,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): NSWarehouse => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const warehouse = getWarehouse(divisionName, cityName);
return {
level: warehouse.level,
@ -353,9 +355,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown): NSMaterial => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const material = getMaterial(divisionName, cityName, materialName);
const corporation = getCorporation();
return {
@ -374,8 +376,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown): NSProduct => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = helpers.string(ctx, "productName", _productName);
const product = getProduct(divisionName, productName);
const corporation = getCorporation();
return {
@ -401,8 +403,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const corporation = getCorporation();
PurchaseWarehouse(corporation, getDivision(divisionName), cityName);
},
@ -410,12 +412,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const amt = ctx.helper.number("amount", _amt);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const amt = helpers.number(ctx, "amount", _amt);
const corporation = getCorporation();
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);
},
@ -423,11 +425,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown, _price: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const amt = ctx.helper.string("amt", _amt);
const price = ctx.helper.string("price", _price);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = helpers.string(ctx, "amt", _amt);
const price = helpers.string(ctx, "price", _price);
const material = getMaterial(divisionName, cityName, materialName);
SellMaterial(material, amt, price);
},
@ -442,12 +444,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_all: unknown,
): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const productName = ctx.helper.string("productName", _productName);
const amt = ctx.helper.string("amt", _amt);
const price = ctx.helper.string("price", _price);
const all = ctx.helper.boolean(_all);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const productName = helpers.string(ctx, "productName", _productName);
const amt = helpers.string(ctx, "amt", _amt);
const price = helpers.string(ctx, "price", _price);
const all = !!_all;
const product = getProduct(divisionName, productName);
SellProduct(product, cityName, amt, price, all);
},
@ -455,44 +457,44 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = helpers.string(ctx, "productName", _productName);
getDivision(divisionName).discontinueProduct(getProduct(divisionName, productName));
},
setSmartSupply:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _enabled: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const enabled = ctx.helper.boolean(_enabled);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const enabled = !!_enabled;
const warehouse = getWarehouse(divisionName, cityName);
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);
},
setSmartSupplyUseLeftovers:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _enabled: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const enabled = ctx.helper.boolean(_enabled);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const enabled = !!_enabled;
const warehouse = getWarehouse(divisionName, cityName);
const material = getMaterial(divisionName, cityName, materialName);
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);
},
buyMaterial:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const amt = ctx.helper.number("amt", _amt);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
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");
const material = getMaterial(divisionName, cityName, materialName);
BuyMaterial(material, amt);
@ -501,13 +503,13 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
if (!hasResearched(getDivision(divisionName), "Bulk Purchasing"))
throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`);
const corporation = getCorporation();
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const amt = ctx.helper.number("amt", _amt);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = helpers.number(ctx, "amt", _amt);
const warehouse = getWarehouse(divisionName, cityName);
const material = getMaterial(divisionName, cityName, materialName);
BulkPurchase(corporation, warehouse, material, amt);
@ -522,11 +524,11 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_marketingInvest: unknown,
): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const productName = ctx.helper.string("productName", _productName);
const designInvest = ctx.helper.number("designInvest", _designInvest);
const marketingInvest = ctx.helper.number("marketingInvest", _marketingInvest);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const productName = helpers.string(ctx, "productName", _productName);
const designInvest = helpers.number(ctx, "designInvest", _designInvest);
const marketingInvest = helpers.number(ctx, "marketingInvest", _marketingInvest);
const corporation = getCorporation();
MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest);
},
@ -534,10 +536,10 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown, _cityName: unknown, _qty: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const productName = ctx.helper.string("productName", _productName);
const qty = ctx.helper.number("qty", _qty);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const productName = helpers.string(ctx, "productName", _productName);
const qty = helpers.number(ctx, "qty", _qty);
LimitProductProduction(getProduct(divisionName, productName), cityName, qty);
},
exportMaterial:
@ -551,12 +553,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_amt: unknown,
): void => {
checkAccess(ctx, 7);
const sourceDivision = ctx.helper.string("sourceDivision", _sourceDivision);
const sourceCity = ctx.helper.string("sourceCity", _sourceCity);
const targetDivision = ctx.helper.string("targetDivision", _targetDivision);
const targetCity = ctx.helper.string("targetCity", _targetCity);
const materialName = ctx.helper.string("materialName", _materialName);
const amt = ctx.helper.string("amt", _amt);
const sourceDivision = helpers.string(ctx, "sourceDivision", _sourceDivision);
const sourceCity = helpers.string(ctx, "sourceCity", _sourceCity);
const targetDivision = helpers.string(ctx, "targetDivision", _targetDivision);
const targetCity = helpers.string(ctx, "targetCity", _targetCity);
const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = helpers.string(ctx, "amt", _amt);
ExportMaterial(
targetDivision,
targetCity,
@ -576,12 +578,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
_amt: unknown,
): void => {
checkAccess(ctx, 7);
const sourceDivision = ctx.helper.string("sourceDivision", _sourceDivision);
const sourceCity = ctx.helper.string("sourceCity", _sourceCity);
const targetDivision = ctx.helper.string("targetDivision", _targetDivision);
const targetCity = ctx.helper.string("targetCity", _targetCity);
const materialName = ctx.helper.string("materialName", _materialName);
const amt = ctx.helper.string("amt", _amt);
const sourceDivision = helpers.string(ctx, "sourceDivision", _sourceDivision);
const sourceCity = helpers.string(ctx, "sourceCity", _sourceCity);
const targetDivision = helpers.string(ctx, "targetDivision", _targetDivision);
const targetCity = helpers.string(ctx, "targetCity", _targetCity);
const materialName = helpers.string(ctx, "materialName", _materialName);
const amt = helpers.string(ctx, "amt", _amt);
CancelExportMaterial(
targetDivision,
targetCity,
@ -593,56 +595,56 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _qty: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const qty = ctx.helper.number("qty", _qty);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const qty = helpers.number(ctx, "qty", _qty);
LimitMaterialProduction(getMaterial(divisionName, cityName, materialName), qty);
},
setMaterialMarketTA1:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _on: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const on = ctx.helper.boolean(_on);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const on = !!_on;
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);
},
setMaterialMarketTA2:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _materialName: unknown, _on: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const materialName = ctx.helper.string("materialName", _materialName);
const on = ctx.helper.boolean(_on);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const materialName = helpers.string(ctx, "materialName", _materialName);
const on = !!_on;
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);
},
setProductMarketTA1:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown, _on: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName);
const on = ctx.helper.boolean(_on);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = helpers.string(ctx, "productName", _productName);
const on = !!_on;
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);
},
setProductMarketTA2:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _productName: unknown, _on: unknown): void => {
checkAccess(ctx, 7);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const productName = ctx.helper.string("productName", _productName);
const on = ctx.helper.boolean(_on);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const productName = helpers.string(ctx, "productName", _productName);
const on = !!_on;
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);
},
};
@ -652,7 +654,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown): number => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const division = getDivision(divisionName);
return division.getAdVertCost();
},
@ -660,7 +662,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown): number => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const division = getDivision(divisionName);
return division.numAdVerts;
},
@ -668,25 +670,25 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _researchName: unknown): number => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const researchName = ctx.helper.string("researchName", _researchName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const researchName = helpers.string(ctx, "researchName", _researchName);
return getResearchCost(getDivision(divisionName), researchName);
},
hasResearched:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _researchName: unknown): boolean => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const researchName = ctx.helper.string("researchName", _researchName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const researchName = helpers.string(ctx, "researchName", _researchName);
return hasResearched(getDivision(divisionName), researchName);
},
getOfficeSizeUpgradeCost:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): number => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const size = ctx.helper.number("size", _size);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
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");
const office = getOffice(divisionName, cityName);
const initialPriceMult = Math.round(office.size / CorporationConstants.OfficeInitialSize);
@ -701,10 +703,10 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): void => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName);
const job = ctx.helper.string("job", _job);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const employeeName = helpers.string(ctx, "employeeName", _employeeName);
const job = helpers.string(ctx, "job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName);
@ -715,10 +717,10 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): boolean => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const amount = ctx.helper.number("amount", _amount);
const job = ctx.helper.string("job", _job);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const amount = helpers.number(ctx, "amount", _amount);
const job = helpers.string(ctx, "job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName);
@ -729,8 +731,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): NSEmployee | undefined => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const office = getOffice(divisionName, cityName);
const employee = office.hireRandomEmployee();
if (employee === undefined) return undefined;
@ -753,9 +755,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): void => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const size = ctx.helper.number("size", _size);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
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");
const office = getOffice(divisionName, cityName);
const corporation = getCorporation();
@ -765,9 +767,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): number => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const costPerEmployee = ctx.helper.number("costPerEmployee", _costPerEmployee);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const costPerEmployee = helpers.number(ctx, "costPerEmployee", _costPerEmployee);
if (costPerEmployee < 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) =>
(_divisionName: unknown, _cityName: unknown): boolean => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const corporation = getCorporation();
const office = getOffice(divisionName, cityName);
@ -794,7 +796,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown): void => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const corporation = getCorporation();
HireAdVert(corporation, getDivision(divisionName));
},
@ -802,16 +804,16 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _researchName: unknown): void => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const researchName = ctx.helper.string("researchName", _researchName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const researchName = helpers.string(ctx, "researchName", _researchName);
Research(getDivision(divisionName), researchName);
},
getOffice:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): NSOffice => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const office = getOffice(divisionName, cityName);
return {
loc: office.loc,
@ -847,9 +849,9 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown): NSEmployee => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
const employeeName = helpers.string(ctx, "employeeName", _employeeName);
const employee = getEmployee(divisionName, cityName, employeeName);
return {
name: employee.name,
@ -871,37 +873,27 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
return {
...warehouseAPI,
...officeAPI,
getMaterialNames:
(ctx: NetscriptContext) =>
(): string[] =>{
getMaterialNames: () => (): string[] => {
return CorporationConstants.AllMaterials;
},
getIndustryTypes:
(ctx: NetscriptContext) =>
(): string[] =>{
},
getIndustryTypes: () => (): string[] => {
return CorporationConstants.AllIndustryTypes;
},
getUnlockables:
(ctx: NetscriptContext) =>
(): string[] =>{
},
getUnlockables: () => (): string[] => {
return CorporationConstants.AllUnlocks;
},
getUpgradeNames:
(ctx: NetscriptContext) =>
(): string[] =>{
},
getUpgradeNames: () => (): string[] => {
return CorporationConstants.AllUpgrades;
},
getResarchNames:
(ctx: NetscriptContext) =>
(): string[] =>{
},
getResearchNames: () => (): string[] => {
return CorporationConstants.AllResearch;
},
},
expandIndustry:
(ctx: NetscriptContext) =>
(_industryName: unknown, _divisionName: unknown): void => {
checkAccess(ctx);
const industryName = ctx.helper.string("industryName", _industryName);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const industryName = helpers.string(ctx, "industryName", _industryName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const corporation = getCorporation();
NewIndustry(corporation, industryName, divisionName);
},
@ -909,8 +901,8 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown): void => {
checkAccess(ctx);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const cityName = helpers.city(ctx, "cityName", _cityName);
if (!CorporationConstants.Cities.includes(cityName)) throw new Error("Invalid city name");
const corporation = getCorporation();
const division = getDivision(divisionName);
@ -920,7 +912,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_upgradeName: unknown): void => {
checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation();
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade.name === upgradeName);
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
@ -930,7 +922,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_upgradeName: unknown): void => {
checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
const corporation = getCorporation();
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
@ -940,12 +932,12 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_rate: unknown): void => {
checkAccess(ctx);
const rate = ctx.helper.number("rate", _rate);
const rate = helpers.number(ctx, "rate", _rate);
const max = CorporationConstants.DividendMaxRate;
if (rate < 0 || rate > max)
throw new Error(`Invalid value for rate field! Must be numeric, greater than 0, and less than ${max}`);
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);
},
@ -955,7 +947,7 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_divisionName: unknown): NSDivision => {
checkAccess(ctx);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
const division = getDivision(divisionName);
return getSafeDivision(division);
},
@ -983,43 +975,43 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
createCorporation:
(ctx: NetscriptContext) =>
(_corporationName: unknown, _selfFund: unknown = true): boolean => {
const corporationName = ctx.helper.string("corporationName", _corporationName);
const selfFund = ctx.helper.boolean(_selfFund);
const corporationName = helpers.string(ctx, "corporationName", _corporationName);
const selfFund = !_selfFund;
return createCorporation(corporationName, selfFund);
},
hasUnlockUpgrade:
(ctx: NetscriptContext) =>
(_upgradeName: unknown): boolean => {
checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return hasUnlockUpgrade(upgradeName);
},
getUnlockUpgradeCost:
(ctx: NetscriptContext) =>
(_upgradeName: unknown): number => {
checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return getUnlockUpgradeCost(upgradeName);
},
getUpgradeLevel:
(ctx: NetscriptContext) =>
(_upgradeName: unknown): number => {
checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return getUpgradeLevel(ctx, upgradeName);
},
getUpgradeLevelCost:
(ctx: NetscriptContext) =>
(_upgradeName: unknown): number => {
checkAccess(ctx);
const upgradeName = ctx.helper.string("upgradeName", _upgradeName);
const upgradeName = helpers.string(ctx, "upgradeName", _upgradeName);
return getUpgradeLevelCost(ctx, upgradeName);
},
getExpandIndustryCost:
(ctx: NetscriptContext) =>
(_industryName: unknown): number => {
checkAccess(ctx);
const industryName = ctx.helper.string("industryName", _industryName);
const industryName = helpers.string(ctx, "industryName", _industryName);
return getExpandIndustryCost(industryName);
},
getExpandCityCost: (ctx: NetscriptContext) => (): number => {
@ -1038,29 +1030,29 @@ export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation
(ctx: NetscriptContext) =>
(_numShares: unknown): boolean => {
checkAccess(ctx);
const numShares = ctx.helper.number("numShares", _numShares);
const numShares = helpers.number(ctx, "numShares", _numShares);
return goPublic(numShares);
},
sellShares:
(ctx: NetscriptContext) =>
(_numShares: unknown): number => {
checkAccess(ctx);
const numShares = ctx.helper.number("numShares", _numShares);
const numShares = helpers.number(ctx, "numShares", _numShares);
return SellShares(getCorporation(), player, numShares);
},
buyBackShares:
(ctx: NetscriptContext) =>
(_numShares: unknown): boolean => {
checkAccess(ctx);
const numShares = ctx.helper.number("numShares", _numShares);
const numShares = helpers.number(ctx, "numShares", _numShares);
return BuyBackShares(getCorporation(), player, numShares);
},
bribe:
(ctx: NetscriptContext) =>
(_factionName: unknown, _amountCash: unknown): boolean => {
checkAccess(ctx);
const factionName = ctx.helper.string("factionName", _factionName);
const amountCash = ctx.helper.number("amountCash", _amountCash);
const factionName = helpers.string(ctx, "factionName", _factionName);
const amountCash = helpers.number(ctx, "amountCash", _amountCash);
return bribe(factionName, amountCash);
},
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 * as bcrypt from "bcryptjs";
import { Apr1Events as devMenu } from "../ui/Apr1";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers";
export interface INetscriptExtra {
heart: {
@ -15,7 +16,7 @@ export interface INetscriptExtra {
rainbow(guess: string): void;
}
export function NetscriptExtra(player: IPlayer): InternalAPI<INetscriptExtra> {
export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
return {
heart: {
// Easter egg function
@ -67,7 +68,7 @@ export function NetscriptExtra(player: IPlayer): InternalAPI<INetscriptExtra> {
function tryGuess(): boolean {
// eslint-disable-next-line no-sync
const verified = bcrypt.compareSync(
ctx.helper.string("guess", guess),
helpers.string(ctx, "guess", guess),
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO",
);
if (verified) {

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

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

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

@ -4,15 +4,17 @@ import { hasAugmentationPrereqs } from "../Faction/FactionHelpers";
import { CityName } from "../Locations/data/CityNames";
import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation";
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 { Router } from "../ui/GameRoot";
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 => {
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",
);
}
@ -22,10 +24,10 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
getAugmentationGraftPrice:
(ctx: NetscriptContext) =>
(_augName: unknown): number => {
const augName = ctx.helper.string("augName", _augName);
const augName = helpers.string(ctx, "augName", _augName);
checkGraftingAPIAccess(ctx);
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]);
return graftableAug.cost;
@ -34,10 +36,10 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
getAugmentationGraftTime:
(ctx: NetscriptContext) =>
(_augName: string): number => {
const augName = ctx.helper.string("augName", _augName);
const augName = helpers.string(ctx, "augName", _augName);
checkGraftingAPIAccess(ctx);
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]);
return calculateGraftingTimeWithBonus(player, graftableAug);
@ -52,14 +54,14 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
graftAugmentation:
(ctx: NetscriptContext) =>
(_augName: string, _focus: unknown = true): boolean => {
const augName = ctx.helper.string("augName", _augName);
const focus = ctx.helper.boolean(_focus);
const augName = helpers.string(ctx, "augName", _augName);
const focus = !!_focus;
checkGraftingAPIAccess(ctx);
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)) {
ctx.log(() => `Invalid aug: ${augName}`);
helpers.log(ctx, () => `Invalid aug: ${augName}`);
return false;
}
@ -67,12 +69,12 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
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;
}
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;
}
@ -92,7 +94,7 @@ export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
Router.toTerminal();
}
ctx.log(() => `Began grafting Augmentation ${augName}.`);
helpers.log(ctx, () => `Began grafting Augmentation ${augName}.`);
return true;
},
};

@ -1,5 +1,4 @@
import { IPlayer } from "../PersonObjects/IPlayer";
import { WorkerScript } from "../Netscript/WorkerScript";
import { Player as player } from "../Player";
import { HacknetServerConstants } from "../Hacknet/data/Constants";
import {
getCostOfNextHacknetNode,
@ -21,12 +20,13 @@ import { GetServer } from "../Server/AllServers";
import { Hacknet as IHacknet, NodeStats } from "../ScriptEditor/NetscriptDefinitions";
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
const getHacknetNode = function (ctx: NetscriptContext, i: number): HacknetNode | HacknetServer {
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)) {
@ -35,7 +35,8 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
const hserver = GetServer(hi);
if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server");
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`,
);
}
@ -71,7 +72,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
getNodeStats:
(ctx: NetscriptContext) =>
(_i: unknown): NodeStats => {
const i = ctx.helper.number("i", _i);
const i = helpers.number(ctx, "i", _i);
const node = getHacknetNode(ctx, i);
const hasUpgraded = hasHacknetServers(player);
const res: NodeStats = {
@ -95,38 +96,38 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
upgradeLevel:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return purchaseLevelUpgrade(player, node, n);
},
upgradeRam:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return purchaseRamUpgrade(player, node, n);
},
upgradeCore:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return purchaseCoreUpgrade(player, node, n);
},
upgradeCache:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
if (!hasHacknetServers(player)) {
return false;
}
const node = getHacknetNode(ctx, i);
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;
}
const res = purchaseCacheUpgrade(player, node, n);
@ -138,38 +139,38 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
getLevelUpgradeCost:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return node.calculateLevelUpgradeCost(n, player.mults.hacknet_node_level_cost);
},
getRamUpgradeCost:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return node.calculateRamUpgradeCost(n, player.mults.hacknet_node_ram_cost);
},
getCoreUpgradeCost:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return node.calculateCoreUpgradeCost(n, player.mults.hacknet_node_core_cost);
},
getCacheUpgradeCost:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): number => {
const i = ctx.helper.number("i", _i);
const n = ctx.helper.number("n", _n);
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
if (!hasHacknetServers(player)) {
return Infinity;
}
const node = getHacknetNode(ctx, i);
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 node.calculateCacheUpgradeCost(n);
@ -189,8 +190,8 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
hashCost:
(ctx: NetscriptContext) =>
(_upgName: unknown, _count: unknown = 1): number => {
const upgName = ctx.helper.string("upgName", _upgName);
const count = ctx.helper.number("count", _count);
const upgName = helpers.string(ctx, "upgName", _upgName);
const count = helpers.number(ctx, "count", _count);
if (!hasHacknetServers(player)) {
return Infinity;
}
@ -200,9 +201,9 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
spendHashes:
(ctx: NetscriptContext) =>
(_upgName: unknown, _upgTarget: unknown = "", _count: unknown = 1): boolean => {
const upgName = ctx.helper.string("upgName", _upgName);
const upgTarget = ctx.helper.string("upgTarget", _upgTarget);
const count = ctx.helper.number("count", _count);
const upgName = helpers.string(ctx, "upgName", _upgName);
const upgTarget = helpers.string(ctx, "upgTarget", _upgTarget);
const count = helpers.number(ctx, "count", _count);
if (!hasHacknetServers(player)) {
return false;
}
@ -217,10 +218,10 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): I
getHashUpgradeLevel:
(ctx: NetscriptContext) =>
(_upgName: unknown): number => {
const upgName = ctx.helper.string("upgName", _upgName);
const upgName = helpers.string(ctx, "upgName", _upgName);
const level = player.hashManager.upgrades[upgName];
if (level === undefined) {
throw ctx.makeRuntimeErrorMsg(`Invalid Hash Upgrade: ${upgName}`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid Hash Upgrade: ${upgName}`);
}
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 {
Infiltration as IInfiltration,
@ -18,8 +18,9 @@ import { Factions } from "../Faction/Factions";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { checkEnum } from "../utils/helpers/checkEnum";
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(
(location: Location) => location.infiltrationData,
);
@ -27,9 +28,9 @@ export function NetscriptInfiltration(player: IPlayer): InternalAPI<IInfiltratio
const calculateInfiltrationData = (ctx: NetscriptContext, locationName: string): InfiltrationLocation => {
if (!checkEnum(LocationName, locationName)) throw new Error(`Location '${locationName}' does not exists.`);
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)
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 difficulty = calculateDifficulty(player, startingSecurityLevel);
const reward = calculateReward(player, startingSecurityLevel);
@ -54,7 +55,7 @@ export function NetscriptInfiltration(player: IPlayer): InternalAPI<IInfiltratio
getInfiltration:
(ctx: NetscriptContext) =>
(_location: unknown): InfiltrationLocation => {
const location = ctx.helper.string("location", _location);
const location = helpers.string(ctx, "location", _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 { StaticAugmentations } from "../Augmentation/StaticAugmentations";
import { CityName } from "../Locations/data/CityNames";
@ -17,11 +17,13 @@ import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork";
import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork";
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 {
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",
);
}
@ -30,8 +32,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
const checkSleeveNumber = function (ctx: NetscriptContext, sleeveNumber: number): void {
if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) {
const msg = `Invalid sleeve number: ${sleeveNumber}`;
ctx.log(() => msg);
throw ctx.makeRuntimeErrorMsg(msg);
helpers.log(ctx, () => msg);
throw helpers.makeRuntimeErrorMsg(ctx, msg);
}
};
@ -58,7 +60,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToShockRecovery:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].shockRecovery(player);
@ -66,7 +68,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToSynchronize:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].synchronize(player);
@ -74,8 +76,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToCommitCrime:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _crimeRoughName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const crimeRoughName = ctx.helper.string("crimeName", _crimeRoughName);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const crimeRoughName = helpers.string(ctx, "crimeName", _crimeRoughName);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
const crime = findCrime(crimeRoughName);
@ -87,9 +89,9 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToUniversityCourse:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _universityName: unknown, _className: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const universityName = ctx.helper.string("universityName", _universityName);
const className = ctx.helper.string("className", _className);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const universityName = helpers.string(ctx, "universityName", _universityName);
const className = helpers.string(ctx, "className", _className);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
@ -97,21 +99,21 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
travel:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _cityName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const cityName = ctx.helper.string("cityName", _cityName);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const cityName = helpers.string(ctx, "cityName", _cityName);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
if (checkEnum(CityName, cityName)) {
return player.sleeves[sleeveNumber].travel(player, cityName);
} else {
throw ctx.makeRuntimeErrorMsg(`Invalid city name: '${cityName}'.`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city name: '${cityName}'.`);
}
},
setToCompanyWork:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, acompanyName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const companyName = ctx.helper.string("companyName", acompanyName);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const companyName = helpers.string(ctx, "companyName", acompanyName);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -122,7 +124,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
}
const other = player.sleeves[i];
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.`,
);
}
@ -133,9 +136,9 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToFactionWork:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _factionName: unknown, _workType: unknown): boolean | undefined => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const factionName = ctx.helper.string("factionName", _factionName);
const workType = ctx.helper.string("workType", _workType);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const factionName = helpers.string(ctx, "factionName", _factionName);
const workType = helpers.string(ctx, "workType", _workType);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -146,14 +149,16 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
}
const other = player.sleeves[i];
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.`,
);
}
}
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.`,
);
}
@ -163,9 +168,9 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
setToGymWorkout:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _gymName: unknown, _stat: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const gymName = ctx.helper.string("gymName", _gymName);
const stat = ctx.helper.string("stat", _stat);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const gymName = helpers.string(ctx, "gymName", _gymName);
const stat = helpers.string(ctx, "stat", _stat);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -174,7 +179,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getSleeveStats:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): SleeveSkills => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return getSleeveStats(sleeveNumber);
@ -182,7 +187,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getTask:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): SleeveTask | null => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -193,7 +198,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getInformation:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): SleeveInformation => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -229,7 +234,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getSleeveAugmentations:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): string[] => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -242,7 +247,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
getSleevePurchasableAugs:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown): AugmentPair[] => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -261,18 +266,18 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
purchaseSleeveAug:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _augName: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const augName = ctx.helper.string("augName", _augName);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const augName = helpers.string(ctx, "augName", _augName);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
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];
if (!aug) {
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
}
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
@ -281,7 +286,7 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
(ctx: NetscriptContext) =>
(_augName: unknown): number => {
checkSleeveAPIAccess(ctx);
const augName = ctx.helper.string("augName", _augName);
const augName = helpers.string(ctx, "augName", _augName);
const aug: Augmentation = StaticAugmentations[augName];
return aug.baseCost;
},
@ -289,20 +294,20 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
(ctx: NetscriptContext) =>
(_augName: unknown): number => {
checkSleeveAPIAccess(ctx);
const augName = ctx.helper.string("augName", _augName);
const augName = helpers.string(ctx, "augName", _augName);
const aug: Augmentation = StaticAugmentations[augName];
return aug.getCost(player).repCost;
},
setToBladeburnerAction:
(ctx: NetscriptContext) =>
(_sleeveNumber: unknown, _action: unknown, _contract?: unknown): boolean => {
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
const action = ctx.helper.string("action", _action);
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const action = helpers.string(ctx, "action", _action);
let contract: string;
if (typeof _contract === "undefined") {
contract = "------";
} else {
contract = ctx.helper.string("contract", _contract);
contract = helpers.string(ctx, "contract", _contract);
}
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
@ -315,7 +320,8 @@ export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
}
const other = player.sleeves[i];
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.`,
);
}

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

@ -1,5 +1,4 @@
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player as player } from "../Player";
import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling";
import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder, initStockMarketFn } from "../StockMarket/StockMarket";
import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers";
@ -14,25 +13,26 @@ import {
} from "../StockMarket/StockMarketCosts";
import { Stock } from "../StockMarket/Stock";
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
*/
const checkTixApiAccess = function (ctx: NetscriptContext): void {
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) {
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 stock = SymbolToStockMap[symbol];
if (stock == null) {
throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: '${symbol}'`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid stock symbol: '${symbol}'`);
}
return stock;
@ -58,7 +58,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getPrice:
(ctx: NetscriptContext) =>
(_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
@ -67,7 +67,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getAskPrice:
(ctx: NetscriptContext) =>
(_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
@ -76,7 +76,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getBidPrice:
(ctx: NetscriptContext) =>
(_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
@ -85,18 +85,18 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getPosition:
(ctx: NetscriptContext) =>
(_symbol: unknown): [number, number, number, number] => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx);
const stock = SymbolToStockMap[symbol];
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];
},
getMaxShares:
(ctx: NetscriptContext) =>
(_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
@ -105,9 +105,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getPurchaseCost:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _posType: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
let shares = ctx.helper.number("shares", _shares);
const posType = ctx.helper.string("posType", _posType);
const symbol = helpers.string(ctx, "symbol", _symbol);
let shares = helpers.number(ctx, "shares", _shares);
const posType = helpers.string(ctx, "posType", _posType);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
shares = Math.round(shares);
@ -132,9 +132,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getSaleGain:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _posType: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
let shares = ctx.helper.number("shares", _shares);
const posType = ctx.helper.string("posType", _posType);
const symbol = helpers.string(ctx, "symbol", _symbol);
let shares = helpers.number(ctx, "shares", _shares);
const posType = helpers.string(ctx, "posType", _posType);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
shares = Math.round(shares);
@ -159,68 +159,77 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
buyStock:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const shares = ctx.helper.number("shares", _shares);
const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
const res = buyStock(stock, shares, workerScript, {});
const res = buyStock(stock, shares, ctx.workerScript, {});
return res ? stock.getAskPrice() : 0;
},
sellStock:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const shares = ctx.helper.number("shares", _shares);
const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx);
const stock = getStockFromSymbol(ctx, symbol);
const res = sellStock(stock, shares, workerScript, {});
const res = sellStock(stock, shares, ctx.workerScript, {});
return res ? stock.getBidPrice() : 0;
},
buyShort:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const shares = ctx.helper.number("shares", _shares);
const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) {
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 res = shortStock(stock, shares, workerScript, {});
const res = shortStock(stock, shares, ctx.workerScript, {});
return res ? stock.getBidPrice() : 0;
},
sellShort:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const shares = ctx.helper.number("shares", _shares);
const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = helpers.number(ctx, "shares", _shares);
checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) {
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 res = sellShort(stock, shares, workerScript, {});
const res = sellShort(stock, shares, ctx.workerScript, {});
return res ? stock.getAskPrice() : 0;
},
placeOrder:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => {
const symbol = ctx.helper.string("symbol", _symbol);
const shares = ctx.helper.number("shares", _shares);
const price = ctx.helper.number("price", _price);
const type = ctx.helper.string("type", _type);
const pos = ctx.helper.string("pos", _pos);
const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = helpers.number(ctx, "shares", _shares);
const price = helpers.number(ctx, "price", _price);
const type = helpers.string(ctx, "type", _type);
const pos = helpers.string(ctx, "pos", _pos);
checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) {
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);
@ -237,7 +246,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (ltype.includes("stop") && ltype.includes("sell")) {
orderType = OrderTypes.StopSell;
} else {
throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid order type: ${type}`);
}
const lpos = pos.toLowerCase();
@ -246,28 +255,34 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (lpos.includes("s")) {
orderPos = PositionTypes.Short;
} 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:
(ctx: NetscriptContext) =>
(_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => {
const symbol = ctx.helper.string("symbol", _symbol);
const shares = ctx.helper.number("shares", _shares);
const price = ctx.helper.number("price", _price);
const type = ctx.helper.string("type", _type);
const pos = ctx.helper.string("pos", _pos);
const symbol = helpers.string(ctx, "symbol", _symbol);
const shares = helpers.number(ctx, "shares", _shares);
const price = helpers.number(ctx, "price", _price);
const type = helpers.string(ctx, "type", _type);
const pos = helpers.string(ctx, "pos", _pos);
checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) {
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);
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 orderPos;
@ -281,7 +296,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (ltype.includes("stop") && ltype.includes("sell")) {
orderType = OrderTypes.StopSell;
} else {
throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid order type: ${type}`);
}
const lpos = pos.toLowerCase();
@ -290,7 +305,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
} else if (lpos.includes("s")) {
orderPos = PositionTypes.Short;
} else {
throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid position type: ${pos}`);
}
const params = {
stock: stock,
@ -299,13 +314,13 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
type: orderType,
pos: orderPos,
};
return cancelOrder(params, workerScript);
return cancelOrder(params, ctx.workerScript);
},
getOrders: (ctx: NetscriptContext) => (): StockOrder => {
checkTixApiAccess(ctx);
if (player.bitNodeN !== 8) {
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:
(ctx: NetscriptContext) =>
(_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
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);
@ -343,9 +358,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
getForecast:
(ctx: NetscriptContext) =>
(_symbol: unknown): number => {
const symbol = ctx.helper.string("symbol", _symbol);
const symbol = helpers.string(ctx, "symbol", _symbol);
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);
@ -355,69 +370,69 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
},
purchase4SMarketData: (ctx: NetscriptContext) => (): boolean => {
if (player.has4SData) {
ctx.log(() => "Already purchased 4S Market Data.");
helpers.log(ctx, () => "Already purchased 4S Market Data.");
return true;
}
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;
}
player.has4SData = true;
player.loseMoney(getStockMarket4SDataCost(), "stock");
ctx.log(() => "Purchased 4S Market Data");
helpers.log(ctx, () => "Purchased 4S Market Data");
return true;
},
purchase4SMarketDataTixApi: (ctx: NetscriptContext) => (): boolean => {
checkTixApiAccess(ctx);
if (player.has4SDataTixApi) {
ctx.log(() => "Already purchased 4S Market Data TIX API");
helpers.log(ctx, () => "Already purchased 4S Market Data TIX API");
return true;
}
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;
}
player.has4SDataTixApi = true;
player.loseMoney(getStockMarket4STixApiCost(), "stock");
ctx.log(() => "Purchased 4S Market Data TIX API");
helpers.log(ctx, () => "Purchased 4S Market Data TIX API");
return true;
},
purchaseWseAccount: (ctx: NetscriptContext) => (): boolean => {
if (player.hasWseAccount) {
ctx.log(() => "Already purchased WSE Account");
helpers.log(ctx, () => "Already purchased WSE Account");
return true;
}
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;
}
player.hasWseAccount = true;
initStockMarketFn();
player.loseMoney(getStockMarketWseCost(), "stock");
ctx.log(() => "Purchased WSE Account Access");
helpers.log(ctx, () => "Purchased WSE Account Access");
return true;
},
purchaseTixApi: (ctx: NetscriptContext) => (): boolean => {
if (player.hasTixApiAccess) {
ctx.log(() => "Already purchased TIX API");
helpers.log(ctx, () => "Already purchased TIX API");
return true;
}
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;
}
player.hasTixApiAccess = true;
player.loseMoney(getStockMarketTixApiCost(), "stock");
ctx.log(() => "Purchased TIX API");
helpers.log(ctx, () => "Purchased TIX API");
return true;
},
};

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

@ -5,7 +5,7 @@
import * as walk from "acorn-walk";
import { parse } from "acorn";
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
import { helpers } from "./Netscript/NetscriptHelpers";
import { ScriptUrl } from "./Script/ScriptUrl";
import { WorkerScript } from "./Netscript/WorkerScript";
import { Script } from "./Script/Script";
@ -74,18 +74,21 @@ export async function executeJSScript(
const ns = workerScript.env.vars;
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
// "SyntaxError: unexpected reserved word" with no line number information.
if (!loadedModule.main) {
throw makeRuntimeRejectMsg(
throw helpers.makeRuntimeRejectMsg(
workerScript,
`${script.filename} cannot be run because it does not have a main function.`,
);
}
if (!ns) {
throw makeRuntimeRejectMsg(
throw helpers.makeRuntimeRejectMsg(
workerScript,
`${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 { Interpreter } from "./ThirdParty/JSInterpreter";
import { isScriptErrorMessage, makeRuntimeRejectMsg } from "./NetscriptEvaluator";
import { NetscriptFunctions } from "./NetscriptFunctions";
import { executeJSScript, Node } from "./NetscriptJSEvaluator";
import { NetscriptPort, IPort } from "./NetscriptPort";
@ -29,7 +28,6 @@ import { dialogBoxCreate } from "./ui/React/DialogBox";
import { arrayToString } from "./utils/helpers/arrayToString";
import { roundToTwo } from "./utils/helpers/roundToTwo";
import { isString } from "./utils/helpers/isString";
import { sprintf } from "sprintf-js";
import { parse } from "acorn";
import { simple as walksimple } from "acorn-walk";
@ -38,6 +36,8 @@ import { Player } from "./Player";
import { Terminal } from "./Terminal";
import { IPlayer } from "./PersonObjects/IPlayer";
import { ScriptArg } from "./Netscript/ScriptArg";
import { helpers } from "./Netscript/NetscriptHelpers";
import { NS } from "./ScriptEditor/NetscriptDefinitions";
// Netscript Ports are instantiated here
export const NetscriptPorts: IPort[] = [];
@ -63,83 +63,6 @@ export function prestigeWorkerScripts(): void {
// that resolves or rejects when the corresponding worker script is done.
function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Promise<void> {
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) => {
executeJSScript(player, workerScript.getServer().scripts, workerScript)
.then(() => {
@ -149,15 +72,18 @@ function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Pro
}).catch((e) => {
if (e instanceof Error) {
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 {
workerScript.errorMessage = makeRuntimeRejectMsg(
workerScript.errorMessage = helpers.makeRuntimeRejectMsg(
workerScript,
e.message + ((e.stack && "\nstack:\n" + e.stack.toString()) || ""),
);
}
throw new ScriptDeath(workerScript);
} else if (isScriptErrorMessage(e)) {
} else if (helpers.isScriptErrorMessage(e)) {
workerScript.errorMessage = e;
throw new ScriptDeath(workerScript);
} 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
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, "" + e);
workerScript.errorMessage = helpers.makeRuntimeRejectMsg(workerScript, "" + e);
throw new ScriptDeath(workerScript);
});
}
@ -189,8 +115,11 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
}
const interpreterInitialization = function (int: Interpreter, scope: unknown): void {
interface NS1 extends NS {
[key: string]: any;
}
//Add the Netscript environment
const ns = NetscriptFunctions(workerScript);
const ns = NetscriptFunctions(workerScript) as NS1;
for (const name of Object.keys(ns)) {
const entry = ns[name];
if (typeof entry === "function") {
@ -242,7 +171,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
name === "vsprintf" ||
name === "scp" ||
name == "write" ||
name === "tryWrite" ||
name === "tryWritePort" ||
name === "run" ||
name === "exec"
) {
@ -319,8 +248,8 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
}
} catch (_e: unknown) {
let e = String(_e);
if (!isScriptErrorMessage(e)) {
e = makeRuntimeRejectMsg(workerScript, e);
if (!helpers.isScriptErrorMessage(e)) {
e = helpers.makeRuntimeRejectMsg(workerScript, e);
}
workerScript.errorMessage = e;
return reject(new ScriptDeath(workerScript));
@ -598,7 +527,7 @@ function createAndAddWorkerScript(
console.error("Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + e.toString());
return;
} else if (e instanceof ScriptDeath) {
if (isScriptErrorMessage(workerScript.errorMessage)) {
if (helpers.isScriptErrorMessage(workerScript.errorMessage)) {
const errorTextArray = workerScript.errorMessage.split("|DELIMITER|");
if (errorTextArray.length != 4) {
console.error("ERROR: Something wrong with Error text in evaluator...");
@ -622,7 +551,7 @@ function createAndAddWorkerScript(
workerScript.log("", () => "Script killed");
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");
console.error(
"ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN: " +

@ -6924,27 +6924,27 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
* Get list of materials
* @returns material names
*/
getMaterialNames():string[];
getMaterialNames(): string[];
/**
* Get list of industry types
* @returns industry names
*/
getIndustryTypes():string[];
getIndustryTypes(): string[];
/**
* Get list of one-time unlockable upgrades
* @returns unlockable upgrades names
*/
getUnlockables():string[];
getUnlockables(): string[];
/**
* Get list of upgrade names
* @returns upgrade names
*/
getUpgradeNames():string[];
getUpgradeNames(): string[];
/**
* Get list of research names
* @returns research names
*/
getResarchNames():string[];
getResearchNames(): string[];
/**
* Accept investment based on you companies current valuation
* @remarks

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

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