diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index 14d953f1f..7f3027ea8 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -82,6 +82,7 @@ import { Gang as IGang, Bladeburner as IBladeburner, Stanek as IStanek, + Sleeve as ISleeve, Infiltration as IInfiltration, RunningScript as IRunningScript, RecentScript as IRecentScript, @@ -93,6 +94,12 @@ import { BitNodeMultipliers as IBNMults, Server as IServerDef, RunningScript as IRunningScriptDef, + Grafting as IGrafting, + UserInterface as IUserInterface, + TIX as ITIX, + Corporation as ICorporation, + CodingContract as ICodingContract, + Hacknet as IHacknet, // ToastVariant, } from "./ScriptEditor/NetscriptDefinitions"; import { NetscriptSingularity } from "./NetscriptFunctions/Singularity"; @@ -360,7 +367,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS { } }; - const hack = function ( + const hack = async function ( hostname: string, manual: boolean, { threads: requestedThreads, stock }: any = {}, @@ -524,23 +531,35 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS { }, }; - const gang = NetscriptGang(Player, workerScript, helper); - const sleeve = NetscriptSleeve(Player, workerScript, helper); const extra = NetscriptExtra(Player, workerScript, helper); - const hacknet = NetscriptHacknet(Player, workerScript, helper); + const formulas = NetscriptFormulas(Player, workerScript, helper); + + const gang = wrapAPI(helper, {}, workerScript, NetscriptGang(Player, workerScript), "gang").gang as unknown as IGang; + const sleeve = wrapAPI(helper, {}, workerScript, NetscriptSleeve(Player), "sleeve").sleeve as unknown as ISleeve; + const hacknet = wrapAPI(helper, {}, workerScript, NetscriptHacknet(Player, workerScript), "hacknet") + .hacknet as unknown as IHacknet; + const bladeburner = wrapAPI(helper, {}, workerScript, NetscriptBladeburner(Player, workerScript), "bladeburner") + .bladeburner as unknown as IBladeburner; + const codingcontract = wrapAPI( + helper, + {}, + workerScript, + NetscriptCodingContract(Player, workerScript), + "codingcontract", + ).codingcontract as unknown as ICodingContract; const infiltration = wrapAPI(helper, {}, workerScript, NetscriptInfiltration(Player), "infiltration") .infiltration as unknown as IInfiltration; const stanek = wrapAPI(helper, {}, workerScript, NetscriptStanek(Player, workerScript, helper), "stanek") .stanek as unknown as IStanek; - const bladeburner = NetscriptBladeburner(Player, workerScript, helper); - const codingcontract = NetscriptCodingContract(Player, workerScript, helper); - const corporation = NetscriptCorporation(Player, workerScript, helper); - const formulas = NetscriptFormulas(Player, workerScript, helper); + const corporation = wrapAPI(helper, {}, workerScript, NetscriptCorporation(Player, workerScript), "corporation") + .corporation as unknown as ICorporation; const singularity = wrapAPI(helper, {}, workerScript, NetscriptSingularity(Player, workerScript), "singularity") .singularity as unknown as ISingularity; - const stockmarket = NetscriptStockMarket(Player, workerScript, helper); - const ui = NetscriptUserInterface(Player, workerScript, helper); - const grafting = NetscriptGrafting(Player, workerScript, helper); + const stockmarket = wrapAPI(helper, {}, workerScript, NetscriptStockMarket(Player, workerScript), "stock") + .stock as unknown as ITIX; + const ui = wrapAPI(helper, {}, workerScript, NetscriptUserInterface(), "ui").ui as unknown as IUserInterface; + const grafting = wrapAPI(helper, {}, workerScript, NetscriptGrafting(Player), "grafting") + .grafting as unknown as IGrafting; const base: INS = { ...singularity, diff --git a/src/NetscriptFunctions/Bladeburner.ts b/src/NetscriptFunctions/Bladeburner.ts index a0ad14ae7..f3a700e86 100644 --- a/src/NetscriptFunctions/Bladeburner.ts +++ b/src/NetscriptFunctions/Bladeburner.ts @@ -1,18 +1,13 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; import { Bladeburner } from "../Bladeburner/Bladeburner"; -import { getRamCost } from "../Netscript/RamCostGenerator"; 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"; -export function NetscriptBladeburner( - player: IPlayer, - workerScript: WorkerScript, - helper: INetscriptHelper, -): INetscriptBladeburner { - const checkBladeburnerAccess = function (func: string, skipjoined = false): void { +export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript): InternalAPI { + const checkBladeburnerAccess = function (ctx: NetscriptContext, skipjoined = false): void { const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Must have joined bladeburner"); const apiAccess = @@ -22,353 +17,354 @@ export function NetscriptBladeburner( }); 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 helper.makeRuntimeErrorMsg(`bladeburner.${func}`, apiDenied); + throw ctx.makeRuntimeErrorMsg(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 helper.makeRuntimeErrorMsg(`bladeburner.${func}`, bladeburnerDenied); + throw ctx.makeRuntimeErrorMsg(bladeburnerDenied); } } }; - const checkBladeburnerCity = function (func: string, city: string): void { + const checkBladeburnerCity = function (ctx: NetscriptContext, city: string): void { const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Must have joined bladeburner"); if (!bladeburner.cities.hasOwnProperty(city)) { - throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid city: ${city}`); + throw ctx.makeRuntimeErrorMsg(`Invalid city: ${city}`); } }; - const getBladeburnerActionObject = function (func: string, type: string, name: string): IAction { + const getBladeburnerActionObject = function (ctx: NetscriptContext, type: string, name: string): IAction { const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Must have joined bladeburner"); const actionId = bladeburner.getActionIdFromTypeAndName(type, name); if (!actionId) { - throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid action type='${type}', name='${name}'`); + throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`); } const actionObj = bladeburner.getActionObject(actionId); if (!actionObj) { - throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid action type='${type}', name='${name}'`); + throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`); } return actionObj; }; - const updateRam = (funcName: string): void => - helper.updateDynamicRam(funcName, getRamCost(player, "bladeburner", funcName)); - return { - getContractNames: function (): string[] { - updateRam("getContractNames"); - checkBladeburnerAccess("getContractNames"); + getContractNames: (ctx: NetscriptContext) => (): string[] => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.getContractNamesNetscriptFn(); }, - getOperationNames: function (): string[] { - updateRam("getOperationNames"); - checkBladeburnerAccess("getOperationNames"); + getOperationNames: (ctx: NetscriptContext) => (): string[] => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.getOperationNamesNetscriptFn(); }, - getBlackOpNames: function (): string[] { - updateRam("getBlackOpNames"); - checkBladeburnerAccess("getBlackOpNames"); + getBlackOpNames: (ctx: NetscriptContext) => (): string[] => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.getBlackOpNamesNetscriptFn(); }, - getBlackOpRank: function (_blackOpName: unknown): number { - updateRam("getBlackOpRank"); - const blackOpName = helper.string("getBlackOpRank", "blackOpName", _blackOpName); - checkBladeburnerAccess("getBlackOpRank"); - const action: any = getBladeburnerActionObject("getBlackOpRank", "blackops", blackOpName); - return action.reqdRank; - }, - getGeneralActionNames: function (): string[] { - updateRam("getGeneralActionNames"); - checkBladeburnerAccess("getGeneralActionNames"); + getBlackOpRank: + (ctx: NetscriptContext) => + (_blackOpName: unknown): number => { + const blackOpName = ctx.helper.string("blackOpName", _blackOpName); + checkBladeburnerAccess(ctx); + const action: any = getBladeburnerActionObject(ctx, "blackops", blackOpName); + return action.reqdRank; + }, + getGeneralActionNames: (ctx: NetscriptContext) => (): string[] => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.getGeneralActionNamesNetscriptFn(); }, - getSkillNames: function (): string[] { - updateRam("getSkillNames"); - checkBladeburnerAccess("getSkillNames"); + getSkillNames: (ctx: NetscriptContext) => (): string[] => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.getSkillNamesNetscriptFn(); }, - startAction: function (_type: unknown, _name: unknown): boolean { - updateRam("startAction"); - const type = helper.string("startAction", "type", _type); - const name = helper.string("startAction", "name", _name); - checkBladeburnerAccess("startAction"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.startActionNetscriptFn(player, type, name, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.startAction", e); - } - }, - stopBladeburnerAction: function (): void { - updateRam("stopBladeburnerAction"); - checkBladeburnerAccess("stopBladeburnerAction"); + startAction: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): boolean => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("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); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + stopBladeburnerAction: (ctx: NetscriptContext) => (): void => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.resetAction(); }, - getCurrentAction: function (): BladeburnerCurAction { - updateRam("getCurrentAction"); - checkBladeburnerAccess("getCurrentAction"); + getCurrentAction: (ctx: NetscriptContext) => (): BladeburnerCurAction => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.getTypeAndNameFromActionId(bladeburner.action); }, - getActionTime: function (_type: unknown, _name: unknown): number { - updateRam("getActionTime"); - const type = helper.string("getActionTime", "type", _type); - const name = helper.string("getActionTime", "name", _name); - checkBladeburnerAccess("getActionTime"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.getActionTimeNetscriptFn(player, type, name, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.getActionTime", e); - } - }, - getActionEstimatedSuccessChance: function (_type: unknown, _name: unknown): [number, number] { - updateRam("getActionEstimatedSuccessChance"); - const type = helper.string("getActionEstimatedSuccessChance", "type", _type); - const name = helper.string("getActionEstimatedSuccessChance", "name", _name); - checkBladeburnerAccess("getActionEstimatedSuccessChance"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.getActionEstimatedSuccessChance", e); - } - }, - getActionRepGain: function (_type: unknown, _name: unknown, _level: unknown): number { - updateRam("getActionRepGain"); - const type = helper.string("getActionRepGain", "type", _type); - const name = helper.string("getActionRepGain", "name", _name); - const level = helper.number("getActionRepGain", "level", _level); - checkBladeburnerAccess("getActionRepGain"); - const action = getBladeburnerActionObject("getActionRepGain", type, name); - let rewardMultiplier; - if (level == null || isNaN(level)) { - rewardMultiplier = Math.pow(action.rewardFac, action.level - 1); - } else { - rewardMultiplier = Math.pow(action.rewardFac, level - 1); - } + getActionTime: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): number => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("name", _name); + checkBladeburnerAccess(ctx); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + try { + return bladeburner.getActionTimeNetscriptFn(player, type, name, workerScript); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + getActionEstimatedSuccessChance: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): [number, number] => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("name", _name); + checkBladeburnerAccess(ctx); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + try { + return bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name, workerScript); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(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); + checkBladeburnerAccess(ctx); + const action = getBladeburnerActionObject(ctx, type, name); + let rewardMultiplier; + if (level == null || isNaN(level)) { + rewardMultiplier = Math.pow(action.rewardFac, action.level - 1); + } else { + rewardMultiplier = Math.pow(action.rewardFac, level - 1); + } - return action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank; - }, - getActionCountRemaining: function (_type: unknown, _name: unknown): number { - updateRam("getActionCountRemaining"); - const type = helper.string("getActionCountRemaining", "type", _type); - const name = helper.string("getActionCountRemaining", "name", _name); - checkBladeburnerAccess("getActionCountRemaining"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.getActionCountRemainingNetscriptFn(type, name, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.getActionCountRemaining", e); - } - }, - getActionMaxLevel: function (_type: unknown, _name: unknown): number { - updateRam("getActionMaxLevel"); - const type = helper.string("getActionMaxLevel", "type", _type); - const name = helper.string("getActionMaxLevel", "name", _name); - checkBladeburnerAccess("getActionMaxLevel"); - const action = getBladeburnerActionObject("getActionMaxLevel", type, name); - return action.maxLevel; - }, - getActionCurrentLevel: function (_type: unknown, _name: unknown): number { - updateRam("getActionCurrentLevel"); - const type = helper.string("getActionCurrentLevel", "type", _type); - const name = helper.string("getActionCurrentLevel", "name", _name); - checkBladeburnerAccess("getActionCurrentLevel"); - const action = getBladeburnerActionObject("getActionCurrentLevel", type, name); - return action.level; - }, - getActionAutolevel: function (_type: unknown, _name: unknown): boolean { - updateRam("getActionAutolevel"); - const type = helper.string("getActionAutolevel", "type", _type); - const name = helper.string("getActionAutolevel", "name", _name); - checkBladeburnerAccess("getActionAutolevel"); - const action = getBladeburnerActionObject("getActionCurrentLevel", type, name); - return action.autoLevel; - }, - setActionAutolevel: function (_type: unknown, _name: unknown, _autoLevel: unknown = true): void { - updateRam("setActionAutolevel"); - const type = helper.string("setActionAutolevel", "type", _type); - const name = helper.string("setActionAutolevel", "name", _name); - const autoLevel = helper.boolean(_autoLevel); - checkBladeburnerAccess("setActionAutolevel"); - const action = getBladeburnerActionObject("setActionAutolevel", type, name); - action.autoLevel = autoLevel; - }, - setActionLevel: function (_type: unknown, _name: unknown, _level: unknown = 1): void { - updateRam("setActionLevel"); - const type = helper.string("setActionLevel", "type", _type); - const name = helper.string("setActionLevel", "name", _name); - const level = helper.number("setActionLevel", "level", _level); - checkBladeburnerAccess("setActionLevel"); - const action = getBladeburnerActionObject("setActionLevel", type, name); - if (level < 1 || level > action.maxLevel) { - throw helper.makeRuntimeErrorMsg( - "bladeburner.setActionLevel", - `Level must be between 1 and ${action.maxLevel}, is ${level}`, - ); - } - action.level = level; - }, - getRank: function (): number { - updateRam("getRank"); - checkBladeburnerAccess("getRank"); + return action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank; + }, + getActionCountRemaining: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): number => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("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); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + getActionMaxLevel: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): number => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("name", _name); + checkBladeburnerAccess(ctx); + const action = getBladeburnerActionObject(ctx, type, name); + return action.maxLevel; + }, + getActionCurrentLevel: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): number => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("name", _name); + checkBladeburnerAccess(ctx); + const action = getBladeburnerActionObject(ctx, type, name); + return action.level; + }, + getActionAutolevel: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): boolean => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("name", _name); + checkBladeburnerAccess(ctx); + const action = getBladeburnerActionObject(ctx, type, name); + return action.autoLevel; + }, + 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); + checkBladeburnerAccess(ctx); + const action = getBladeburnerActionObject(ctx, type, name); + action.autoLevel = autoLevel; + }, + 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); + 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}`); + } + action.level = level; + }, + getRank: (ctx: NetscriptContext) => (): number => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.rank; }, - getSkillPoints: function (): number { - updateRam("getSkillPoints"); - checkBladeburnerAccess("getSkillPoints"); + getSkillPoints: (ctx: NetscriptContext) => (): number => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.skillPoints; }, - getSkillLevel: function (_skillName: unknown): number { - updateRam("getSkillLevel"); - const skillName = helper.string("getSkillLevel", "skillName", _skillName); - checkBladeburnerAccess("getSkillLevel"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.getSkillLevelNetscriptFn(skillName, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.getSkillLevel", e); - } - }, - getSkillUpgradeCost: function (_skillName: unknown): number { - updateRam("getSkillUpgradeCost"); - const skillName = helper.string("getSkillUpgradeCost", "skillName", _skillName); - checkBladeburnerAccess("getSkillUpgradeCost"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.getSkillUpgradeCost", e); - } - }, - upgradeSkill: function (_skillName: unknown): boolean { - updateRam("upgradeSkill"); - const skillName = helper.string("upgradeSkill", "skillName", _skillName); - checkBladeburnerAccess("upgradeSkill"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.upgradeSkillNetscriptFn(skillName, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.upgradeSkill", e); - } - }, - getTeamSize: function (_type: unknown, _name: unknown): number { - updateRam("getTeamSize"); - const type = helper.string("getTeamSize", "type", _type); - const name = helper.string("getTeamSize", "name", _name); - checkBladeburnerAccess("getTeamSize"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.getTeamSizeNetscriptFn(type, name, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.getTeamSize", e); - } - }, - setTeamSize: function (_type: unknown, _name: unknown, _size: unknown): number { - updateRam("setTeamSize"); - const type = helper.string("setTeamSize", "type", _type); - const name = helper.string("setTeamSize", "name", _name); - const size = helper.number("setTeamSize", "size", _size); - checkBladeburnerAccess("setTeamSize"); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - try { - return bladeburner.setTeamSizeNetscriptFn(type, name, size, workerScript); - } catch (e: any) { - throw helper.makeRuntimeErrorMsg("bladeburner.setTeamSize", e); - } - }, - getCityEstimatedPopulation: function (_cityName: unknown): number { - updateRam("getCityEstimatedPopulation"); - const cityName = helper.string("getCityEstimatedPopulation", "cityName", _cityName); - checkBladeburnerAccess("getCityEstimatedPopulation"); - checkBladeburnerCity("getCityEstimatedPopulation", cityName); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - return bladeburner.cities[cityName].popEst; - }, - getCityCommunities: function (_cityName: unknown): number { - updateRam("getCityCommunities"); - const cityName = helper.string("getCityCommunities", "cityName", _cityName); - checkBladeburnerAccess("getCityCommunities"); - checkBladeburnerCity("getCityCommunities", cityName); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - return bladeburner.cities[cityName].comms; - }, - getCityChaos: function (_cityName: unknown): number { - updateRam("getCityChaos"); - const cityName = helper.string("getCityChaos", "cityName", _cityName); - checkBladeburnerAccess("getCityChaos"); - checkBladeburnerCity("getCityChaos", cityName); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - return bladeburner.cities[cityName].chaos; - }, - getCity: function (): string { - updateRam("getCity"); - checkBladeburnerAccess("getCityChaos"); + getSkillLevel: + (ctx: NetscriptContext) => + (_skillName: unknown): number => { + const skillName = ctx.helper.string("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); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + getSkillUpgradeCost: + (ctx: NetscriptContext) => + (_skillName: unknown): number => { + const skillName = ctx.helper.string("skillName", _skillName); + checkBladeburnerAccess(ctx); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + try { + return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, workerScript); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + upgradeSkill: + (ctx: NetscriptContext) => + (_skillName: unknown): boolean => { + const skillName = ctx.helper.string("skillName", _skillName); + checkBladeburnerAccess(ctx); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + try { + return bladeburner.upgradeSkillNetscriptFn(skillName, workerScript); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + getTeamSize: + (ctx: NetscriptContext) => + (_type: unknown, _name: unknown): number => { + const type = ctx.helper.string("type", _type); + const name = ctx.helper.string("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); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(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); + 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); + } catch (e: any) { + throw ctx.makeRuntimeErrorMsg(e); + } + }, + getCityEstimatedPopulation: + (ctx: NetscriptContext) => + (_cityName: unknown): number => { + const cityName = ctx.helper.string("cityName", _cityName); + checkBladeburnerAccess(ctx); + checkBladeburnerCity(ctx, cityName); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + return bladeburner.cities[cityName].popEst; + }, + getCityCommunities: + (ctx: NetscriptContext) => + (_cityName: unknown): number => { + const cityName = ctx.helper.string("cityName", _cityName); + checkBladeburnerAccess(ctx); + checkBladeburnerCity(ctx, cityName); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + return bladeburner.cities[cityName].comms; + }, + getCityChaos: + (ctx: NetscriptContext) => + (_cityName: unknown): number => { + const cityName = ctx.helper.string("cityName", _cityName); + checkBladeburnerAccess(ctx); + checkBladeburnerCity(ctx, cityName); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + return bladeburner.cities[cityName].chaos; + }, + getCity: (ctx: NetscriptContext) => (): string => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.city; }, - switchCity: function (_cityName: unknown): boolean { - updateRam("switchCity"); - const cityName = helper.string("switchCity", "cityName", _cityName); - checkBladeburnerAccess("switchCity"); - checkBladeburnerCity("switchCity", cityName); - const bladeburner = player.bladeburner; - if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); - bladeburner.city = cityName; - return true; - }, - getStamina: function (): [number, number] { - updateRam("getStamina"); - checkBladeburnerAccess("getStamina"); + switchCity: + (ctx: NetscriptContext) => + (_cityName: unknown): boolean => { + const cityName = ctx.helper.string("cityName", _cityName); + checkBladeburnerAccess(ctx); + checkBladeburnerCity(ctx, cityName); + const bladeburner = player.bladeburner; + if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); + bladeburner.city = cityName; + return true; + }, + getStamina: (ctx: NetscriptContext) => (): [number, number] => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return [bladeburner.stamina, bladeburner.maxStamina]; }, - joinBladeburnerFaction: function (): boolean { - updateRam("joinBladeburnerFaction"); - checkBladeburnerAccess("joinBladeburnerFaction", true); + joinBladeburnerFaction: (ctx: NetscriptContext) => (): boolean => { + checkBladeburnerAccess(ctx, true); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return bladeburner.joinBladeburnerFactionNetscriptFn(workerScript); }, - joinBladeburnerDivision: function (): boolean { - updateRam("joinBladeburnerDivision"); + joinBladeburnerDivision: (ctx: NetscriptContext) => (): boolean => { if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) { if (player.bitNodeN === 8) { return false; @@ -382,22 +378,18 @@ export function NetscriptBladeburner( player.agility >= 100 ) { player.bladeburner = new Bladeburner(player); - workerScript.log("joinBladeburnerDivision", () => "You have been accepted into the Bladeburner division"); + ctx.log(() => "You have been accepted into the Bladeburner division"); return true; } else { - workerScript.log( - "joinBladeburnerDivision", - () => "You do not meet the requirements for joining the Bladeburner division", - ); + ctx.log(() => "You do not meet the requirements for joining the Bladeburner division"); return false; } } return false; }, - getBonusTime: function (): number { - updateRam("getBonusTime"); - checkBladeburnerAccess("getBonusTime"); + getBonusTime: (ctx: NetscriptContext) => (): number => { + checkBladeburnerAccess(ctx); const bladeburner = player.bladeburner; if (bladeburner === null) throw new Error("Should not be called without Bladeburner"); return Math.round(bladeburner.storedCycles / 5) * 1000; diff --git a/src/NetscriptFunctions/CodingContract.ts b/src/NetscriptFunctions/CodingContract.ts index 52901eef4..c5d50f59f 100644 --- a/src/NetscriptFunctions/CodingContract.ts +++ b/src/NetscriptFunctions/CodingContract.ts @@ -1,132 +1,124 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; -import { getRamCost } from "../Netscript/RamCostGenerator"; 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"; -export function NetscriptCodingContract( - player: IPlayer, - workerScript: WorkerScript, - helper: INetscriptHelper, -): ICodingContract { - const getCodingContract = function (func: string, hostname: string, filename: string): CodingContract { - const server = helper.getServer(hostname, func); +export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScript): InternalAPI { + const getCodingContract = function ( + ctx: NetscriptContext, + func: string, + hostname: string, + filename: string, + ): CodingContract { + const server = ctx.helper.getServer(hostname); const contract = server.getContract(filename); if (contract == null) { - throw helper.makeRuntimeErrorMsg( - `codingcontract.${func}`, - `Cannot find contract '${filename}' on server '${hostname}'`, - ); + throw ctx.makeRuntimeErrorMsg(`Cannot find contract '${filename}' on server '${hostname}'`); } return contract; }; - const updateRam = (funcName: string): void => - helper.updateDynamicRam(funcName, getRamCost(player, "codingcontract", funcName)); - return { - attempt: function ( - answer: any, - _filename: unknown, - _hostname: unknown = workerScript.hostname, - { returnReward }: CodingAttemptOptions = { returnReward: false }, - ): boolean | string { - updateRam("attempt"); - const filename = helper.string("attempt", "filename", _filename); - const hostname = helper.string("attempt", "hostname", _hostname); - const contract = getCodingContract("attempt", hostname, filename); + attempt: + (ctx: NetscriptContext) => + ( + answer: any, + _filename: unknown, + _hostname: unknown = workerScript.hostname, + { returnReward }: CodingAttemptOptions = { returnReward: false }, + ): boolean | string => { + const filename = ctx.helper.string("filename", _filename); + const hostname = ctx.helper.string("hostname", _hostname); + const contract = getCodingContract(ctx, "attempt", hostname, filename); - // Convert answer to string. If the answer is a 2D array, then we have to - // manually add brackets for the inner arrays - if (is2DArray(answer)) { - const answerComponents = []; - for (let i = 0; i < answer.length; ++i) { - answerComponents.push(["[", answer[i].toString(), "]"].join("")); - } - - answer = answerComponents.join(","); - } else { - answer = String(answer); - } - - const creward = contract.reward; - if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward"); - - const serv = helper.getServer(hostname, "codingcontract.attempt"); - if (contract.isSolution(answer)) { - const reward = player.gainCodingContractReward(creward, contract.getDifficulty()); - workerScript.log( - "codingcontract.attempt", - () => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`, - ); - serv.removeContract(filename); - return returnReward ? reward : true; - } else { - ++contract.tries; - if (contract.tries >= contract.getMaxNumTries()) { - workerScript.log( - "codingcontract.attempt", - () => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`, - ); - serv.removeContract(filename); - } else { - workerScript.log( - "codingcontract.attempt", - () => - `Coding Contract attempt '${filename}' failed. ${ - contract.getMaxNumTries() - contract.tries - } attempts remaining.`, - ); - } - - return returnReward ? "" : false; - } - }, - getContractType: function (_filename: unknown, _hostname: unknown = workerScript.hostname): string { - updateRam("getContractType"); - const filename = helper.string("getContractType", "filename", _filename); - const hostname = helper.string("getContractType", "hostname", _hostname); - const contract = getCodingContract("getContractType", hostname, filename); - return contract.getType(); - }, - getData: function (_filename: unknown, _hostname: unknown = workerScript.hostname): any { - updateRam("getData"); - const filename = helper.string("getContractType", "filename", _filename); - const hostname = helper.string("getContractType", "hostname", _hostname); - const contract = getCodingContract("getData", hostname, filename); - const data = contract.getData(); - if (data.constructor === Array) { - // For two dimensional arrays, we have to copy the internal arrays using - // slice() as well. As of right now, no contract has arrays that have - // more than two dimensions - const copy = data.slice(); - for (let i = 0; i < copy.length; ++i) { - if (data[i].constructor === Array) { - copy[i] = data[i].slice(); + // Convert answer to string. If the answer is a 2D array, then we have to + // manually add brackets for the inner arrays + if (is2DArray(answer)) { + const answerComponents = []; + for (let i = 0; i < answer.length; ++i) { + answerComponents.push(["[", answer[i].toString(), "]"].join("")); } + + answer = answerComponents.join(","); + } else { + answer = String(answer); } - return copy; - } else { - return data; - } - }, - getDescription: function (_filename: unknown, _hostname: unknown = workerScript.hostname): string { - updateRam("getDescription"); - const filename = helper.string("getDescription", "filename", _filename); - const hostname = helper.string("getDescription", "hostname", _hostname); - const contract = getCodingContract("getDescription", hostname, filename); - return contract.getDescription(); - }, - getNumTriesRemaining: function (_filename: unknown, _hostname: unknown = workerScript.hostname): number { - updateRam("getNumTriesRemaining"); - const filename = helper.string("getNumTriesRemaining", "filename", _filename); - const hostname = helper.string("getNumTriesRemaining", "hostname", _hostname); - const contract = getCodingContract("getNumTriesRemaining", hostname, filename); - return contract.getMaxNumTries() - contract.tries; - }, + 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); + if (contract.isSolution(answer)) { + const reward = player.gainCodingContractReward(creward, contract.getDifficulty()); + ctx.log(() => `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`); + serv.removeContract(filename); + } else { + ctx.log( + () => + `Coding Contract attempt '${filename}' failed. ${ + contract.getMaxNumTries() - contract.tries + } attempts remaining.`, + ); + } + + return returnReward ? "" : false; + } + }, + getContractType: + (ctx: NetscriptContext) => + (_filename: unknown, _hostname: unknown = workerScript.hostname): string => { + const filename = ctx.helper.string("filename", _filename); + const hostname = ctx.helper.string("hostname", _hostname); + const contract = getCodingContract(ctx, "getContractType", hostname, filename); + return contract.getType(); + }, + getData: + (ctx: NetscriptContext) => + (_filename: unknown, _hostname: unknown = workerScript.hostname): any => { + const filename = ctx.helper.string("filename", _filename); + const hostname = ctx.helper.string("hostname", _hostname); + const contract = getCodingContract(ctx, "getData", hostname, filename); + const data = contract.getData(); + if (data.constructor === Array) { + // For two dimensional arrays, we have to copy the internal arrays using + // slice() as well. As of right now, no contract has arrays that have + // more than two dimensions + const copy = data.slice(); + for (let i = 0; i < copy.length; ++i) { + if (data[i].constructor === Array) { + copy[i] = data[i].slice(); + } + } + + return copy; + } else { + return data; + } + }, + getDescription: + (ctx: NetscriptContext) => + (_filename: unknown, _hostname: unknown = workerScript.hostname): string => { + const filename = ctx.helper.string("filename", _filename); + const hostname = ctx.helper.string("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); + const contract = getCodingContract(ctx, "getNumTriesRemaining", hostname, filename); + return contract.getMaxNumTries() - contract.tries; + }, }; } diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 2c7642e88..87c9c71f5 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -1,4 +1,3 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; import { netscriptDelay } from "../NetscriptEvaluator"; @@ -68,12 +67,9 @@ import { IndustryUpgrades } from "../Corporation/IndustryUpgrades"; import { ResearchMap } from "../Corporation/ResearchMap"; import { Factions } from "../Faction/Factions"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; +import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; -export function NetscriptCorporation( - player: IPlayer, - workerScript: WorkerScript, - helper: INetscriptHelper, -): NSCorporation { +export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript): InternalAPI { function createCorporation(corporationName: string, selfFund = true): boolean { if (!player.canAccessCorporation() || player.hasCorporation()) return false; if (!corporationName) return false; @@ -106,8 +102,8 @@ export function NetscriptCorporation( return upgrade.price; } - function getUpgradeLevel(_upgradeName: string): number { - const upgradeName = helper.string("levelUpgrade", "upgradeName", _upgradeName); + function getUpgradeLevel(ctx: NetscriptContext, _upgradeName: string): number { + const upgradeName = ctx.helper.string("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}'`); @@ -115,8 +111,8 @@ export function NetscriptCorporation( return corporation.upgrades[upgN]; } - function getUpgradeLevelCost(_upgradeName: string): number { - const upgradeName = helper.string("levelUpgrade", "upgradeName", _upgradeName); + function getUpgradeLevelCost(ctx: NetscriptContext, _upgradeName: string): number { + const upgradeName = ctx.helper.string("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}'`); @@ -281,12 +277,11 @@ export function NetscriptCorporation( return employee; } - function checkAccess(func: string, api?: number): void { - if (player.corporation === null) throw helper.makeRuntimeErrorMsg(`corporation.${func}`, "Must own a corporation."); + function checkAccess(ctx: NetscriptContext, api?: number): void { + if (player.corporation === null) throw ctx.makeRuntimeErrorMsg("Must own a corporation."); if (!api) return; - if (!player.corporation.unlockUpgrades[api]) - throw helper.makeRuntimeErrorMsg(`corporation.${func}`, "You do not have access to this API."); + if (!player.corporation.unlockUpgrades[api]) throw ctx.makeRuntimeErrorMsg("You do not have access to this API."); } function getSafeDivision(division: Industry): NSDivision { @@ -314,604 +309,637 @@ export function NetscriptCorporation( }; } - const warehouseAPI: WarehouseAPI = { - getPurchaseWarehouseCost: function (): number { - checkAccess("getPurchaseWarehouseCost", 7); + const warehouseAPI: InternalAPI = { + getPurchaseWarehouseCost: (ctx: NetscriptContext) => (): number => { + checkAccess(ctx, 7); return CorporationConstants.WarehouseInitialCost; }, - getUpgradeWarehouseCost: function (_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): number { - checkAccess("upgradeWarehouse", 7); - const divisionName = helper.string("getUpgradeWarehouseCost", "divisionName", _divisionName); - const cityName = helper.city("getUpgradeWarehouseCost", "cityName", _cityName); - const amt = helper.number("getUpgradeWarehouseCost", "amount", _amt); - if (amt < 1) { - throw helper.makeRuntimeErrorMsg(`corporation.getUpgradeWarehouseCost`, "You must provide a positive number"); - } - const warehouse = getWarehouse(divisionName, cityName); - return UpgradeWarehouseCost(warehouse, amt); - }, - hasWarehouse: function (_divisionName: unknown, _cityName: unknown): boolean { - checkAccess("hasWarehouse", 7); - const divisionName = helper.string("getWarehouse", "divisionName", _divisionName); - const cityName = helper.city("getWarehouse", "cityName", _cityName); - const division = getDivision(divisionName); - if (!(cityName in division.warehouses)) throw new Error(`Invalid city name '${cityName}'`); - const warehouse = division.warehouses[cityName]; - return warehouse !== 0; - }, - getWarehouse: function (_divisionName: unknown, _cityName: unknown): NSWarehouse { - checkAccess("getWarehouse", 7); - const divisionName = helper.string("getWarehouse", "divisionName", _divisionName); - const cityName = helper.city("getWarehouse", "cityName", _cityName); - const warehouse = getWarehouse(divisionName, cityName); - return { - level: warehouse.level, - loc: warehouse.loc, - size: warehouse.size, - sizeUsed: warehouse.sizeUsed, - smartSupplyEnabled: warehouse.smartSupplyEnabled, - }; - }, - getMaterial: function (_divisionName: unknown, _cityName: unknown, _materialName: unknown): NSMaterial { - checkAccess("getMaterial", 7); - const divisionName = helper.string("getMaterial", "divisionName", _divisionName); - const cityName = helper.city("getMaterial", "cityName", _cityName); - const materialName = helper.string("getMaterial", "materialName", _materialName); - const material = getMaterial(divisionName, cityName, materialName); - const corporation = getCorporation(); - return { - cost: material.bCost, - sCost: material.sCost, - name: material.name, - qty: material.qty, - qlt: material.qlt, - dmd: corporation.unlockUpgrades[2] ? material.dmd : undefined, - cmp: corporation.unlockUpgrades[3] ? material.cmp : undefined, - prod: material.prd, - sell: material.sll, - }; - }, - getProduct: function (_divisionName: unknown, _productName: unknown): NSProduct { - checkAccess("getProduct", 7); - const divisionName = helper.string("getProduct", "divisionName", _divisionName); - const productName = helper.string("getProduct", "productName", _productName); - const product = getProduct(divisionName, productName); - const corporation = getCorporation(); - return { - name: product.name, - dmd: corporation.unlockUpgrades[2] ? product.dmd : undefined, - cmp: corporation.unlockUpgrades[3] ? product.cmp : undefined, - rat: product.rat, - properties: { - qlt: product.qlt, - per: product.per, - dur: product.dur, - rel: product.rel, - aes: product.aes, - fea: product.fea, - }, - pCost: product.pCost, - sCost: product.sCost, - cityData: product.data, - developmentProgress: product.prog, - }; - }, - purchaseWarehouse: function (_divisionName: unknown, _cityName: unknown): void { - checkAccess("purchaseWarehouse", 7); - const divisionName = helper.string("purchaseWarehouse", "divisionName", _divisionName); - const cityName = helper.city("purchaseWarehouse", "cityName", _cityName); - const corporation = getCorporation(); - PurchaseWarehouse(corporation, getDivision(divisionName), cityName); - }, - upgradeWarehouse: function (_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): void { - checkAccess("upgradeWarehouse", 7); - const divisionName = helper.string("upgradeWarehouse", "divisionName", _divisionName); - const cityName = helper.city("upgradeWarehouse", "cityName", _cityName); - const amt = helper.number("upgradeWarehouse", "amount", _amt); - const corporation = getCorporation(); - if (amt < 1) { - throw helper.makeRuntimeErrorMsg(`corporation.upgradeWarehouse`, "You must provide a positive number"); - } - UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName), amt); - }, - sellMaterial: function ( - _divisionName: unknown, - _cityName: unknown, - _materialName: unknown, - _amt: unknown, - _price: unknown, - ): void { - checkAccess("sellMaterial", 7); - const divisionName = helper.string("sellMaterial", "divisionName", _divisionName); - const cityName = helper.city("sellMaterial", "cityName", _cityName); - const materialName = helper.string("sellMaterial", "materialName", _materialName); - const amt = helper.string("sellMaterial", "amt", _amt); - const price = helper.string("sellMaterial", "price", _price); - const material = getMaterial(divisionName, cityName, materialName); - SellMaterial(material, amt, price); - }, - sellProduct: function ( - _divisionName: unknown, - _cityName: unknown, - _productName: unknown, - _amt: unknown, - _price: unknown, - _all: unknown, - ): void { - checkAccess("sellProduct", 7); - const divisionName = helper.string("sellProduct", "divisionName", _divisionName); - const cityName = helper.city("sellProduct", "cityName", _cityName); - const productName = helper.string("sellProduct", "productName", _productName); - const amt = helper.string("sellProduct", "amt", _amt); - const price = helper.string("sellProduct", "price", _price); - const all = helper.boolean(_all); - const product = getProduct(divisionName, productName); - SellProduct(product, cityName, amt, price, all); - }, - discontinueProduct: function (_divisionName: unknown, _productName: unknown): void { - checkAccess("discontinueProduct", 7); - const divisionName = helper.string("discontinueProduct", "divisionName", _divisionName); - const productName = helper.string("discontinueProduct", "productName", _productName); - getDivision(divisionName).discontinueProduct(getProduct(divisionName, productName)); - }, - setSmartSupply: function (_divisionName: unknown, _cityName: unknown, _enabled: unknown): void { - checkAccess("setSmartSupply", 7); - const divisionName = helper.string("setSmartSupply", "divisionName", _divisionName); - const cityName = helper.city("sellProduct", "cityName", _cityName); - const enabled = helper.boolean(_enabled); - const warehouse = getWarehouse(divisionName, cityName); - if (!hasUnlockUpgrade("Smart Supply")) - throw helper.makeRuntimeErrorMsg( - `corporation.setSmartSupply`, - `You have not purchased the Smart Supply upgrade!`, + getUpgradeWarehouseCost: + (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); + if (amt < 1) { + throw ctx.makeRuntimeErrorMsg("You must provide a positive number"); + } + const warehouse = getWarehouse(divisionName, cityName); + return UpgradeWarehouseCost(warehouse, amt); + }, + hasWarehouse: + (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 division = getDivision(divisionName); + if (!(cityName in division.warehouses)) throw new Error(`Invalid city name '${cityName}'`); + const warehouse = division.warehouses[cityName]; + return warehouse !== 0; + }, + getWarehouse: + (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 warehouse = getWarehouse(divisionName, cityName); + return { + level: warehouse.level, + loc: warehouse.loc, + size: warehouse.size, + sizeUsed: warehouse.sizeUsed, + smartSupplyEnabled: warehouse.smartSupplyEnabled, + }; + }, + getMaterial: + (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 material = getMaterial(divisionName, cityName, materialName); + const corporation = getCorporation(); + return { + cost: material.bCost, + sCost: material.sCost, + name: material.name, + qty: material.qty, + qlt: material.qlt, + dmd: corporation.unlockUpgrades[2] ? material.dmd : undefined, + cmp: corporation.unlockUpgrades[3] ? material.cmp : undefined, + prod: material.prd, + sell: material.sll, + }; + }, + getProduct: + (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 product = getProduct(divisionName, productName); + const corporation = getCorporation(); + return { + name: product.name, + dmd: corporation.unlockUpgrades[2] ? product.dmd : undefined, + cmp: corporation.unlockUpgrades[3] ? product.cmp : undefined, + rat: product.rat, + properties: { + qlt: product.qlt, + per: product.per, + dur: product.dur, + rel: product.rel, + aes: product.aes, + fea: product.fea, + }, + pCost: product.pCost, + sCost: product.sCost, + cityData: product.data, + developmentProgress: product.prog, + }; + }, + purchaseWarehouse: + (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 corporation = getCorporation(); + PurchaseWarehouse(corporation, getDivision(divisionName), cityName); + }, + upgradeWarehouse: + (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 corporation = getCorporation(); + if (amt < 1) { + throw ctx.makeRuntimeErrorMsg("You must provide a positive number"); + } + UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName), amt); + }, + sellMaterial: + (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 material = getMaterial(divisionName, cityName, materialName); + SellMaterial(material, amt, price); + }, + sellProduct: + (ctx: NetscriptContext) => + ( + _divisionName: unknown, + _cityName: unknown, + _productName: unknown, + _amt: unknown, + _price: unknown, + _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 product = getProduct(divisionName, productName); + SellProduct(product, cityName, amt, price, all); + }, + discontinueProduct: + (ctx: NetscriptContext) => + (_divisionName: unknown, _productName: unknown): void => { + checkAccess(ctx, 7); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const productName = ctx.helper.string("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 warehouse = getWarehouse(divisionName, cityName); + if (!hasUnlockUpgrade("Smart Supply")) + throw ctx.makeRuntimeErrorMsg(`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 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!`); + 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); + 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); + }, + bulkPurchase: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void => { + checkAccess(ctx, 7); + const divisionName = ctx.helper.string("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 warehouse = getWarehouse(divisionName, cityName); + const material = getMaterial(divisionName, cityName, materialName); + BulkPurchase(corporation, warehouse, material, amt); + }, + makeProduct: + (ctx: NetscriptContext) => + ( + _divisionName: unknown, + _cityName: unknown, + _productName: unknown, + _designInvest: unknown, + _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 corporation = getCorporation(); + MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest); + }, + limitProductProduction: + (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); + LimitProductProduction(getProduct(divisionName, productName), cityName, qty); + }, + exportMaterial: + (ctx: NetscriptContext) => + ( + _sourceDivision: unknown, + _sourceCity: unknown, + _targetDivision: unknown, + _targetCity: unknown, + _materialName: unknown, + _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); + ExportMaterial( + targetDivision, + targetCity, + getMaterial(sourceDivision, sourceCity, materialName), + amt + "", + getDivision(targetDivision), ); - SetSmartSupply(warehouse, enabled); - }, - setSmartSupplyUseLeftovers: function ( - _divisionName: unknown, - _cityName: unknown, - _materialName: unknown, - _enabled: unknown, - ): void { - checkAccess("setSmartSupplyUseLeftovers", 7); - const divisionName = helper.string("setSmartSupply", "divisionName", _divisionName); - const cityName = helper.city("sellProduct", "cityName", _cityName); - const materialName = helper.string("sellProduct", "materialName", _materialName); - const enabled = helper.boolean(_enabled); - const warehouse = getWarehouse(divisionName, cityName); - const material = getMaterial(divisionName, cityName, materialName); - if (!hasUnlockUpgrade("Smart Supply")) - throw helper.makeRuntimeErrorMsg( - `corporation.setSmartSupply`, - `You have not purchased the Smart Supply upgrade!`, + }, + cancelExportMaterial: + (ctx: NetscriptContext) => + ( + _sourceDivision: unknown, + _sourceCity: unknown, + _targetDivision: unknown, + _targetCity: unknown, + _materialName: unknown, + _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); + CancelExportMaterial( + targetDivision, + targetCity, + getMaterial(sourceDivision, sourceCity, materialName), + amt + "", ); - SetSmartSupplyUseLeftovers(warehouse, material, enabled); - }, - buyMaterial: function (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void { - checkAccess("buyMaterial", 7); - const divisionName = helper.string("buyMaterial", "divisionName", _divisionName); - const cityName = helper.city("buyMaterial", "cityName", _cityName); - const materialName = helper.string("buyMaterial", "materialName", _materialName); - const amt = helper.number("buyMaterial", "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); - }, - bulkPurchase: function (_divisionName: unknown, _cityName: unknown, _materialName: unknown, _amt: unknown): void { - checkAccess("bulkPurchase", 7); - const divisionName = helper.string("bulkPurchase", "divisionName", _divisionName); - if (!hasResearched(getDivision(divisionName), "Bulk Purchasing")) - throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`); - const corporation = getCorporation(); - const cityName = helper.city("bulkPurchase", "cityName", _cityName); - const materialName = helper.string("bulkPurchase", "materialName", _materialName); - const amt = helper.number("bulkPurchase", "amt", _amt); - const warehouse = getWarehouse(divisionName, cityName); - const material = getMaterial(divisionName, cityName, materialName); - BulkPurchase(corporation, warehouse, material, amt); - }, - makeProduct: function ( - _divisionName: unknown, - _cityName: unknown, - _productName: unknown, - _designInvest: unknown, - _marketingInvest: unknown, - ): void { - checkAccess("makeProduct", 7); - const divisionName = helper.string("makeProduct", "divisionName", _divisionName); - const cityName = helper.city("makeProduct", "cityName", _cityName); - const productName = helper.string("makeProduct", "productName", _productName); - const designInvest = helper.number("makeProduct", "designInvest", _designInvest); - const marketingInvest = helper.number("makeProduct", "marketingInvest", _marketingInvest); - const corporation = getCorporation(); - MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest); - }, - limitProductProduction: function ( - _divisionName: unknown, - _productName: unknown, - _cityName: unknown, - _qty: unknown, - ) { - checkAccess("limitProductProduction", 7); - const divisionName = helper.string("limitProductProduction", "divisionName", _divisionName); - const cityName = helper.city("limitMaterialProduction", "cityName", _cityName); - const productName = helper.string("limitProductProduction", "productName", _productName); - const qty = helper.number("limitMaterialProduction", "qty", _qty); - LimitProductProduction(getProduct(divisionName, productName), cityName, qty); - }, - exportMaterial: function ( - _sourceDivision: unknown, - _sourceCity: unknown, - _targetDivision: unknown, - _targetCity: unknown, - _materialName: unknown, - _amt: unknown, - ): void { - checkAccess("exportMaterial", 7); - const sourceDivision = helper.string("exportMaterial", "sourceDivision", _sourceDivision); - const sourceCity = helper.string("exportMaterial", "sourceCity", _sourceCity); - const targetDivision = helper.string("exportMaterial", "targetDivision", _targetDivision); - const targetCity = helper.string("exportMaterial", "targetCity", _targetCity); - const materialName = helper.string("exportMaterial", "materialName", _materialName); - const amt = helper.string("exportMaterial", "amt", _amt); - ExportMaterial( - targetDivision, - targetCity, - getMaterial(sourceDivision, sourceCity, materialName), - amt + "", - getDivision(targetDivision), - ); - }, - cancelExportMaterial: function ( - _sourceDivision: unknown, - _sourceCity: unknown, - _targetDivision: unknown, - _targetCity: unknown, - _materialName: unknown, - _amt: unknown, - ): void { - checkAccess("cancelExportMaterial", 7); - const sourceDivision = helper.string("cancelExportMaterial", "sourceDivision", _sourceDivision); - const sourceCity = helper.string("cancelExportMaterial", "sourceCity", _sourceCity); - const targetDivision = helper.string("cancelExportMaterial", "targetDivision", _targetDivision); - const targetCity = helper.string("cancelExportMaterial", "targetCity", _targetCity); - const materialName = helper.string("cancelExportMaterial", "materialName", _materialName); - const amt = helper.string("cancelExportMaterial", "amt", _amt); - CancelExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + ""); - }, - limitMaterialProduction: function ( - _divisionName: unknown, - _cityName: unknown, - _materialName: unknown, - _qty: unknown, - ) { - checkAccess("limitMaterialProduction", 7); - const divisionName = helper.string("limitMaterialProduction", "divisionName", _divisionName); - const cityName = helper.city("limitMaterialProduction", "cityName", _cityName); - const materialName = helper.string("limitMaterialProduction", "materialName", _materialName); - const qty = helper.number("limitMaterialProduction", "qty", _qty); - LimitMaterialProduction(getMaterial(divisionName, cityName, materialName), qty); - }, - setMaterialMarketTA1: function ( - _divisionName: unknown, - _cityName: unknown, - _materialName: unknown, - _on: unknown, - ): void { - checkAccess("setMaterialMarketTA1", 7); - const divisionName = helper.string("setMaterialMarketTA1", "divisionName", _divisionName); - const cityName = helper.city("setMaterialMarketTA1", "cityName", _cityName); - const materialName = helper.string("setMaterialMarketTA1", "materialName", _materialName); - const on = helper.boolean(_on); - if (!getDivision(divisionName).hasResearch("Market-TA.I")) - throw helper.makeRuntimeErrorMsg( - `corporation.setMaterialMarketTA1`, - `You have not researched MarketTA.I for division: ${divisionName}`, - ); - SetMaterialMarketTA1(getMaterial(divisionName, cityName, materialName), on); - }, - setMaterialMarketTA2: function ( - _divisionName: unknown, - _cityName: unknown, - _materialName: unknown, - _on: unknown, - ): void { - checkAccess("setMaterialMarketTA2", 7); - const divisionName = helper.string("setMaterialMarketTA2", "divisionName", _divisionName); - const cityName = helper.city("setMaterialMarketTA2", "cityName", _cityName); - const materialName = helper.string("setMaterialMarketTA2", "materialName", _materialName); - const on = helper.boolean(_on); - if (!getDivision(divisionName).hasResearch("Market-TA.II")) - throw helper.makeRuntimeErrorMsg( - `corporation.setMaterialMarketTA2`, - `You have not researched MarketTA.II for division: ${divisionName}`, - ); - SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on); - }, - setProductMarketTA1: function (_divisionName: unknown, _productName: unknown, _on: unknown): void { - checkAccess("setProductMarketTA1", 7); - const divisionName = helper.string("setProductMarketTA1", "divisionName", _divisionName); - const productName = helper.string("setProductMarketTA1", "productName", _productName); - const on = helper.boolean(_on); - if (!getDivision(divisionName).hasResearch("Market-TA.I")) - throw helper.makeRuntimeErrorMsg( - `corporation.setProductMarketTA1`, - `You have not researched MarketTA.I for division: ${divisionName}`, - ); - SetProductMarketTA1(getProduct(divisionName, productName), on); - }, - setProductMarketTA2: function (_divisionName: unknown, _productName: unknown, _on: unknown): void { - checkAccess("setProductMarketTA2", 7); - const divisionName = helper.string("setProductMarketTA2", "divisionName", _divisionName); - const productName = helper.string("setProductMarketTA2", "productName", _productName); - const on = helper.boolean(_on); - if (!getDivision(divisionName).hasResearch("Market-TA.II")) - throw helper.makeRuntimeErrorMsg( - `corporation.setProductMarketTA2`, - `You have not researched MarketTA.II for division: ${divisionName}`, - ); - SetProductMarketTA2(getProduct(divisionName, productName), on); - }, + }, + limitMaterialProduction: + (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); + 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); + if (!getDivision(divisionName).hasResearch("Market-TA.I")) + throw ctx.makeRuntimeErrorMsg(`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); + if (!getDivision(divisionName).hasResearch("Market-TA.II")) + throw ctx.makeRuntimeErrorMsg(`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); + if (!getDivision(divisionName).hasResearch("Market-TA.I")) + throw ctx.makeRuntimeErrorMsg(`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); + if (!getDivision(divisionName).hasResearch("Market-TA.II")) + throw ctx.makeRuntimeErrorMsg(`You have not researched MarketTA.II for division: ${divisionName}`); + SetProductMarketTA2(getProduct(divisionName, productName), on); + }, }; - const officeAPI: OfficeAPI = { - getHireAdVertCost: function (_divisionName: unknown): number { - checkAccess("getHireAdVertCost", 8); - const divisionName = helper.string("getHireAdVertCost", "divisionName", _divisionName); - const division = getDivision(divisionName); - const upgrade = IndustryUpgrades[1]; - return upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]); - }, - getHireAdVertCount: function (_divisionName: unknown): number { - checkAccess("getHireAdVertCount", 8); - const divisionName = helper.string("getHireAdVertCount", "divisionName", _divisionName); - const division = getDivision(divisionName); - return division.upgrades[1]; - }, - getResearchCost: function (_divisionName: unknown, _researchName: unknown): number { - checkAccess("getResearchCost", 8); - const divisionName = helper.string("getResearchCost", "divisionName", _divisionName); - const researchName = helper.string("getResearchCost", "researchName", _researchName); - return getResearchCost(getDivision(divisionName), researchName); - }, - hasResearched: function (_divisionName: unknown, _researchName: unknown): boolean { - checkAccess("hasResearched", 8); - const divisionName = helper.string("hasResearched", "divisionName", _divisionName); - const researchName = helper.string("hasResearched", "researchName", _researchName); - return hasResearched(getDivision(divisionName), researchName); - }, - setAutoJobAssignment: function ( - _divisionName: unknown, - _cityName: unknown, - _job: unknown, - _amount: unknown, - ): Promise { - checkAccess("setAutoJobAssignment", 8); - const divisionName = helper.string("setAutoJobAssignment", "divisionName", _divisionName); - const cityName = helper.city("setAutoJobAssignment", "cityName", _cityName); - const amount = helper.number("setAutoJobAssignment", "amount", _amount); - const job = helper.string("setAutoJobAssignment", "job", _job); - const office = getOffice(divisionName, cityName); - if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); - return netscriptDelay(1000, workerScript).then(function () { - return Promise.resolve(office.setEmployeeToJob(job, amount)); - }); - }, - getOfficeSizeUpgradeCost: function (_divisionName: unknown, _cityName: unknown, _size: unknown): number { - checkAccess("getOfficeSizeUpgradeCost", 8); - const divisionName = helper.string("getOfficeSizeUpgradeCost", "divisionName", _divisionName); - const cityName = helper.city("getOfficeSizeUpgradeCost", "cityName", _cityName); - const size = helper.number("getOfficeSizeUpgradeCost", "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); - const costMultiplier = 1.09; - let mult = 0; - for (let i = 0; i < size / CorporationConstants.OfficeInitialSize; ++i) { - mult += Math.pow(costMultiplier, initialPriceMult + i); - } - return CorporationConstants.OfficeInitialCost * mult; - }, - assignJob: function ( - _divisionName: unknown, - _cityName: unknown, - _employeeName: unknown, - _job: unknown, - ): Promise { - checkAccess("assignJob", 8); - const divisionName = helper.string("assignJob", "divisionName", _divisionName); - const cityName = helper.city("assignJob", "cityName", _cityName); - const employeeName = helper.string("assignJob", "employeeName", _employeeName); - const job = helper.string("assignJob", "job", _job); - const employee = getEmployee(divisionName, cityName, employeeName); - return netscriptDelay(1000, workerScript).then(function () { - return Promise.resolve(AssignJob(employee, job)); - }); - }, - hireEmployee: function (_divisionName: unknown, _cityName: unknown): any { - checkAccess("hireEmployee", 8); - const divisionName = helper.string("hireEmployee", "divisionName", _divisionName); - const cityName = helper.city("hireEmployee", "cityName", _cityName); - const office = getOffice(divisionName, cityName); - const employee = office.hireRandomEmployee(); - if (employee === undefined) return undefined; - return { - name: employee.name, - mor: employee.mor, - hap: employee.hap, - ene: employee.ene, - int: employee.int, - cha: employee.cha, - exp: employee.exp, - cre: employee.cre, - eff: employee.eff, - sal: employee.sal, - loc: employee.loc, - pos: employee.pos, - }; - }, - upgradeOfficeSize: function (_divisionName: unknown, _cityName: unknown, _size: unknown): void { - checkAccess("upgradeOfficeSize", 8); - const divisionName = helper.string("upgradeOfficeSize", "divisionName", _divisionName); - const cityName = helper.city("upgradeOfficeSize", "cityName", _cityName); - const size = helper.number("upgradeOfficeSize", "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(); - UpgradeOfficeSize(corporation, office, size); - }, - throwParty: function (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): Promise { - checkAccess("throwParty", 8); - const divisionName = helper.string("throwParty", "divisionName", _divisionName); - const cityName = helper.city("throwParty", "cityName", _cityName); - const costPerEmployee = helper.number("throwParty", "costPerEmployee", _costPerEmployee); - if (costPerEmployee < 0) - throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0"); - const office = getOffice(divisionName, cityName); - const corporation = getCorporation(); - return netscriptDelay( - (60 * 1000) / (player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)), - workerScript, - ).then(function () { - return Promise.resolve(ThrowParty(corporation, office, costPerEmployee)); - }); - }, - buyCoffee: function (_divisionName: unknown, _cityName: unknown): Promise { - checkAccess("buyCoffee", 8); - const divisionName = helper.string("buyCoffee", "divisionName", _divisionName); - const cityName = helper.city("buyCoffee", "cityName", _cityName); - const corporation = getCorporation(); - return netscriptDelay( - (60 * 1000) / (player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)), - workerScript, - ).then(function () { - return Promise.resolve(BuyCoffee(corporation, getDivision(divisionName), getOffice(divisionName, cityName))); - }); - }, - hireAdVert: function (_divisionName: unknown): void { - checkAccess("hireAdVert", 8); - const divisionName = helper.string("hireAdVert", "divisionName", _divisionName); - const corporation = getCorporation(); - HireAdVert(corporation, getDivision(divisionName), getOffice(divisionName, "Sector-12")); - }, - research: function (_divisionName: unknown, _researchName: unknown): void { - checkAccess("research", 8); - const divisionName = helper.string("research", "divisionName", _divisionName); - const researchName = helper.string("research", "researchName", _researchName); - Research(getDivision(divisionName), researchName); - }, - getOffice: function (_divisionName: unknown, _cityName: unknown): any { - checkAccess("getOffice", 8); - const divisionName = helper.string("getOffice", "divisionName", _divisionName); - const cityName = helper.city("getOffice", "cityName", _cityName); - const office = getOffice(divisionName, cityName); - return { - loc: office.loc, - size: office.size, - minEne: office.minEne, - maxEne: office.maxEne, - minHap: office.minHap, - maxHap: office.maxHap, - maxMor: office.maxMor, - employees: office.employees.map((e) => e.name), - employeeProd: { - Operations: office.employeeProd[EmployeePositions.Operations], - Engineer: office.employeeProd[EmployeePositions.Engineer], - Business: office.employeeProd[EmployeePositions.Business], - Management: office.employeeProd[EmployeePositions.Management], - "Research & Development": office.employeeProd[EmployeePositions.RandD], - Training: office.employeeProd[EmployeePositions.Training], - }, - employeeJobs: { - Operations: office.employeeJobs[EmployeePositions.Operations], - Engineer: office.employeeJobs[EmployeePositions.Engineer], - Business: office.employeeJobs[EmployeePositions.Business], - Management: office.employeeJobs[EmployeePositions.Management], - "Research & Development": office.employeeJobs[EmployeePositions.RandD], - Training: office.employeeJobs[EmployeePositions.Training], - Unassigned: office.employeeJobs[EmployeePositions.Unassigned], - }, - }; - }, - getEmployee: function (_divisionName: unknown, _cityName: unknown, _employeeName: unknown): NSEmployee { - checkAccess("getEmployee", 8); - const divisionName = helper.string("getEmployee", "divisionName", _divisionName); - const cityName = helper.city("getEmployee", "cityName", _cityName); - const employeeName = helper.string("getEmployee", "employeeName", _employeeName); - const employee = getEmployee(divisionName, cityName, employeeName); - return { - name: employee.name, - mor: employee.mor, - hap: employee.hap, - ene: employee.ene, - int: employee.int, - cha: employee.cha, - exp: employee.exp, - cre: employee.cre, - eff: employee.eff, - sal: employee.sal, - loc: employee.loc, - pos: employee.pos, - }; - }, + const officeAPI: InternalAPI = { + getHireAdVertCost: + (ctx: NetscriptContext) => + (_divisionName: unknown): number => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const division = getDivision(divisionName); + const upgrade = IndustryUpgrades[1]; + return upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]); + }, + getHireAdVertCount: + (ctx: NetscriptContext) => + (_divisionName: unknown): number => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const division = getDivision(divisionName); + return division.upgrades[1]; + }, + getResearchCost: + (ctx: NetscriptContext) => + (_divisionName: unknown, _researchName: unknown): number => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const researchName = ctx.helper.string("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); + return hasResearched(getDivision(divisionName), researchName); + }, + setAutoJobAssignment: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): Promise => { + 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 office = getOffice(divisionName, cityName); + if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); + return netscriptDelay(1000, workerScript).then(function () { + return Promise.resolve(office.setEmployeeToJob(job, amount)); + }); + }, + 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); + 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); + const costMultiplier = 1.09; + let mult = 0; + for (let i = 0; i < size / CorporationConstants.OfficeInitialSize; ++i) { + mult += Math.pow(costMultiplier, initialPriceMult + i); + } + return CorporationConstants.OfficeInitialCost * mult; + }, + assignJob: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): Promise => { + 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 employee = getEmployee(divisionName, cityName, employeeName); + return netscriptDelay(1000, workerScript).then(function () { + return Promise.resolve(AssignJob(employee, job)); + }); + }, + hireEmployee: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown): any => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const cityName = ctx.helper.city("cityName", _cityName); + const office = getOffice(divisionName, cityName); + const employee = office.hireRandomEmployee(); + if (employee === undefined) return undefined; + return { + name: employee.name, + mor: employee.mor, + hap: employee.hap, + ene: employee.ene, + int: employee.int, + cha: employee.cha, + exp: employee.exp, + cre: employee.cre, + eff: employee.eff, + sal: employee.sal, + loc: employee.loc, + pos: employee.pos, + }; + }, + upgradeOfficeSize: + (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); + 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(); + UpgradeOfficeSize(corporation, office, size); + }, + throwParty: + (ctx: NetscriptContext) => + async (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): Promise => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const cityName = ctx.helper.city("cityName", _cityName); + const costPerEmployee = ctx.helper.number("costPerEmployee", _costPerEmployee); + if (costPerEmployee < 0) + throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0"); + const office = getOffice(divisionName, cityName); + const corporation = getCorporation(); + return netscriptDelay( + (60 * 1000) / (player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)), + workerScript, + ).then(function () { + return Promise.resolve(ThrowParty(corporation, office, costPerEmployee)); + }); + }, + buyCoffee: + (ctx: NetscriptContext) => + async (_divisionName: unknown, _cityName: unknown): Promise => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const cityName = ctx.helper.city("cityName", _cityName); + const corporation = getCorporation(); + return netscriptDelay( + (60 * 1000) / (player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)), + workerScript, + ).then(function () { + return Promise.resolve(BuyCoffee(corporation, getDivision(divisionName), getOffice(divisionName, cityName))); + }); + }, + hireAdVert: + (ctx: NetscriptContext) => + (_divisionName: unknown): void => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const corporation = getCorporation(); + HireAdVert(corporation, getDivision(divisionName), getOffice(divisionName, "Sector-12")); + }, + research: + (ctx: NetscriptContext) => + (_divisionName: unknown, _researchName: unknown): void => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const researchName = ctx.helper.string("researchName", _researchName); + Research(getDivision(divisionName), researchName); + }, + getOffice: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown): any => { + checkAccess(ctx, 8); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const cityName = ctx.helper.city("cityName", _cityName); + const office = getOffice(divisionName, cityName); + return { + loc: office.loc, + size: office.size, + minEne: office.minEne, + maxEne: office.maxEne, + minHap: office.minHap, + maxHap: office.maxHap, + maxMor: office.maxMor, + employees: office.employees.map((e) => e.name), + employeeProd: { + Operations: office.employeeProd[EmployeePositions.Operations], + Engineer: office.employeeProd[EmployeePositions.Engineer], + Business: office.employeeProd[EmployeePositions.Business], + Management: office.employeeProd[EmployeePositions.Management], + "Research & Development": office.employeeProd[EmployeePositions.RandD], + Training: office.employeeProd[EmployeePositions.Training], + }, + employeeJobs: { + Operations: office.employeeJobs[EmployeePositions.Operations], + Engineer: office.employeeJobs[EmployeePositions.Engineer], + Business: office.employeeJobs[EmployeePositions.Business], + Management: office.employeeJobs[EmployeePositions.Management], + "Research & Development": office.employeeJobs[EmployeePositions.RandD], + Training: office.employeeJobs[EmployeePositions.Training], + Unassigned: office.employeeJobs[EmployeePositions.Unassigned], + }, + }; + }, + getEmployee: + (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 employee = getEmployee(divisionName, cityName, employeeName); + return { + name: employee.name, + mor: employee.mor, + hap: employee.hap, + ene: employee.ene, + int: employee.int, + cha: employee.cha, + exp: employee.exp, + cre: employee.cre, + eff: employee.eff, + sal: employee.sal, + loc: employee.loc, + pos: employee.pos, + }; + }, }; return { ...warehouseAPI, ...officeAPI, - expandIndustry: function (_industryName: unknown, _divisionName: unknown): void { - checkAccess("expandIndustry"); - const industryName = helper.string("expandIndustry", "industryName", _industryName); - const divisionName = helper.string("expandIndustry", "divisionName", _divisionName); - const corporation = getCorporation(); - NewIndustry(corporation, industryName, divisionName); - }, - expandCity: function (_divisionName: unknown, _cityName: unknown): void { - checkAccess("expandCity"); - const divisionName = helper.string("expandCity", "divisionName", _divisionName); - const cityName = helper.city("expandCity", "cityName", _cityName); - if (!CorporationConstants.Cities.includes(cityName)) throw new Error("Invalid city name"); - const corporation = getCorporation(); - const division = getDivision(divisionName); - NewCity(corporation, division, cityName); - }, - unlockUpgrade: function (_upgradeName: unknown): void { - checkAccess("unlockUpgrade"); - const upgradeName = helper.string("unlockUpgrade", "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}'`); - UnlockUpgrade(corporation, upgrade); - }, - levelUpgrade: function (_upgradeName: unknown): void { - checkAccess("levelUpgrade"); - const upgradeName = helper.string("levelUpgrade", "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}'`); - LevelUpgrade(corporation, upgrade); - }, - issueDividends: function (_percent: unknown): void { - checkAccess("issueDividends"); - const percent = helper.number("issueDividends", "percent", _percent); - if (percent < 0 || percent > 100) - throw new Error("Invalid value for percent field! Must be numeric, greater than 0, and less than 100"); - const corporation = getCorporation(); - if (!corporation.public) - throw helper.makeRuntimeErrorMsg(`corporation.issueDividends`, `Your company has not gone public!`); - IssueDividends(corporation, percent); - }, + 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 corporation = getCorporation(); + NewIndustry(corporation, industryName, divisionName); + }, + expandCity: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown): void => { + checkAccess(ctx); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const cityName = ctx.helper.city("cityName", _cityName); + if (!CorporationConstants.Cities.includes(cityName)) throw new Error("Invalid city name"); + const corporation = getCorporation(); + const division = getDivision(divisionName); + NewCity(corporation, division, cityName); + }, + unlockUpgrade: + (ctx: NetscriptContext) => + (_upgradeName: unknown): void => { + checkAccess(ctx); + const upgradeName = ctx.helper.string("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}'`); + UnlockUpgrade(corporation, upgrade); + }, + levelUpgrade: + (ctx: NetscriptContext) => + (_upgradeName: unknown): void => { + checkAccess(ctx); + const upgradeName = ctx.helper.string("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}'`); + LevelUpgrade(corporation, upgrade); + }, + issueDividends: + (ctx: NetscriptContext) => + (_percent: unknown): void => { + checkAccess(ctx); + const percent = ctx.helper.number("percent", _percent); + if (percent < 0 || percent > 100) + throw new Error("Invalid value for percent field! Must be numeric, greater than 0, and less than 100"); + const corporation = getCorporation(); + if (!corporation.public) throw ctx.makeRuntimeErrorMsg(`Your company has not gone public!`); + IssueDividends(corporation, percent); + }, // If you modify these objects you will affect them for real, it's not // copies. - getDivision: function (_divisionName: unknown): NSDivision { - checkAccess("getDivision"); - const divisionName = helper.string("getDivision", "divisionName", _divisionName); - const division = getDivision(divisionName); - return getSafeDivision(division); - }, - getCorporation: function (): CorporationInfo { - checkAccess("getCorporation"); + getDivision: + (ctx: NetscriptContext) => + (_divisionName: unknown): NSDivision => { + checkAccess(ctx); + const divisionName = ctx.helper.string("divisionName", _divisionName); + const division = getDivision(divisionName); + return getSafeDivision(division); + }, + getCorporation: (ctx: NetscriptContext) => (): CorporationInfo => { + checkAccess(ctx); const corporation = getCorporation(); return { name: corporation.name, @@ -928,72 +956,92 @@ export function NetscriptCorporation( divisions: corporation.divisions.map((division): NSDivision => getSafeDivision(division)), }; }, - createCorporation: function (_corporationName: unknown, _selfFund: unknown = true): boolean { - const corporationName = helper.string("createCorporation", "corporationName", _corporationName); - const selfFund = helper.boolean(_selfFund); - return createCorporation(corporationName, selfFund); - }, - hasUnlockUpgrade: function (_upgradeName: unknown): boolean { - checkAccess("hasUnlockUpgrade"); - const upgradeName = helper.string("hasUnlockUpgrade", "upgradeName", _upgradeName); - return hasUnlockUpgrade(upgradeName); - }, - getUnlockUpgradeCost: function (_upgradeName: unknown): number { - checkAccess("getUnlockUpgradeCost"); - const upgradeName = helper.string("getUnlockUpgradeCost", "upgradeName", _upgradeName); - return getUnlockUpgradeCost(upgradeName); - }, - getUpgradeLevel: function (_upgradeName: unknown): number { - checkAccess("hasUnlockUpgrade"); - const upgradeName = helper.string("getUpgradeLevel", "upgradeName", _upgradeName); - return getUpgradeLevel(upgradeName); - }, - getUpgradeLevelCost: function (_upgradeName: unknown): number { - checkAccess("getUpgradeLevelCost"); - const upgradeName = helper.string("getUpgradeLevelCost", "upgradeName", _upgradeName); - return getUpgradeLevelCost(upgradeName); - }, - getExpandIndustryCost: function (_industryName: unknown): number { - checkAccess("getExpandIndustryCost"); - const industryName = helper.string("getExpandIndustryCost", "industryName", _industryName); - return getExpandIndustryCost(industryName); - }, - getExpandCityCost: function (): number { - checkAccess("getExpandCityCost"); + createCorporation: + (ctx: NetscriptContext) => + (_corporationName: unknown, _selfFund: unknown = true): boolean => { + const corporationName = ctx.helper.string("corporationName", _corporationName); + const selfFund = ctx.helper.boolean(_selfFund); + return createCorporation(corporationName, selfFund); + }, + hasUnlockUpgrade: + (ctx: NetscriptContext) => + (_upgradeName: unknown): boolean => { + checkAccess(ctx); + const upgradeName = ctx.helper.string("upgradeName", _upgradeName); + return hasUnlockUpgrade(upgradeName); + }, + getUnlockUpgradeCost: + (ctx: NetscriptContext) => + (_upgradeName: unknown): number => { + checkAccess(ctx); + const upgradeName = ctx.helper.string("upgradeName", _upgradeName); + return getUnlockUpgradeCost(upgradeName); + }, + getUpgradeLevel: + (ctx: NetscriptContext) => + (_upgradeName: unknown): number => { + checkAccess(ctx); + const upgradeName = ctx.helper.string("upgradeName", _upgradeName); + return getUpgradeLevel(ctx, upgradeName); + }, + getUpgradeLevelCost: + (ctx: NetscriptContext) => + (_upgradeName: unknown): number => { + checkAccess(ctx); + const upgradeName = ctx.helper.string("upgradeName", _upgradeName); + return getUpgradeLevelCost(ctx, upgradeName); + }, + getExpandIndustryCost: + (ctx: NetscriptContext) => + (_industryName: unknown): number => { + checkAccess(ctx); + const industryName = ctx.helper.string("industryName", _industryName); + return getExpandIndustryCost(industryName); + }, + getExpandCityCost: (ctx: NetscriptContext) => (): number => { + checkAccess(ctx); return getExpandCityCost(); }, - getInvestmentOffer: function (): InvestmentOffer { - checkAccess("getInvestmentOffer"); + getInvestmentOffer: (ctx: NetscriptContext) => (): InvestmentOffer => { + checkAccess(ctx); return getInvestmentOffer(); }, - acceptInvestmentOffer: function (): boolean { - checkAccess("acceptInvestmentOffer"); + acceptInvestmentOffer: (ctx: NetscriptContext) => (): boolean => { + checkAccess(ctx); return acceptInvestmentOffer(); }, - goPublic: function (_numShares: unknown): boolean { - checkAccess("acceptInvestmentOffer"); - const numShares = helper.number("goPublic", "numShares", _numShares); - return goPublic(numShares); - }, - sellShares: function (_numShares: unknown): number { - checkAccess("acceptInvestmentOffer"); - const numShares = helper.number("sellStock", "numShares", _numShares); - return SellShares(getCorporation(), player, numShares); - }, - buyBackShares: function (_numShares: unknown): boolean { - checkAccess("acceptInvestmentOffer"); - const numShares = helper.number("buyStock", "numShares", _numShares); - return BuyBackShares(getCorporation(), player, numShares); - }, - bribe: function (_factionName: unknown, _amountCash: unknown, _amountShares: unknown): boolean { - checkAccess("bribe"); - const factionName = helper.string("bribe", "factionName", _factionName); - const amountCash = helper.number("bribe", "amountCash", _amountCash); - const amountShares = helper.number("bribe", "amountShares", _amountShares); - return bribe(factionName, amountCash, amountShares); - }, - getBonusTime: function (): number { - checkAccess("getBonusTime"); + goPublic: + (ctx: NetscriptContext) => + (_numShares: unknown): boolean => { + checkAccess(ctx); + const numShares = ctx.helper.number("numShares", _numShares); + return goPublic(numShares); + }, + sellShares: + (ctx: NetscriptContext) => + (_numShares: unknown): number => { + checkAccess(ctx); + const numShares = ctx.helper.number("numShares", _numShares); + return SellShares(getCorporation(), player, numShares); + }, + buyBackShares: + (ctx: NetscriptContext) => + (_numShares: unknown): boolean => { + checkAccess(ctx); + const numShares = ctx.helper.number("numShares", _numShares); + return BuyBackShares(getCorporation(), player, numShares); + }, + bribe: + (ctx: NetscriptContext) => + (_factionName: unknown, _amountCash: unknown, _amountShares: unknown): boolean => { + checkAccess(ctx); + const factionName = ctx.helper.string("factionName", _factionName); + const amountCash = ctx.helper.number("amountCash", _amountCash); + const amountShares = ctx.helper.number("amountShares", _amountShares); + return bribe(factionName, amountCash, amountShares); + }, + getBonusTime: (ctx: NetscriptContext) => (): number => { + checkAccess(ctx); return Math.round(getCorporation().storedCycles / 5) * 1000; }, }; diff --git a/src/NetscriptFunctions/Gang.ts b/src/NetscriptFunctions/Gang.ts index 14fd74d43..8eeb575a5 100644 --- a/src/NetscriptFunctions/Gang.ts +++ b/src/NetscriptFunctions/Gang.ts @@ -1,8 +1,6 @@ import { FactionNames } from "../Faction/data/FactionNames"; import { GangConstants } from "../Gang/data/Constants"; -import { INetscriptHelper } from "./INetscriptHelper"; import { IPlayer } from "../PersonObjects/IPlayer"; -import { getRamCost } from "../Netscript/RamCostGenerator"; import { Gang } from "../Gang/Gang"; import { AllGangs } from "../Gang/AllGangs"; import { GangMemberTasks } from "../Gang/GangMemberTasks"; @@ -20,63 +18,60 @@ import { EquipmentStats, GangTaskStats, } from "../ScriptEditor/NetscriptDefinitions"; +import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; -export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IGang { - const checkGangApiAccess = function (func: string): void { +export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): InternalAPI { + 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 helper.makeRuntimeErrorMsg(`gang.${func}`, `You do not currently have a Gang`); + throw ctx.makeRuntimeErrorMsg(`You do not currently have a Gang`); } }; - const getGangMember = function (func: string, name: string): GangMember { + const getGangMember = function (ctx: NetscriptContext, name: string): GangMember { 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 helper.makeRuntimeErrorMsg(`gang.${func}`, `Invalid gang member: '${name}'`); + throw ctx.makeRuntimeErrorMsg(`Invalid gang member: '${name}'`); }; - const getGangTask = function (func: string, name: string): GangMemberTask { + const getGangTask = function (ctx: NetscriptContext, name: string): GangMemberTask { const task = GangMemberTasks[name]; if (!task) { - throw helper.makeRuntimeErrorMsg(`gang.${func}`, `Invalid task: '${name}'`); + throw ctx.makeRuntimeErrorMsg(`Invalid task: '${name}'`); } return task; }; - const updateRam = (funcName: string): void => helper.updateDynamicRam(funcName, getRamCost(player, "gang", funcName)); - return { - createGang: function (_faction: unknown): boolean { - updateRam("createGang"); - const faction = helper.string("createGang", "faction", _faction); - // this list is copied from Faction/ui/Root.tsx + createGang: + (ctx: NetscriptContext) => + (_faction: unknown): boolean => { + const faction = ctx.helper.string("faction", _faction); + // this list is copied from Faction/ui/Root.tsx - if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false; - if (player.inGang()) return false; - if (!player.factions.includes(faction)) return false; + if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false; + if (player.inGang()) return false; + if (!player.factions.includes(faction)) return false; - const isHacking = faction === FactionNames.NiteSec || faction === FactionNames.TheBlackHand; - player.startGang(faction, isHacking); - return true; - }, - inGang: function (): boolean { - updateRam("inGang"); + const isHacking = faction === FactionNames.NiteSec || faction === FactionNames.TheBlackHand; + player.startGang(faction, isHacking); + return true; + }, + inGang: () => (): boolean => { return player.inGang(); }, - getMemberNames: function (): string[] { - updateRam("getMemberNames"); - checkGangApiAccess("getMemberNames"); + getMemberNames: (ctx: NetscriptContext) => (): string[] => { + checkGangApiAccess(ctx); const gang = player.gang; if (gang === null) throw new Error("Should not be called without Gang"); return gang.members.map((member) => member.name); }, - getGangInformation: function (): GangGenInfo { - updateRam("getGangInformation"); - checkGangApiAccess("getGangInformation"); + getGangInformation: (ctx: NetscriptContext) => (): GangGenInfo => { + checkGangApiAccess(ctx); const gang = player.gang; if (gang === null) throw new Error("Should not be called without Gang"); return { @@ -94,9 +89,8 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe wantedPenalty: gang.getWantedPenalty(), }; }, - getOtherGangInformation: function (): GangOtherInfo { - updateRam("getOtherGangInformation"); - checkGangApiAccess("getOtherGangInformation"); + getOtherGangInformation: (ctx: NetscriptContext) => (): GangOtherInfo => { + checkGangApiAccess(ctx); const cpy: any = {}; for (const gang of Object.keys(AllGangs)) { cpy[gang] = Object.assign({}, AllGangs[gang]); @@ -104,242 +98,251 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe return cpy; }, - getMemberInformation: function (_memberName: unknown): GangMemberInfo { - updateRam("getMemberInformation"); - const memberName = helper.string("getMemberInformation", "memberName", _memberName); - checkGangApiAccess("getMemberInformation"); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - const member = getGangMember("getMemberInformation", memberName); - return { - name: member.name, - task: member.task, - earnedRespect: member.earnedRespect, - hack: member.hack, - str: member.str, - def: member.def, - dex: member.dex, - agi: member.agi, - cha: member.cha, + getMemberInformation: + (ctx: NetscriptContext) => + (_memberName: unknown): GangMemberInfo => { + const memberName = ctx.helper.string("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); + return { + name: member.name, + task: member.task, + earnedRespect: member.earnedRespect, + hack: member.hack, + str: member.str, + def: member.def, + dex: member.dex, + agi: member.agi, + cha: member.cha, - hack_exp: member.hack_exp, - str_exp: member.str_exp, - def_exp: member.def_exp, - dex_exp: member.dex_exp, - agi_exp: member.agi_exp, - cha_exp: member.cha_exp, + hack_exp: member.hack_exp, + str_exp: member.str_exp, + def_exp: member.def_exp, + dex_exp: member.dex_exp, + agi_exp: member.agi_exp, + cha_exp: member.cha_exp, - hack_mult: member.hack_mult, - str_mult: member.str_mult, - def_mult: member.def_mult, - dex_mult: member.dex_mult, - agi_mult: member.agi_mult, - cha_mult: member.cha_mult, + hack_mult: member.hack_mult, + str_mult: member.str_mult, + def_mult: member.def_mult, + dex_mult: member.dex_mult, + agi_mult: member.agi_mult, + cha_mult: member.cha_mult, - hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points), - str_asc_mult: member.calculateAscensionMult(member.str_asc_points), - def_asc_mult: member.calculateAscensionMult(member.def_asc_points), - dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points), - agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points), - cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points), + hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points), + str_asc_mult: member.calculateAscensionMult(member.str_asc_points), + def_asc_mult: member.calculateAscensionMult(member.def_asc_points), + dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points), + agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points), + cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points), - hack_asc_points: member.hack_asc_points, - str_asc_points: member.str_asc_points, - def_asc_points: member.def_asc_points, - dex_asc_points: member.dex_asc_points, - agi_asc_points: member.agi_asc_points, - cha_asc_points: member.cha_asc_points, + hack_asc_points: member.hack_asc_points, + str_asc_points: member.str_asc_points, + def_asc_points: member.def_asc_points, + dex_asc_points: member.dex_asc_points, + agi_asc_points: member.agi_asc_points, + cha_asc_points: member.cha_asc_points, - upgrades: member.upgrades.slice(), - augmentations: member.augmentations.slice(), + upgrades: member.upgrades.slice(), + augmentations: member.augmentations.slice(), - respectGain: member.calculateRespectGain(gang), - wantedLevelGain: member.calculateWantedLevelGain(gang), - moneyGain: member.calculateMoneyGain(gang), - }; - }, - canRecruitMember: function (): boolean { - updateRam("canRecruitMember"); - checkGangApiAccess("canRecruitMember"); + respectGain: member.calculateRespectGain(gang), + wantedLevelGain: member.calculateWantedLevelGain(gang), + moneyGain: member.calculateMoneyGain(gang), + }; + }, + canRecruitMember: (ctx: NetscriptContext) => (): boolean => { + checkGangApiAccess(ctx); const gang = player.gang; if (gang === null) throw new Error("Should not be called without Gang"); return gang.canRecruitMember(); }, - recruitMember: function (_memberName: unknown): boolean { - updateRam("recruitMember"); - const memberName = helper.string("recruitMember", "memberName", _memberName); - checkGangApiAccess("recruitMember"); - 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}'`); - } else { - workerScript.log("gang.recruitMember", () => `Failed to recruit Gang Member '${memberName}'`); - } + recruitMember: + (ctx: NetscriptContext) => + (_memberName: unknown): boolean => { + const memberName = ctx.helper.string("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}'`); + } else { + workerScript.log("gang.recruitMember", () => `Failed to recruit Gang Member '${memberName}'`); + } - return recruited; - }, - getTaskNames: function (): string[] { - updateRam("getTaskNames"); - checkGangApiAccess("getTaskNames"); + return recruited; + }, + getTaskNames: (ctx: NetscriptContext) => (): string[] => { + checkGangApiAccess(ctx); const gang = player.gang; if (gang === null) throw new Error("Should not be called without Gang"); const tasks = gang.getAllTaskNames(); tasks.unshift("Unassigned"); return tasks; }, - setMemberTask: function (_memberName: unknown, _taskName: unknown): boolean { - updateRam("setMemberTask"); - const memberName = helper.string("setMemberTask", "memberName", _memberName); - const taskName = helper.string("setMemberTask", "taskName", _taskName); - checkGangApiAccess("setMemberTask"); - const member = getGangMember("setMemberTask", memberName); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - if (!gang.getAllTaskNames().includes(taskName)) { - workerScript.log( - "gang.setMemberTask", - () => - `Failed to assign Gang Member '${memberName}' to Invalid task '${taskName}'. '${memberName}' is now Unassigned`, - ); - return member.assignToTask("Unassigned"); - } - const success = member.assignToTask(taskName); - if (success) { - workerScript.log( - "gang.setMemberTask", - () => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`, - ); - } else { - workerScript.log( - "gang.setMemberTask", - () => `Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`, - ); - } + setMemberTask: + (ctx: NetscriptContext) => + (_memberName: unknown, _taskName: unknown): boolean => { + const memberName = ctx.helper.string("memberName", _memberName); + const taskName = ctx.helper.string("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( + "gang.setMemberTask", + () => + `Failed to assign Gang Member '${memberName}' to Invalid task '${taskName}'. '${memberName}' is now Unassigned`, + ); + return member.assignToTask("Unassigned"); + } + const success = member.assignToTask(taskName); + if (success) { + workerScript.log( + "gang.setMemberTask", + () => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`, + ); + } else { + workerScript.log( + "gang.setMemberTask", + () => + `Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`, + ); + } - return success; - }, - getTaskStats: function (_taskName: unknown): GangTaskStats { - updateRam("getTaskStats"); - const taskName = helper.string("getTaskStats", "taskName", _taskName); - checkGangApiAccess("getTaskStats"); - const task = getGangTask("getTaskStats", taskName); - const copy = Object.assign({}, task); - copy.territory = Object.assign({}, task.territory); - return copy; - }, - getEquipmentNames: function (): string[] { - updateRam("getEquipmentNames"); - checkGangApiAccess("getEquipmentNames"); + return success; + }, + getTaskStats: + (ctx: NetscriptContext) => + (_taskName: unknown): GangTaskStats => { + const taskName = ctx.helper.string("taskName", _taskName); + checkGangApiAccess(ctx); + const task = getGangTask(ctx, taskName); + const copy = Object.assign({}, task); + copy.territory = Object.assign({}, task.territory); + return copy; + }, + getEquipmentNames: (ctx: NetscriptContext) => (): string[] => { + checkGangApiAccess(ctx); return Object.keys(GangMemberUpgrades); }, - getEquipmentCost: function (_equipName: any): number { - updateRam("getEquipmentCost"); - const equipName = helper.string("getEquipmentCost", "equipName", _equipName); - checkGangApiAccess("getEquipmentCost"); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - const upg = GangMemberUpgrades[equipName]; - if (upg === null) return Infinity; - return gang.getUpgradeCost(upg); - }, - getEquipmentType: function (_equipName: unknown): string { - updateRam("getEquipmentType"); - const equipName = helper.string("getEquipmentType", "equipName", _equipName); - checkGangApiAccess("getEquipmentType"); - const upg = GangMemberUpgrades[equipName]; - if (upg == null) return ""; - return upg.getType(); - }, - getEquipmentStats: function (_equipName: unknown): EquipmentStats { - updateRam("getEquipmentStats"); - const equipName = helper.string("getEquipmentStats", "equipName", _equipName); - checkGangApiAccess("getEquipmentStats"); - const equipment = GangMemberUpgrades[equipName]; - if (!equipment) { - throw helper.makeRuntimeErrorMsg("getEquipmentStats", `Invalid equipment: ${equipName}`); - } - const typecheck: EquipmentStats = equipment.mults; - return Object.assign({}, typecheck) as any; - }, - purchaseEquipment: function (_memberName: unknown, _equipName: unknown): boolean { - updateRam("purchaseEquipment"); - const memberName = helper.string("purchaseEquipment", "memberName", _memberName); - const equipName = helper.string("purchaseEquipment", "equipName", _equipName); - checkGangApiAccess("purchaseEquipment"); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - const member = getGangMember("purchaseEquipment", memberName); - const equipment = GangMemberUpgrades[equipName]; - if (!equipment) return false; - const res = member.buyUpgrade(equipment, player, gang); - if (res) { - workerScript.log("gang.purchaseEquipment", () => `Purchased '${equipName}' for Gang member '${memberName}'`); - } else { - workerScript.log( - "gang.purchaseEquipment", - () => `Failed to purchase '${equipName}' for Gang member '${memberName}'`, - ); - } + getEquipmentCost: + (ctx: NetscriptContext) => + (_equipName: any): number => { + const equipName = ctx.helper.string("equipName", _equipName); + checkGangApiAccess(ctx); + const gang = player.gang; + if (gang === null) throw new Error("Should not be called without Gang"); + const upg = GangMemberUpgrades[equipName]; + if (upg === null) return Infinity; + return gang.getUpgradeCost(upg); + }, + getEquipmentType: + (ctx: NetscriptContext) => + (_equipName: unknown): string => { + const equipName = ctx.helper.string("equipName", _equipName); + checkGangApiAccess(ctx); + const upg = GangMemberUpgrades[equipName]; + if (upg == null) return ""; + return upg.getType(); + }, + getEquipmentStats: + (ctx: NetscriptContext) => + (_equipName: unknown): EquipmentStats => { + const equipName = ctx.helper.string("equipName", _equipName); + checkGangApiAccess(ctx); + const equipment = GangMemberUpgrades[equipName]; + if (!equipment) { + throw ctx.makeRuntimeErrorMsg(`Invalid equipment: ${equipName}`); + } + const typecheck: EquipmentStats = equipment.mults; + return Object.assign({}, typecheck) as any; + }, + purchaseEquipment: + (ctx: NetscriptContext) => + (_memberName: unknown, _equipName: unknown): boolean => { + const memberName = ctx.helper.string("memberName", _memberName); + const equipName = ctx.helper.string("equipName", _equipName); + checkGangApiAccess(ctx); + const gang = player.gang; + if (gang === null) throw new Error("Should not be called without Gang"); + const member = getGangMember(ctx, memberName); + const equipment = GangMemberUpgrades[equipName]; + if (!equipment) return false; + const res = member.buyUpgrade(equipment, player, gang); + if (res) { + workerScript.log("gang.purchaseEquipment", () => `Purchased '${equipName}' for Gang member '${memberName}'`); + } else { + workerScript.log( + "gang.purchaseEquipment", + () => `Failed to purchase '${equipName}' for Gang member '${memberName}'`, + ); + } - return res; - }, - ascendMember: function (_memberName: unknown): GangMemberAscension | undefined { - updateRam("ascendMember"); - const memberName = helper.string("ascendMember", "memberName", _memberName); - checkGangApiAccess("ascendMember"); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - const member = getGangMember("ascendMember", memberName); - if (!member.canAscend()) return; - return gang.ascendMember(member, workerScript); - }, - getAscensionResult: function (_memberName: unknown): GangMemberAscension | undefined { - updateRam("getAscensionResult"); - const memberName = helper.string("getAscensionResult", "memberName", _memberName); - checkGangApiAccess("getAscensionResult"); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - const member = getGangMember("getAscensionResult", memberName); - if (!member.canAscend()) return; - return { - respect: member.earnedRespect, - ...member.getAscensionResults(), - }; - }, - setTerritoryWarfare: function (_engage: unknown): void { - updateRam("setTerritoryWarfare"); - const engage = helper.boolean(_engage); - checkGangApiAccess("setTerritoryWarfare"); - 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"); - } else { - gang.territoryWarfareEngaged = false; - workerScript.log("gang.setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare"); - } - }, - getChanceToWinClash: function (_otherGang: unknown): number { - updateRam("getChanceToWinClash"); - const otherGang = helper.string("getChanceToWinClash", "otherGang", _otherGang); - checkGangApiAccess("getChanceToWinClash"); - const gang = player.gang; - if (gang === null) throw new Error("Should not be called without Gang"); - if (AllGangs[otherGang] == null) { - throw helper.makeRuntimeErrorMsg(`gang.getChanceToWinClash`, `Invalid gang: ${otherGang}`); - } + return res; + }, + ascendMember: + (ctx: NetscriptContext) => + (_memberName: unknown): GangMemberAscension | undefined => { + const memberName = ctx.helper.string("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); + }, + getAscensionResult: + (ctx: NetscriptContext) => + (_memberName: unknown): GangMemberAscension | undefined => { + const memberName = ctx.helper.string("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 { + respect: member.earnedRespect, + ...member.getAscensionResults(), + }; + }, + setTerritoryWarfare: + (ctx: NetscriptContext) => + (_engage: unknown): void => { + const engage = ctx.helper.boolean(_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"); + } else { + gang.territoryWarfareEngaged = false; + workerScript.log("gang.setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare"); + } + }, + getChanceToWinClash: + (ctx: NetscriptContext) => + (_otherGang: unknown): number => { + const otherGang = ctx.helper.string("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}`); + } - const playerPower = AllGangs[gang.facName].power; - const otherPower = AllGangs[otherGang].power; + const playerPower = AllGangs[gang.facName].power; + const otherPower = AllGangs[otherGang].power; - return playerPower / (otherPower + playerPower); - }, - getBonusTime: function (): number { - updateRam("getBonusTime"); - checkGangApiAccess("getBonusTime"); + return playerPower / (otherPower + playerPower); + }, + getBonusTime: (ctx: NetscriptContext) => (): number => { + checkGangApiAccess(ctx); const gang = player.gang; if (gang === null) throw new Error("Should not be called without Gang"); return Math.round(gang.storedCycles / 5) * 1000; diff --git a/src/NetscriptFunctions/Grafting.ts b/src/NetscriptFunctions/Grafting.ts index 0837eee5f..021f935a4 100644 --- a/src/NetscriptFunctions/Grafting.ts +++ b/src/NetscriptFunctions/Grafting.ts @@ -1,104 +1,97 @@ +import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { StaticAugmentations } from "../Augmentation/StaticAugmentations"; import { hasAugmentationPrereqs } from "../Faction/FactionHelpers"; import { CityName } from "../Locations/data/CityNames"; -import { getRamCost } from "../Netscript/RamCostGenerator"; -import { WorkerScript } from "../Netscript/WorkerScript"; import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation"; import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../PersonObjects/Grafting/GraftingHelpers"; import { IPlayer } from "../PersonObjects/IPlayer"; import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions"; import { Router } from "../ui/GameRoot"; -import { INetscriptHelper } from "./INetscriptHelper"; -export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IGrafting { - const checkGraftingAPIAccess = (func: string): void => { +export function NetscriptGrafting(player: IPlayer): InternalAPI { + const checkGraftingAPIAccess = (ctx: NetscriptContext): void => { if (!player.canAccessGrafting()) { - throw helper.makeRuntimeErrorMsg( - `grafting.${func}`, + throw ctx.makeRuntimeErrorMsg( "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", ); } }; - const updateRam = (funcName: string): void => - helper.updateDynamicRam(funcName, getRamCost(player, "grafting", funcName)); - return { - getAugmentationGraftPrice: (_augName: unknown): number => { - updateRam("getAugmentationGraftPrice"); - const augName = helper.string("getAugmentationGraftPrice", "augName", _augName); - checkGraftingAPIAccess("getAugmentationGraftPrice"); - if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { - throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftPrice", `Invalid aug: ${augName}`); - } - const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]); - return graftableAug.cost; - }, + getAugmentationGraftPrice: + (ctx: NetscriptContext) => + (_augName: unknown): number => { + const augName = ctx.helper.string("augName", _augName); + checkGraftingAPIAccess(ctx); + if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { + throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`); + } + const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]); + return graftableAug.cost; + }, - getAugmentationGraftTime: (_augName: string): number => { - updateRam("getAugmentationGraftTime"); - const augName = helper.string("getAugmentationGraftTime", "augName", _augName); - checkGraftingAPIAccess("getAugmentationGraftTime"); - if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { - throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftTime", `Invalid aug: ${augName}`); - } - const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]); - return calculateGraftingTimeWithBonus(player, graftableAug); - }, + getAugmentationGraftTime: + (ctx: NetscriptContext) => + (_augName: string): number => { + const augName = ctx.helper.string("augName", _augName); + checkGraftingAPIAccess(ctx); + if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { + throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`); + } + const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]); + return calculateGraftingTimeWithBonus(player, graftableAug); + }, - getGraftableAugmentations: (): string[] => { - updateRam("getGraftableAugmentations"); - checkGraftingAPIAccess("getGraftableAugmentations"); + getGraftableAugmentations: (ctx: NetscriptContext) => (): string[] => { + checkGraftingAPIAccess(ctx); const graftableAugs = getGraftingAvailableAugs(player); return graftableAugs; }, - graftAugmentation: (_augName: string, _focus: unknown = true): boolean => { - updateRam("graftAugmentation"); - const augName = helper.string("graftAugmentation", "augName", _augName); - const focus = helper.boolean(_focus); - checkGraftingAPIAccess("graftAugmentation"); - if (player.city !== CityName.NewTokyo) { - throw helper.makeRuntimeErrorMsg( - "grafting.graftAugmentation", - "You must be in New Tokyo to begin grafting an Augmentation.", - ); - } - if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { - workerScript.log("grafting.graftAugmentation", () => `Invalid aug: ${augName}`); - return false; - } + graftAugmentation: + (ctx: NetscriptContext) => + (_augName: string, _focus: unknown = true): boolean => { + const augName = ctx.helper.string("augName", _augName); + const focus = ctx.helper.boolean(_focus); + checkGraftingAPIAccess(ctx); + if (player.city !== CityName.NewTokyo) { + throw ctx.makeRuntimeErrorMsg("You must be in New Tokyo to begin grafting an Augmentation."); + } + if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) { + ctx.log(() => `Invalid aug: ${augName}`); + return false; + } - const wasFocusing = player.focus; - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("graftAugmentation", () => txt); - } + const wasFocusing = player.focus; + if (player.isWorking) { + const txt = player.singularityStopWork(); + ctx.log(() => txt); + } - const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]); - if (player.money < craftableAug.cost) { - workerScript.log("grafting.graftAugmentation", () => `You don't have enough money to craft ${augName}`); - return false; - } + const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]); + if (player.money < craftableAug.cost) { + ctx.log(() => `You don't have enough money to craft ${augName}`); + return false; + } - if (!hasAugmentationPrereqs(craftableAug.augmentation)) { - workerScript.log("grafting.graftAugmentation", () => `You don't have the pre-requisites for ${augName}`); - return false; - } + if (!hasAugmentationPrereqs(craftableAug.augmentation)) { + ctx.log(() => `You don't have the pre-requisites for ${augName}`); + return false; + } - player.loseMoney(craftableAug.cost, "augmentations"); - player.startGraftAugmentationWork(augName, craftableAug.time); + player.loseMoney(craftableAug.cost, "augmentations"); + player.startGraftAugmentationWork(augName, craftableAug.time); - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } - workerScript.log("grafting.graftAugmentation", () => `Began grafting Augmentation ${augName}.`); - return true; - }, + ctx.log(() => `Began grafting Augmentation ${augName}.`); + return true; + }, }; } diff --git a/src/NetscriptFunctions/Hacknet.ts b/src/NetscriptFunctions/Hacknet.ts index b771a12bd..5bbdb77a8 100644 --- a/src/NetscriptFunctions/Hacknet.ts +++ b/src/NetscriptFunctions/Hacknet.ts @@ -1,4 +1,3 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { IPlayer } from "../PersonObjects/IPlayer"; import { WorkerScript } from "../Netscript/WorkerScript"; import { HacknetServerConstants } from "../Hacknet/data/Constants"; @@ -21,12 +20,13 @@ import { HashUpgrade } from "../Hacknet/HashUpgrade"; import { GetServer } from "../Server/AllServers"; import { Hacknet as IHacknet, NodeStats } from "../ScriptEditor/NetscriptDefinitions"; +import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; -export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IHacknet { +export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): InternalAPI { // Utility function to get Hacknet Node object - const getHacknetNode = function (i: number, callingFn = ""): HacknetNode | HacknetServer { + const getHacknetNode = function (ctx: NetscriptContext, i: number): HacknetNode | HacknetServer { if (i < 0 || i >= player.hacknetNodes.length) { - throw helper.makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i); + throw ctx.makeRuntimeErrorMsg("Index specified for Hacknet Node is out-of-bounds: " + i); } if (hasHacknetServers(player)) { @@ -35,8 +35,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he const hserver = GetServer(hi); if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server"); if (hserver == null) { - throw helper.makeRuntimeErrorMsg( - callingFn, + throw ctx.makeRuntimeErrorMsg( `Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`, ); } @@ -50,162 +49,186 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he }; return { - numNodes: function (): number { + numNodes: () => (): number => { return player.hacknetNodes.length; }, - maxNumNodes: function (): number { + maxNumNodes: () => (): number => { if (hasHacknetServers(player)) { return HacknetServerConstants.MaxServers; } return Infinity; }, - purchaseNode: function (): number { + purchaseNode: () => (): number => { return purchaseHacknet(player); }, - getPurchaseNodeCost: function (): number { + getPurchaseNodeCost: () => (): number => { if (hasHacknetServers(player)) { return getCostOfNextHacknetServer(player); } else { return getCostOfNextHacknetNode(player); } }, - getNodeStats: function (_i: unknown): NodeStats { - const i = helper.number("getNodeStats", "i", _i); - const node = getHacknetNode(i, "getNodeStats"); - const hasUpgraded = hasHacknetServers(player); - const res: any = { - name: node instanceof HacknetServer ? node.hostname : node.name, - level: node.level, - ram: node instanceof HacknetServer ? node.maxRam : node.ram, - ramUsed: node instanceof HacknetServer ? node.ramUsed : undefined, - cores: node.cores, - production: node instanceof HacknetServer ? node.hashRate : node.moneyGainRatePerSecond, - timeOnline: node.onlineTimeSeconds, - totalProduction: node instanceof HacknetServer ? node.totalHashesGenerated : node.totalMoneyGenerated, - }; + getNodeStats: + (ctx: NetscriptContext) => + (_i: unknown): NodeStats => { + const i = ctx.helper.number("i", _i); + const node = getHacknetNode(ctx, i); + const hasUpgraded = hasHacknetServers(player); + const res: any = { + name: node instanceof HacknetServer ? node.hostname : node.name, + level: node.level, + ram: node instanceof HacknetServer ? node.maxRam : node.ram, + ramUsed: node instanceof HacknetServer ? node.ramUsed : undefined, + cores: node.cores, + production: node instanceof HacknetServer ? node.hashRate : node.moneyGainRatePerSecond, + timeOnline: node.onlineTimeSeconds, + totalProduction: node instanceof HacknetServer ? node.totalHashesGenerated : node.totalMoneyGenerated, + }; - if (hasUpgraded && node instanceof HacknetServer) { - res.cache = node.cache; - res.hashCapacity = node.hashCapacity; - } + if (hasUpgraded && node instanceof HacknetServer) { + res.cache = node.cache; + res.hashCapacity = node.hashCapacity; + } - return res; - }, - upgradeLevel: function (_i: unknown, _n: unknown = 1): boolean { - const i = helper.number("upgradeLevel", "i", _i); - const n = helper.number("upgradeLevel", "n", _n); - const node = getHacknetNode(i, "upgradeLevel"); - return purchaseLevelUpgrade(player, node, n); - }, - upgradeRam: function (_i: unknown, _n: unknown = 1): boolean { - const i = helper.number("upgradeRam", "i", _i); - const n = helper.number("upgradeRam", "n", _n); - const node = getHacknetNode(i, "upgradeRam"); - return purchaseRamUpgrade(player, node, n); - }, - upgradeCore: function (_i: unknown, _n: unknown = 1): boolean { - const i = helper.number("upgradeCore", "i", _i); - const n = helper.number("upgradeCore", "n", _n); - const node = getHacknetNode(i, "upgradeCore"); - return purchaseCoreUpgrade(player, node, n); - }, - upgradeCache: function (_i: unknown, _n: unknown = 1): boolean { - const i = helper.number("upgradeCache", "i", _i); - const n = helper.number("upgradeCache", "n", _n); - if (!hasHacknetServers(player)) { - return false; - } - const node = getHacknetNode(i, "upgradeCache"); - if (!(node instanceof HacknetServer)) { - workerScript.log("hacknet.upgradeCache", () => "Can only be called on hacknet servers"); - return false; - } - const res = purchaseCacheUpgrade(player, node, n); - if (res) { - updateHashManagerCapacity(player); - } - return res; - }, - getLevelUpgradeCost: function (_i: unknown, _n: unknown = 1): number { - const i = helper.number("getLevelUpgradeCost", "i", _i); - const n = helper.number("getLevelUpgradeCost", "n", _n); - const node = getHacknetNode(i, "upgradeLevel"); - return node.calculateLevelUpgradeCost(n, player.hacknet_node_level_cost_mult); - }, - getRamUpgradeCost: function (_i: unknown, _n: unknown = 1): number { - const i = helper.number("getRamUpgradeCost", "i", _i); - const n = helper.number("getRamUpgradeCost", "n", _n); - const node = getHacknetNode(i, "upgradeRam"); - return node.calculateRamUpgradeCost(n, player.hacknet_node_ram_cost_mult); - }, - getCoreUpgradeCost: function (_i: unknown, _n: unknown = 1): number { - const i = helper.number("getCoreUpgradeCost", "i", _i); - const n = helper.number("getCoreUpgradeCost", "n", _n); - const node = getHacknetNode(i, "upgradeCore"); - return node.calculateCoreUpgradeCost(n, player.hacknet_node_core_cost_mult); - }, - getCacheUpgradeCost: function (_i: unknown, _n: unknown = 1): number { - const i = helper.number("getCacheUpgradeCost", "i", _i); - const n = helper.number("getCacheUpgradeCost", "n", _n); - if (!hasHacknetServers(player)) { - return Infinity; - } - const node = getHacknetNode(i, "upgradeCache"); - if (!(node instanceof HacknetServer)) { - workerScript.log("hacknet.getCacheUpgradeCost", () => "Can only be called on hacknet servers"); - return -1; - } - return node.calculateCacheUpgradeCost(n); - }, - numHashes: function (): number { + return res; + }, + upgradeLevel: + (ctx: NetscriptContext) => + (_i: unknown, _n: unknown = 1): boolean => { + const i = ctx.helper.number("i", _i); + const n = ctx.helper.number("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 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 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); + 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"); + return false; + } + const res = purchaseCacheUpgrade(player, node, n); + if (res) { + updateHashManagerCapacity(player); + } + return res; + }, + getLevelUpgradeCost: + (ctx: NetscriptContext) => + (_i: unknown, _n: unknown = 1): number => { + const i = ctx.helper.number("i", _i); + const n = ctx.helper.number("n", _n); + const node = getHacknetNode(ctx, i); + return node.calculateLevelUpgradeCost(n, player.hacknet_node_level_cost_mult); + }, + getRamUpgradeCost: + (ctx: NetscriptContext) => + (_i: unknown, _n: unknown = 1): number => { + const i = ctx.helper.number("i", _i); + const n = ctx.helper.number("n", _n); + const node = getHacknetNode(ctx, i); + return node.calculateRamUpgradeCost(n, player.hacknet_node_ram_cost_mult); + }, + getCoreUpgradeCost: + (ctx: NetscriptContext) => + (_i: unknown, _n: unknown = 1): number => { + const i = ctx.helper.number("i", _i); + const n = ctx.helper.number("n", _n); + const node = getHacknetNode(ctx, i); + return node.calculateCoreUpgradeCost(n, player.hacknet_node_core_cost_mult); + }, + getCacheUpgradeCost: + (ctx: NetscriptContext) => + (_i: unknown, _n: unknown = 1): number => { + const i = ctx.helper.number("i", _i); + const n = ctx.helper.number("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"); + return -1; + } + return node.calculateCacheUpgradeCost(n); + }, + numHashes: () => (): number => { if (!hasHacknetServers(player)) { return 0; } return player.hashManager.hashes; }, - hashCapacity: function (): number { + hashCapacity: () => (): number => { if (!hasHacknetServers(player)) { return 0; } return player.hashManager.capacity; }, - hashCost: function (_upgName: unknown): number { - const upgName = helper.string("hashCost", "upgName", _upgName); - if (!hasHacknetServers(player)) { - return Infinity; - } + hashCost: + (ctx: NetscriptContext) => + (_upgName: unknown): number => { + const upgName = ctx.helper.string("upgName", _upgName); + if (!hasHacknetServers(player)) { + return Infinity; + } - return player.hashManager.getUpgradeCost(upgName); - }, - spendHashes: function (_upgName: unknown, _upgTarget: unknown = ""): boolean { - const upgName = helper.string("spendHashes", "upgName", _upgName); - const upgTarget = helper.string("spendHashes", "upgTarget", _upgTarget); - if (!hasHacknetServers(player)) { - return false; - } - return purchaseHashUpgrade(player, upgName, upgTarget); - }, - getHashUpgrades: function (): string[] { + return player.hashManager.getUpgradeCost(upgName); + }, + spendHashes: + (ctx: NetscriptContext) => + (_upgName: unknown, _upgTarget: unknown = ""): boolean => { + const upgName = ctx.helper.string("upgName", _upgName); + const upgTarget = ctx.helper.string("upgTarget", _upgTarget); + if (!hasHacknetServers(player)) { + return false; + } + return purchaseHashUpgrade(player, upgName, upgTarget); + }, + getHashUpgrades: () => (): string[] => { if (!hasHacknetServers(player)) { return []; } return Object.values(HashUpgrades).map((upgrade: HashUpgrade) => upgrade.name); }, - getHashUpgradeLevel: function (_upgName: unknown): number { - const upgName = helper.string("getHashUpgradeLevel", "upgName", _upgName); - const level = player.hashManager.upgrades[upgName]; - if (level === undefined) { - throw helper.makeRuntimeErrorMsg("hacknet.hashUpgradeLevel", `Invalid Hash Upgrade: ${upgName}`); - } - return level; - }, - getStudyMult: function (): number { + getHashUpgradeLevel: + (ctx: NetscriptContext) => + (_upgName: unknown): number => { + const upgName = ctx.helper.string("upgName", _upgName); + const level = player.hashManager.upgrades[upgName]; + if (level === undefined) { + throw ctx.makeRuntimeErrorMsg(`Invalid Hash Upgrade: ${upgName}`); + } + return level; + }, + getStudyMult: () => (): number => { if (!hasHacknetServers(player)) { return 1; } return player.hashManager.getStudyMult(); }, - getTrainingMult: function (): number { + getTrainingMult: () => (): number => { if (!hasHacknetServers(player)) { return 1; } diff --git a/src/NetscriptFunctions/Sleeve.ts b/src/NetscriptFunctions/Sleeve.ts index 771c588dc..e6beb8064 100644 --- a/src/NetscriptFunctions/Sleeve.ts +++ b/src/NetscriptFunctions/Sleeve.ts @@ -1,9 +1,6 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { IPlayer } from "../PersonObjects/IPlayer"; -import { getRamCost } from "../Netscript/RamCostGenerator"; import { FactionWorkType } from "../Faction/FactionWorkTypeEnum"; import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum"; -import { WorkerScript } from "../Netscript/WorkerScript"; import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers"; import { StaticAugmentations } from "../Augmentation/StaticAugmentations"; import { CityName } from "../Locations/data/CityNames"; @@ -17,22 +14,22 @@ import { SleeveTask, } from "../ScriptEditor/NetscriptDefinitions"; import { checkEnum } from "../utils/helpers/checkEnum"; +import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; -export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): ISleeve { - const checkSleeveAPIAccess = function (func: string): void { +export function NetscriptSleeve(player: IPlayer): InternalAPI { + const checkSleeveAPIAccess = function (ctx: NetscriptContext): void { if (player.bitNodeN !== 10 && !player.sourceFileLvl(10)) { - throw helper.makeRuntimeErrorMsg( - `sleeve.${func}`, + throw ctx.makeRuntimeErrorMsg( "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", ); } }; - const checkSleeveNumber = function (func: string, sleeveNumber: number): void { + const checkSleeveNumber = function (ctx: NetscriptContext, sleeveNumber: number): void { if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) { const msg = `Invalid sleeve number: ${sleeveNumber}`; - workerScript.log(func, () => msg); - throw helper.makeRuntimeErrorMsg(`sleeve.${func}`, msg); + ctx.log(() => msg); + throw ctx.makeRuntimeErrorMsg(msg); } }; @@ -50,265 +47,268 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel }; }; - const updateRam = (funcName: string): void => - helper.updateDynamicRam(funcName, getRamCost(player, "sleeve", funcName)); - return { - getNumSleeves: function (): number { - updateRam("getNumSleeves"); - checkSleeveAPIAccess("getNumSleeves"); + getNumSleeves: (ctx: NetscriptContext) => (): number => { + checkSleeveAPIAccess(ctx); return player.sleeves.length; }, - setToShockRecovery: function (_sleeveNumber: unknown): boolean { - updateRam("setToShockRecovery"); - const sleeveNumber = helper.number("setToShockRecovery", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("setToShockRecovery"); - checkSleeveNumber("setToShockRecovery", sleeveNumber); - return player.sleeves[sleeveNumber].shockRecovery(player); - }, - setToSynchronize: function (_sleeveNumber: unknown): boolean { - updateRam("setToSynchronize"); - const sleeveNumber = helper.number("setToSynchronize", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("setToSynchronize"); - checkSleeveNumber("setToSynchronize", sleeveNumber); - return player.sleeves[sleeveNumber].synchronize(player); - }, - setToCommitCrime: function (_sleeveNumber: unknown, _crimeRoughName: unknown): boolean { - updateRam("setToCommitCrime"); - const sleeveNumber = helper.number("setToCommitCrime", "sleeveNumber", _sleeveNumber); - const crimeRoughName = helper.string("setToCommitCrime", "crimeName", _crimeRoughName); - checkSleeveAPIAccess("setToCommitCrime"); - checkSleeveNumber("setToCommitCrime", sleeveNumber); - const crime = findCrime(crimeRoughName); - if (crime === null) { - return false; - } - return player.sleeves[sleeveNumber].commitCrime(player, crime.name); - }, - setToUniversityCourse: function (_sleeveNumber: unknown, _universityName: unknown, _className: unknown): boolean { - updateRam("setToUniversityCourse"); - const sleeveNumber = helper.number("setToUniversityCourse", "sleeveNumber", _sleeveNumber); - const universityName = helper.string("setToUniversityCourse", "universityName", _universityName); - const className = helper.string("setToUniversityCourse", "className", _className); - checkSleeveAPIAccess("setToUniversityCourse"); - checkSleeveNumber("setToUniversityCourse", sleeveNumber); - return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className); - }, - travel: function (_sleeveNumber: unknown, _cityName: unknown): boolean { - updateRam("travel"); - const sleeveNumber = helper.number("travel", "sleeveNumber", _sleeveNumber); - const cityName = helper.string("travel", "cityName", _cityName); - checkSleeveAPIAccess("travel"); - checkSleeveNumber("travel", sleeveNumber); - if (checkEnum(CityName, cityName)) { - return player.sleeves[sleeveNumber].travel(player, cityName); - } else { - throw helper.makeRuntimeErrorMsg("sleeve.setToCompanyWork", `Invalid city name: '${cityName}'.`); - } - }, - setToCompanyWork: function (_sleeveNumber: unknown, acompanyName: unknown): boolean { - updateRam("setToCompanyWork"); - const sleeveNumber = helper.number("setToCompanyWork", "sleeveNumber", _sleeveNumber); - const companyName = helper.string("setToCompanyWork", "companyName", acompanyName); - checkSleeveAPIAccess("setToCompanyWork"); - checkSleeveNumber("setToCompanyWork", sleeveNumber); - - // Cannot work at the same company that another sleeve is working at - for (let i = 0; i < player.sleeves.length; ++i) { - if (i === sleeveNumber) { - continue; + setToShockRecovery: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): boolean => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + return player.sleeves[sleeveNumber].shockRecovery(player); + }, + setToSynchronize: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): boolean => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + return player.sleeves[sleeveNumber].synchronize(player); + }, + setToCommitCrime: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown, _crimeRoughName: unknown): boolean => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + const crimeRoughName = ctx.helper.string("crimeName", _crimeRoughName); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + const crime = findCrime(crimeRoughName); + if (crime === null) { + return false; } - const other = player.sleeves[i]; - if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) { - throw helper.makeRuntimeErrorMsg( - "sleeve.setToCompanyWork", - `Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`, + return player.sleeves[sleeveNumber].commitCrime(player, crime.name); + }, + 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); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className); + }, + travel: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown, _cityName: unknown): boolean => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + const cityName = ctx.helper.string("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}'.`); + } + }, + setToCompanyWork: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown, acompanyName: unknown): boolean => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + const companyName = ctx.helper.string("companyName", acompanyName); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + + // Cannot work at the same company that another sleeve is working at + for (let i = 0; i < player.sleeves.length; ++i) { + if (i === sleeveNumber) { + continue; + } + const other = player.sleeves[i]; + if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) { + throw ctx.makeRuntimeErrorMsg( + `Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`, + ); + } + } + + return player.sleeves[sleeveNumber].workForCompany(player, companyName); + }, + 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); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + + // Cannot work at the same faction that another sleeve is working at + for (let i = 0; i < player.sleeves.length; ++i) { + if (i === sleeveNumber) { + continue; + } + const other = player.sleeves[i]; + if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) { + throw ctx.makeRuntimeErrorMsg( + `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( + `Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`, ); } - } - return player.sleeves[sleeveNumber].workForCompany(player, companyName); - }, - setToFactionWork: function ( - _sleeveNumber: unknown, - _factionName: unknown, - _workType: unknown, - ): boolean | undefined { - updateRam("setToFactionWork"); - const sleeveNumber = helper.number("setToFactionWork", "sleeveNumber", _sleeveNumber); - const factionName = helper.string("setToFactionWork", "factionName", _factionName); - const workType = helper.string("setToFactionWork", "workType", _workType); - checkSleeveAPIAccess("setToFactionWork"); - checkSleeveNumber("setToFactionWork", sleeveNumber); + return player.sleeves[sleeveNumber].workForFaction(player, factionName, workType); + }, + 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); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); - // Cannot work at the same faction that another sleeve is working at - for (let i = 0; i < player.sleeves.length; ++i) { - if (i === sleeveNumber) { - continue; + return player.sleeves[sleeveNumber].workoutAtGym(player, gymName, stat); + }, + getSleeveStats: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): SleeveSkills => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + return getSleeveStats(sleeveNumber); + }, + getTask: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): SleeveTask => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + + const sl = player.sleeves[sleeveNumber]; + return { + task: SleeveTaskType[sl.currentTask], + crime: sl.crimeType, + location: sl.currentTaskLocation, + gymStatType: sl.gymStatType, + factionWorkType: FactionWorkType[sl.factionWorkType], + }; + }, + getInformation: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): SleeveInformation => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + + const sl = player.sleeves[sleeveNumber]; + return { + tor: false, + city: sl.city, + hp: sl.hp, + jobs: Object.keys(player.jobs), // technically sleeves have the same jobs as the player. + jobTitle: Object.values(player.jobs), + maxHp: sl.max_hp, + + mult: { + agility: sl.agility_mult, + agilityExp: sl.agility_exp_mult, + charisma: sl.charisma_mult, + charismaExp: sl.charisma_exp_mult, + companyRep: sl.company_rep_mult, + crimeMoney: sl.crime_money_mult, + crimeSuccess: sl.crime_success_mult, + defense: sl.defense_mult, + defenseExp: sl.defense_exp_mult, + dexterity: sl.dexterity_mult, + dexterityExp: sl.dexterity_exp_mult, + factionRep: sl.faction_rep_mult, + hacking: sl.hacking_mult, + hackingExp: sl.hacking_exp_mult, + strength: sl.strength_mult, + strengthExp: sl.strength_exp_mult, + workMoney: sl.work_money_mult, + }, + + timeWorked: sl.currentTaskTime, + earningsForSleeves: { + workHackExpGain: sl.earningsForSleeves.hack, + workStrExpGain: sl.earningsForSleeves.str, + workDefExpGain: sl.earningsForSleeves.def, + workDexExpGain: sl.earningsForSleeves.dex, + workAgiExpGain: sl.earningsForSleeves.agi, + workChaExpGain: sl.earningsForSleeves.cha, + workMoneyGain: sl.earningsForSleeves.money, + }, + earningsForPlayer: { + workHackExpGain: sl.earningsForPlayer.hack, + workStrExpGain: sl.earningsForPlayer.str, + workDefExpGain: sl.earningsForPlayer.def, + workDexExpGain: sl.earningsForPlayer.dex, + workAgiExpGain: sl.earningsForPlayer.agi, + workChaExpGain: sl.earningsForPlayer.cha, + workMoneyGain: sl.earningsForPlayer.money, + }, + earningsForTask: { + workHackExpGain: sl.earningsForTask.hack, + workStrExpGain: sl.earningsForTask.str, + workDefExpGain: sl.earningsForTask.def, + workDexExpGain: sl.earningsForTask.dex, + workAgiExpGain: sl.earningsForTask.agi, + workChaExpGain: sl.earningsForTask.cha, + workMoneyGain: sl.earningsForTask.money, + }, + workRepGain: sl.getRepGain(player), + }; + }, + getSleeveAugmentations: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): string[] => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + + const augs = []; + for (let i = 0; i < player.sleeves[sleeveNumber].augmentations.length; i++) { + augs.push(player.sleeves[sleeveNumber].augmentations[i].name); } - const other = player.sleeves[i]; - if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) { - throw helper.makeRuntimeErrorMsg( - "sleeve.setToFactionWork", - `Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`, - ); + return augs; + }, + getSleevePurchasableAugs: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown): AugmentPair[] => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); + + const purchasableAugs = findSleevePurchasableAugs(player.sleeves[sleeveNumber], player); + const augs = []; + for (let i = 0; i < purchasableAugs.length; i++) { + const aug = purchasableAugs[i]; + augs.push({ + name: aug.name, + cost: aug.baseCost, + }); } - } - if (player.gang && player.gang.facName == factionName) { - throw helper.makeRuntimeErrorMsg( - "sleeve.setToFactionWork", - `Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`, - ); - } + return augs; + }, + purchaseSleeveAug: + (ctx: NetscriptContext) => + (_sleeveNumber: unknown, _augName: unknown): boolean => { + const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber); + const augName = ctx.helper.string("augName", _augName); + checkSleeveAPIAccess(ctx); + checkSleeveNumber(ctx, sleeveNumber); - return player.sleeves[sleeveNumber].workForFaction(player, factionName, workType); - }, - setToGymWorkout: function (_sleeveNumber: unknown, _gymName: unknown, _stat: unknown): boolean { - updateRam("setToGymWorkout"); - const sleeveNumber = helper.number("setToGymWorkout", "sleeveNumber", _sleeveNumber); - const gymName = helper.string("setToGymWorkout", "gymName", _gymName); - const stat = helper.string("setToGymWorkout", "stat", _stat); - checkSleeveAPIAccess("setToGymWorkout"); - checkSleeveNumber("setToGymWorkout", sleeveNumber); + if (getSleeveStats(sleeveNumber).shock > 0) { + throw ctx.makeRuntimeErrorMsg(`Sleeve shock too high: Sleeve ${sleeveNumber}`); + } - return player.sleeves[sleeveNumber].workoutAtGym(player, gymName, stat); - }, - getSleeveStats: function (_sleeveNumber: unknown): SleeveSkills { - updateRam("getSleeveStats"); - const sleeveNumber = helper.number("getSleeveStats", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("getSleeveStats"); - checkSleeveNumber("getSleeveStats", sleeveNumber); - return getSleeveStats(sleeveNumber); - }, - getTask: function (_sleeveNumber: unknown): SleeveTask { - updateRam("getTask"); - const sleeveNumber = helper.number("getTask", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("getTask"); - checkSleeveNumber("getTask", sleeveNumber); + const aug = StaticAugmentations[augName]; + if (!aug) { + throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`); + } - const sl = player.sleeves[sleeveNumber]; - return { - task: SleeveTaskType[sl.currentTask], - crime: sl.crimeType, - location: sl.currentTaskLocation, - gymStatType: sl.gymStatType, - factionWorkType: FactionWorkType[sl.factionWorkType], - }; - }, - getInformation: function (_sleeveNumber: unknown): SleeveInformation { - updateRam("getInformation"); - const sleeveNumber = helper.number("getInformation", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("getInformation"); - checkSleeveNumber("getInformation", sleeveNumber); - - const sl = player.sleeves[sleeveNumber]; - return { - tor: false, - city: sl.city, - hp: sl.hp, - jobs: Object.keys(player.jobs), // technically sleeves have the same jobs as the player. - jobTitle: Object.values(player.jobs), - maxHp: sl.max_hp, - - mult: { - agility: sl.agility_mult, - agilityExp: sl.agility_exp_mult, - charisma: sl.charisma_mult, - charismaExp: sl.charisma_exp_mult, - companyRep: sl.company_rep_mult, - crimeMoney: sl.crime_money_mult, - crimeSuccess: sl.crime_success_mult, - defense: sl.defense_mult, - defenseExp: sl.defense_exp_mult, - dexterity: sl.dexterity_mult, - dexterityExp: sl.dexterity_exp_mult, - factionRep: sl.faction_rep_mult, - hacking: sl.hacking_mult, - hackingExp: sl.hacking_exp_mult, - strength: sl.strength_mult, - strengthExp: sl.strength_exp_mult, - workMoney: sl.work_money_mult, - }, - - timeWorked: sl.currentTaskTime, - earningsForSleeves: { - workHackExpGain: sl.earningsForSleeves.hack, - workStrExpGain: sl.earningsForSleeves.str, - workDefExpGain: sl.earningsForSleeves.def, - workDexExpGain: sl.earningsForSleeves.dex, - workAgiExpGain: sl.earningsForSleeves.agi, - workChaExpGain: sl.earningsForSleeves.cha, - workMoneyGain: sl.earningsForSleeves.money, - }, - earningsForPlayer: { - workHackExpGain: sl.earningsForPlayer.hack, - workStrExpGain: sl.earningsForPlayer.str, - workDefExpGain: sl.earningsForPlayer.def, - workDexExpGain: sl.earningsForPlayer.dex, - workAgiExpGain: sl.earningsForPlayer.agi, - workChaExpGain: sl.earningsForPlayer.cha, - workMoneyGain: sl.earningsForPlayer.money, - }, - earningsForTask: { - workHackExpGain: sl.earningsForTask.hack, - workStrExpGain: sl.earningsForTask.str, - workDefExpGain: sl.earningsForTask.def, - workDexExpGain: sl.earningsForTask.dex, - workAgiExpGain: sl.earningsForTask.agi, - workChaExpGain: sl.earningsForTask.cha, - workMoneyGain: sl.earningsForTask.money, - }, - workRepGain: sl.getRepGain(player), - }; - }, - getSleeveAugmentations: function (_sleeveNumber: unknown): string[] { - updateRam("getSleeveAugmentations"); - const sleeveNumber = helper.number("getSleeveAugmentations", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("getSleeveAugmentations"); - checkSleeveNumber("getSleeveAugmentations", sleeveNumber); - - const augs = []; - for (let i = 0; i < player.sleeves[sleeveNumber].augmentations.length; i++) { - augs.push(player.sleeves[sleeveNumber].augmentations[i].name); - } - return augs; - }, - getSleevePurchasableAugs: function (_sleeveNumber: unknown): AugmentPair[] { - updateRam("getSleevePurchasableAugs"); - const sleeveNumber = helper.number("getSleevePurchasableAugs", "sleeveNumber", _sleeveNumber); - checkSleeveAPIAccess("getSleevePurchasableAugs"); - checkSleeveNumber("getSleevePurchasableAugs", sleeveNumber); - - const purchasableAugs = findSleevePurchasableAugs(player.sleeves[sleeveNumber], player); - const augs = []; - for (let i = 0; i < purchasableAugs.length; i++) { - const aug = purchasableAugs[i]; - augs.push({ - name: aug.name, - cost: aug.baseCost, - }); - } - - return augs; - }, - purchaseSleeveAug: function (_sleeveNumber: unknown, _augName: unknown): boolean { - updateRam("purchaseSleeveAug"); - const sleeveNumber = helper.number("purchaseSleeveAug", "sleeveNumber", _sleeveNumber); - const augName = helper.string("purchaseSleeveAug", "augName", _augName); - checkSleeveAPIAccess("purchaseSleeveAug"); - checkSleeveNumber("purchaseSleeveAug", sleeveNumber); - - if (getSleeveStats(sleeveNumber).shock > 0) { - throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Sleeve shock too high: Sleeve ${sleeveNumber}`); - } - - const aug = StaticAugmentations[augName]; - if (!aug) { - throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Invalid aug: ${augName}`); - } - - return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug); - }, + return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug); + }, }; } diff --git a/src/NetscriptFunctions/StockMarket.ts b/src/NetscriptFunctions/StockMarket.ts index 86f71efa7..ad0fb3941 100644 --- a/src/NetscriptFunctions/StockMarket.ts +++ b/src/NetscriptFunctions/StockMarket.ts @@ -1,7 +1,5 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; -import { getRamCost } from "../Netscript/RamCostGenerator"; import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling"; import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder, initStockMarketFn } from "../StockMarket/StockMarket"; import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers"; @@ -16,301 +14,286 @@ import { } from "../StockMarket/StockMarketCosts"; import { Stock } from "../StockMarket/Stock"; import { TIX } from "../ScriptEditor/NetscriptDefinitions"; +import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; -export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): TIX { +export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript): InternalAPI { /** * Checks if the player has TIX API access. Throws an error if the player does not */ - const checkTixApiAccess = function (callingFn: string): void { + const checkTixApiAccess = function (ctx: NetscriptContext): void { if (!player.hasWseAccount) { - throw helper.makeRuntimeErrorMsg(callingFn, `You don't have WSE Access! Cannot use ${callingFn}()`); + throw ctx.makeRuntimeErrorMsg(`You don't have WSE Access! Cannot use ${ctx.function}()`); } if (!player.hasTixApiAccess) { - throw helper.makeRuntimeErrorMsg(callingFn, `You don't have TIX API Access! Cannot use ${callingFn}()`); + throw ctx.makeRuntimeErrorMsg(`You don't have TIX API Access! Cannot use ${ctx.function}()`); } }; - const getStockFromSymbol = function (symbol: string, callingFn: string): Stock { + const getStockFromSymbol = function (ctx: NetscriptContext, symbol: string): Stock { const stock = SymbolToStockMap[symbol]; if (stock == null) { - throw helper.makeRuntimeErrorMsg(callingFn, `Invalid stock symbol: '${symbol}'`); + throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: '${symbol}'`); } return stock; }; - const updateRam = (funcName: string): void => - helper.updateDynamicRam(funcName, getRamCost(player, "stock", funcName)); - return { - getSymbols: function (): string[] { - updateRam("getSymbols"); - checkTixApiAccess("getSymbols"); + getSymbols: (ctx: NetscriptContext) => (): string[] => { + checkTixApiAccess(ctx); return Object.values(StockSymbols); }, - getPrice: function (_symbol: unknown): number { - updateRam("getPrice"); - const symbol = helper.string("getPrice", "symbol", _symbol); - checkTixApiAccess("getPrice"); - const stock = getStockFromSymbol(symbol, "getPrice"); + getPrice: + (ctx: NetscriptContext) => + (_symbol: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); - return stock.price; - }, - getAskPrice: function (_symbol: unknown): number { - updateRam("getAskPrice"); - const symbol = helper.string("getAskPrice", "symbol", _symbol); - checkTixApiAccess("getAskPrice"); - const stock = getStockFromSymbol(symbol, "getAskPrice"); + return stock.price; + }, + getAskPrice: + (ctx: NetscriptContext) => + (_symbol: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); - return stock.getAskPrice(); - }, - getBidPrice: function (_symbol: unknown): number { - updateRam("getBidPrice"); - const symbol = helper.string("getBidPrice", "symbol", _symbol); - checkTixApiAccess("getBidPrice"); - const stock = getStockFromSymbol(symbol, "getBidPrice"); + return stock.getAskPrice(); + }, + getBidPrice: + (ctx: NetscriptContext) => + (_symbol: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); - return stock.getBidPrice(); - }, - getPosition: function (_symbol: unknown): [number, number, number, number] { - updateRam("getPosition"); - const symbol = helper.string("getPosition", "symbol", _symbol); - checkTixApiAccess("getPosition"); - const stock = SymbolToStockMap[symbol]; - if (stock == null) { - throw helper.makeRuntimeErrorMsg("getPosition", `Invalid stock symbol: ${symbol}`); - } - return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx]; - }, - getMaxShares: function (_symbol: unknown): number { - updateRam("getMaxShares"); - const symbol = helper.string("getMaxShares", "symbol", _symbol); - checkTixApiAccess("getMaxShares"); - const stock = getStockFromSymbol(symbol, "getMaxShares"); - - return stock.maxShares; - }, - getPurchaseCost: function (_symbol: unknown, _shares: unknown, _posType: unknown): number { - updateRam("getPurchaseCost"); - const symbol = helper.string("getPurchaseCost", "symbol", _symbol); - let shares = helper.number("getPurchaseCost", "shares", _shares); - const posType = helper.string("getPurchaseCost", "posType", _posType); - checkTixApiAccess("getPurchaseCost"); - const stock = getStockFromSymbol(symbol, "getPurchaseCost"); - shares = Math.round(shares); - - let pos; - const sanitizedPosType = posType.toLowerCase(); - if (sanitizedPosType.includes("l")) { - pos = PositionTypes.Long; - } else if (sanitizedPosType.includes("s")) { - pos = PositionTypes.Short; - } else { - return Infinity; - } - - const res = getBuyTransactionCost(stock, shares, pos); - if (res == null) { - return Infinity; - } - - return res; - }, - getSaleGain: function (_symbol: unknown, _shares: unknown, _posType: unknown): number { - updateRam("getSaleGain"); - const symbol = helper.string("getSaleGain", "symbol", _symbol); - let shares = helper.number("getSaleGain", "shares", _shares); - const posType = helper.string("getSaleGain", "posType", _posType); - checkTixApiAccess("getSaleGain"); - const stock = getStockFromSymbol(symbol, "getSaleGain"); - shares = Math.round(shares); - - let pos; - const sanitizedPosType = posType.toLowerCase(); - if (sanitizedPosType.includes("l")) { - pos = PositionTypes.Long; - } else if (sanitizedPosType.includes("s")) { - pos = PositionTypes.Short; - } else { - return 0; - } - - const res = getSellTransactionGain(stock, shares, pos); - if (res == null) { - return 0; - } - - return res; - }, - buy: function (_symbol: unknown, _shares: unknown): number { - updateRam("buy"); - const symbol = helper.string("buy", "symbol", _symbol); - const shares = helper.number("buy", "shares", _shares); - checkTixApiAccess("buy"); - const stock = getStockFromSymbol(symbol, "buy"); - const res = buyStock(stock, shares, workerScript, {}); - return res ? stock.getAskPrice() : 0; - }, - sell: function (_symbol: unknown, _shares: unknown): number { - updateRam("sell"); - const symbol = helper.string("sell", "symbol", _symbol); - const shares = helper.number("sell", "shares", _shares); - checkTixApiAccess("sell"); - const stock = getStockFromSymbol(symbol, "sell"); - const res = sellStock(stock, shares, workerScript, {}); - - return res ? stock.getBidPrice() : 0; - }, - short: function (_symbol: unknown, _shares: unknown): number { - updateRam("short"); - const symbol = helper.string("short", "symbol", _symbol); - const shares = helper.number("short", "shares", _shares); - checkTixApiAccess("short"); - if (player.bitNodeN !== 8) { - if (player.sourceFileLvl(8) <= 1) { - throw helper.makeRuntimeErrorMsg( - "short", - "You must either be in BitNode-8 or you must have Source-File 8 Level 2.", - ); + return stock.getBidPrice(); + }, + getPosition: + (ctx: NetscriptContext) => + (_symbol: unknown): [number, number, number, number] => { + const symbol = ctx.helper.string("symbol", _symbol); + checkTixApiAccess(ctx); + const stock = SymbolToStockMap[symbol]; + if (stock == null) { + throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: ${symbol}`); } - } - const stock = getStockFromSymbol(symbol, "short"); - const res = shortStock(stock, shares, workerScript, {}); + return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx]; + }, + getMaxShares: + (ctx: NetscriptContext) => + (_symbol: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); - return res ? stock.getBidPrice() : 0; - }, - sellShort: function (_symbol: unknown, _shares: unknown): number { - updateRam("sellShort"); - const symbol = helper.string("sellShort", "symbol", _symbol); - const shares = helper.number("sellShort", "shares", _shares); - checkTixApiAccess("sellShort"); - if (player.bitNodeN !== 8) { - if (player.sourceFileLvl(8) <= 1) { - throw helper.makeRuntimeErrorMsg( - "sellShort", - "You must either be in BitNode-8 or you must have Source-File 8 Level 2.", - ); + return stock.maxShares; + }, + 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); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); + shares = Math.round(shares); + + let pos; + const sanitizedPosType = posType.toLowerCase(); + if (sanitizedPosType.includes("l")) { + pos = PositionTypes.Long; + } else if (sanitizedPosType.includes("s")) { + pos = PositionTypes.Short; + } else { + return Infinity; } - } - const stock = getStockFromSymbol(symbol, "sellShort"); - const res = sellShort(stock, shares, workerScript, {}); - return res ? stock.getAskPrice() : 0; - }, - placeOrder: function (_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean { - updateRam("placeOrder"); - const symbol = helper.string("placeOrder", "symbol", _symbol); - const shares = helper.number("placeOrder", "shares", _shares); - const price = helper.number("placeOrder", "price", _price); - const type = helper.string("placeOrder", "type", _type); - const pos = helper.string("placeOrder", "pos", _pos); - checkTixApiAccess("placeOrder"); + const res = getBuyTransactionCost(stock, shares, pos); + if (res == null) { + return Infinity; + } + + return res; + }, + 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); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); + shares = Math.round(shares); + + let pos; + const sanitizedPosType = posType.toLowerCase(); + if (sanitizedPosType.includes("l")) { + pos = PositionTypes.Long; + } else if (sanitizedPosType.includes("s")) { + pos = PositionTypes.Short; + } else { + return 0; + } + + const res = getSellTransactionGain(stock, shares, pos); + if (res == null) { + return 0; + } + + return res; + }, + buy: + (ctx: NetscriptContext) => + (_symbol: unknown, _shares: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + const shares = ctx.helper.number("shares", _shares); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); + const res = buyStock(stock, shares, workerScript, {}); + return res ? stock.getAskPrice() : 0; + }, + sell: + (ctx: NetscriptContext) => + (_symbol: unknown, _shares: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + const shares = ctx.helper.number("shares", _shares); + checkTixApiAccess(ctx); + const stock = getStockFromSymbol(ctx, symbol); + const res = sellStock(stock, shares, workerScript, {}); + + return res ? stock.getBidPrice() : 0; + }, + short: + (ctx: NetscriptContext) => + (_symbol: unknown, _shares: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + const shares = ctx.helper.number("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."); + } + } + const stock = getStockFromSymbol(ctx, symbol); + const res = shortStock(stock, shares, 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); + 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."); + } + } + const stock = getStockFromSymbol(ctx, symbol); + const res = sellShort(stock, shares, 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); + 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."); + } + } + const stock = getStockFromSymbol(ctx, symbol); + + let orderType; + let orderPos; + const ltype = type.toLowerCase(); + if (ltype.includes("limit") && ltype.includes("buy")) { + orderType = OrderTypes.LimitBuy; + } else if (ltype.includes("limit") && ltype.includes("sell")) { + orderType = OrderTypes.LimitSell; + } else if (ltype.includes("stop") && ltype.includes("buy")) { + orderType = OrderTypes.StopBuy; + } else if (ltype.includes("stop") && ltype.includes("sell")) { + orderType = OrderTypes.StopSell; + } else { + throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`); + } + + const lpos = pos.toLowerCase(); + if (lpos.includes("l")) { + orderPos = PositionTypes.Long; + } else if (lpos.includes("s")) { + orderPos = PositionTypes.Short; + } else { + throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`); + } + + return placeOrder(stock, shares, price, orderType, orderPos, 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); + 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."); + } + } + const stock = getStockFromSymbol(ctx, symbol); + if (isNaN(shares) || isNaN(price)) { + throw ctx.makeRuntimeErrorMsg(`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`); + } + let orderType; + let orderPos; + const ltype = type.toLowerCase(); + if (ltype.includes("limit") && ltype.includes("buy")) { + orderType = OrderTypes.LimitBuy; + } else if (ltype.includes("limit") && ltype.includes("sell")) { + orderType = OrderTypes.LimitSell; + } else if (ltype.includes("stop") && ltype.includes("buy")) { + orderType = OrderTypes.StopBuy; + } else if (ltype.includes("stop") && ltype.includes("sell")) { + orderType = OrderTypes.StopSell; + } else { + throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`); + } + + const lpos = pos.toLowerCase(); + if (lpos.includes("l")) { + orderPos = PositionTypes.Long; + } else if (lpos.includes("s")) { + orderPos = PositionTypes.Short; + } else { + throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`); + } + const params = { + stock: stock, + shares: shares, + price: price, + type: orderType, + pos: orderPos, + }; + return cancelOrder(params, workerScript); + }, + getOrders: (ctx: NetscriptContext) => (): any => { + checkTixApiAccess(ctx); if (player.bitNodeN !== 8) { if (player.sourceFileLvl(8) <= 2) { - throw helper.makeRuntimeErrorMsg( - "placeOrder", - "You must either be in BitNode-8 or you must have Source-File 8 Level 3.", - ); - } - } - const stock = getStockFromSymbol(symbol, "placeOrder"); - - let orderType; - let orderPos; - const ltype = type.toLowerCase(); - if (ltype.includes("limit") && ltype.includes("buy")) { - orderType = OrderTypes.LimitBuy; - } else if (ltype.includes("limit") && ltype.includes("sell")) { - orderType = OrderTypes.LimitSell; - } else if (ltype.includes("stop") && ltype.includes("buy")) { - orderType = OrderTypes.StopBuy; - } else if (ltype.includes("stop") && ltype.includes("sell")) { - orderType = OrderTypes.StopSell; - } else { - throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid order type: ${type}`); - } - - const lpos = pos.toLowerCase(); - if (lpos.includes("l")) { - orderPos = PositionTypes.Long; - } else if (lpos.includes("s")) { - orderPos = PositionTypes.Short; - } else { - throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid position type: ${pos}`); - } - - return placeOrder(stock, shares, price, orderType, orderPos, workerScript); - }, - cancelOrder: function ( - _symbol: unknown, - _shares: unknown, - _price: unknown, - _type: unknown, - _pos: unknown, - ): boolean { - updateRam("cancelOrder"); - const symbol = helper.string("cancelOrder", "symbol", _symbol); - const shares = helper.number("cancelOrder", "shares", _shares); - const price = helper.number("cancelOrder", "price", _price); - const type = helper.string("cancelOrder", "type", _type); - const pos = helper.string("cancelOrder", "pos", _pos); - checkTixApiAccess("cancelOrder"); - if (player.bitNodeN !== 8) { - if (player.sourceFileLvl(8) <= 2) { - throw helper.makeRuntimeErrorMsg( - "cancelOrder", - "You must either be in BitNode-8 or you must have Source-File 8 Level 3.", - ); - } - } - const stock = getStockFromSymbol(symbol, "cancelOrder"); - if (isNaN(shares) || isNaN(price)) { - throw helper.makeRuntimeErrorMsg( - "cancelOrder", - `Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`, - ); - } - let orderType; - let orderPos; - const ltype = type.toLowerCase(); - if (ltype.includes("limit") && ltype.includes("buy")) { - orderType = OrderTypes.LimitBuy; - } else if (ltype.includes("limit") && ltype.includes("sell")) { - orderType = OrderTypes.LimitSell; - } else if (ltype.includes("stop") && ltype.includes("buy")) { - orderType = OrderTypes.StopBuy; - } else if (ltype.includes("stop") && ltype.includes("sell")) { - orderType = OrderTypes.StopSell; - } else { - throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid order type: ${type}`); - } - - const lpos = pos.toLowerCase(); - if (lpos.includes("l")) { - orderPos = PositionTypes.Long; - } else if (lpos.includes("s")) { - orderPos = PositionTypes.Short; - } else { - throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid position type: ${pos}`); - } - const params = { - stock: stock, - shares: shares, - price: price, - type: orderType, - pos: orderPos, - }; - return cancelOrder(params, workerScript); - }, - getOrders: function (): any { - updateRam("getOrders"); - checkTixApiAccess("getOrders"); - if (player.bitNodeN !== 8) { - if (player.sourceFileLvl(8) <= 2) { - throw helper.makeRuntimeErrorMsg( - "getOrders", - "You must either be in BitNode-8 or have Source-File 8 Level 3.", - ); + throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or have Source-File 8 Level 3."); } } @@ -334,103 +317,95 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript return orders; }, - getVolatility: function (_symbol: unknown): number { - updateRam("getVolatility"); - const symbol = helper.string("getVolatility", "symbol", _symbol); - if (!player.has4SDataTixApi) { - throw helper.makeRuntimeErrorMsg("getVolatility", "You don't have 4S Market Data TIX API Access!"); - } - const stock = getStockFromSymbol(symbol, "getVolatility"); + getVolatility: + (ctx: NetscriptContext) => + (_symbol: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + if (!player.has4SDataTixApi) { + throw ctx.makeRuntimeErrorMsg("You don't have 4S Market Data TIX API Access!"); + } + const stock = getStockFromSymbol(ctx, symbol); - return stock.mv / 100; // Convert from percentage to decimal - }, - getForecast: function (_symbol: unknown): number { - updateRam("getForecast"); - const symbol = helper.string("getForecast", "symbol", _symbol); - if (!player.has4SDataTixApi) { - throw helper.makeRuntimeErrorMsg("getForecast", "You don't have 4S Market Data TIX API Access!"); - } - const stock = getStockFromSymbol(symbol, "getForecast"); - - let forecast = 50; - stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag); - return forecast / 100; // Convert from percentage to decimal - }, - purchase4SMarketData: function (): boolean { - updateRam("purchase4SMarketData"); + return stock.mv / 100; // Convert from percentage to decimal + }, + getForecast: + (ctx: NetscriptContext) => + (_symbol: unknown): number => { + const symbol = ctx.helper.string("symbol", _symbol); + if (!player.has4SDataTixApi) { + throw ctx.makeRuntimeErrorMsg("You don't have 4S Market Data TIX API Access!"); + } + const stock = getStockFromSymbol(ctx, symbol); + let forecast = 50; + stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag); + return forecast / 100; // Convert from percentage to decimal + }, + purchase4SMarketData: (ctx: NetscriptContext) => (): boolean => { if (player.has4SData) { - workerScript.log("stock.purchase4SMarketData", () => "Already purchased 4S Market Data."); + ctx.log(() => "Already purchased 4S Market Data."); return true; } if (player.money < getStockMarket4SDataCost()) { - workerScript.log("stock.purchase4SMarketData", () => "Not enough money to purchase 4S Market Data."); + ctx.log(() => "Not enough money to purchase 4S Market Data."); return false; } player.has4SData = true; player.loseMoney(getStockMarket4SDataCost(), "stock"); - workerScript.log("stock.purchase4SMarketData", () => "Purchased 4S Market Data"); + ctx.log(() => "Purchased 4S Market Data"); return true; }, - purchase4SMarketDataTixApi: function (): boolean { - updateRam("purchase4SMarketDataTixApi"); - checkTixApiAccess("purchase4SMarketDataTixApi"); + purchase4SMarketDataTixApi: (ctx: NetscriptContext) => (): boolean => { + checkTixApiAccess(ctx); if (player.has4SDataTixApi) { - workerScript.log("stock.purchase4SMarketDataTixApi", () => "Already purchased 4S Market Data TIX API"); + ctx.log(() => "Already purchased 4S Market Data TIX API"); return true; } if (player.money < getStockMarket4STixApiCost()) { - workerScript.log( - "stock.purchase4SMarketDataTixApi", - () => "Not enough money to purchase 4S Market Data TIX API", - ); + ctx.log(() => "Not enough money to purchase 4S Market Data TIX API"); return false; } player.has4SDataTixApi = true; player.loseMoney(getStockMarket4STixApiCost(), "stock"); - workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API"); + ctx.log(() => "Purchased 4S Market Data TIX API"); return true; }, - purchaseWseAccount: function (): boolean { - updateRam("PurchaseWseAccount"); - + purchaseWseAccount: (ctx: NetscriptContext) => (): boolean => { if (player.hasWseAccount) { - workerScript.log("stock.purchaseWseAccount", () => "Already purchased WSE Account"); + ctx.log(() => "Already purchased WSE Account"); return true; } if (player.money < getStockMarketWseCost()) { - workerScript.log("stock.purchaseWseAccount", () => "Not enough money to purchase WSE Account Access"); + ctx.log(() => "Not enough money to purchase WSE Account Access"); return false; } player.hasWseAccount = true; initStockMarketFn(); player.loseMoney(getStockMarketWseCost(), "stock"); - workerScript.log("stock.purchaseWseAccount", () => "Purchased WSE Account Access"); + ctx.log(() => "Purchased WSE Account Access"); return true; }, - purchaseTixApi: function (): boolean { - updateRam("purchaseTixApi"); - + purchaseTixApi: (ctx: NetscriptContext) => (): boolean => { if (player.hasTixApiAccess) { - workerScript.log("stock.purchaseTixApi", () => "Already purchased TIX API"); + ctx.log(() => "Already purchased TIX API"); return true; } if (player.money < getStockMarketTixApiCost()) { - workerScript.log("stock.purchaseTixApi", () => "Not enough money to purchase TIX API Access"); + ctx.log(() => "Not enough money to purchase TIX API Access"); return false; } player.hasTixApiAccess = true; player.loseMoney(getStockMarketTixApiCost(), "stock"); - workerScript.log("stock.purchaseTixApi", () => "Purchased TIX API"); + ctx.log(() => "Purchased TIX API"); return true; }, }; diff --git a/src/NetscriptFunctions/UserInterface.ts b/src/NetscriptFunctions/UserInterface.ts index b639f718a..a500aae7c 100644 --- a/src/NetscriptFunctions/UserInterface.ts +++ b/src/NetscriptFunctions/UserInterface.ts @@ -1,7 +1,3 @@ -import { INetscriptHelper } from "./INetscriptHelper"; -import { WorkerScript } from "../Netscript/WorkerScript"; -import { IPlayer } from "../PersonObjects/IPlayer"; -import { getRamCost } from "../Netscript/RamCostGenerator"; import { GameInfo, IStyleSettings, @@ -14,88 +10,80 @@ 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"; -export function NetscriptUserInterface( - player: IPlayer, - workerScript: WorkerScript, - helper: INetscriptHelper, -): IUserInterface { - const updateRam = (funcName: string): void => helper.updateDynamicRam(funcName, getRamCost(player, "ui", funcName)); +export function NetscriptUserInterface(): InternalAPI { return { - getTheme: function (): UserInterfaceTheme { - updateRam("getTheme"); + getTheme: () => (): UserInterfaceTheme => { return { ...Settings.theme }; }, - getStyles: function (): IStyleSettings { - updateRam("getStyles"); + getStyles: () => (): IStyleSettings => { return { ...Settings.styles }; }, - setTheme: function (newTheme: UserInterfaceTheme): void { - updateRam("setTheme"); - const hex = /^(#)((?:[A-Fa-f0-9]{2}){3,4}|(?:[A-Fa-f0-9]{3}))$/; - const currentTheme = { ...Settings.theme }; - const errors: string[] = []; - for (const key of Object.keys(newTheme)) { - if (!currentTheme[key]) { - // Invalid key - errors.push(`Invalid key "${key}"`); - } else if (!hex.test(newTheme[key] ?? "")) { - errors.push(`Invalid color "${key}": ${newTheme[key]}`); - } else { - currentTheme[key] = newTheme[key]; + setTheme: + (ctx: NetscriptContext) => + (newTheme: UserInterfaceTheme): void => { + const hex = /^(#)((?:[A-Fa-f0-9]{2}){3,4}|(?:[A-Fa-f0-9]{3}))$/; + const currentTheme = { ...Settings.theme }; + const errors: string[] = []; + for (const key of Object.keys(newTheme)) { + if (!currentTheme[key]) { + // Invalid key + errors.push(`Invalid key "${key}"`); + } else if (!hex.test(newTheme[key] ?? "")) { + errors.push(`Invalid color "${key}": ${newTheme[key]}`); + } else { + currentTheme[key] = newTheme[key]; + } } - } - if (errors.length === 0) { - Object.assign(Settings.theme, currentTheme); - ThemeEvents.emit(); - workerScript.log("ui.setTheme", () => `Successfully set theme`); - } else { - workerScript.log("ui.setTheme", () => `Failed to set theme. Errors: ${errors.join(", ")}`); - } - }, - - setStyles: function (newStyles: IStyleSettings): void { - updateRam("setStyles"); - - const currentStyles = { ...Settings.styles }; - const errors: string[] = []; - for (const key of Object.keys(newStyles)) { - if (!(currentStyles as any)[key]) { - // Invalid key - errors.push(`Invalid key "${key}"`); + if (errors.length === 0) { + Object.assign(Settings.theme, currentTheme); + ThemeEvents.emit(); + ctx.log(() => `Successfully set theme`); } else { - (currentStyles as any)[key] = (newStyles as any)[key]; + ctx.log(() => `Failed to set theme. Errors: ${errors.join(", ")}`); } - } + }, - if (errors.length === 0) { - Object.assign(Settings.styles, currentStyles); - ThemeEvents.emit(); - workerScript.log("ui.setStyles", () => `Successfully set styles`); - } else { - workerScript.log("ui.setStyles", () => `Failed to set styles. Errors: ${errors.join(", ")}`); - } - }, + setStyles: + (ctx: NetscriptContext) => + (newStyles: IStyleSettings): void => { + const currentStyles = { ...Settings.styles }; + const errors: string[] = []; + for (const key of Object.keys(newStyles)) { + if (!(currentStyles as any)[key]) { + // Invalid key + errors.push(`Invalid key "${key}"`); + } else { + (currentStyles as any)[key] = (newStyles as any)[key]; + } + } - resetTheme: function (): void { - updateRam("resetTheme"); + if (errors.length === 0) { + Object.assign(Settings.styles, currentStyles); + ThemeEvents.emit(); + ctx.log(() => `Successfully set styles`); + } else { + ctx.log(() => `Failed to set styles. Errors: ${errors.join(", ")}`); + } + }, + + resetTheme: (ctx: NetscriptContext) => (): void => { Settings.theme = { ...defaultTheme }; ThemeEvents.emit(); - workerScript.log("ui.resetTheme", () => `Reinitialized theme to default`); + ctx.log(() => `Reinitialized theme to default`); }, - resetStyles: function (): void { - updateRam("resetStyles"); + resetStyles: (ctx: NetscriptContext) => (): void => { Settings.styles = { ...defaultStyles }; ThemeEvents.emit(); - workerScript.log("ui.resetStyles", () => `Reinitialized styles to default`); + ctx.log(() => `Reinitialized styles to default`); }, - getGameInfo: function (): GameInfo { - updateRam("getGameInfo"); + getGameInfo: () => (): GameInfo => { const version = CONSTANTS.VersionString; const commit = hash(); const platform = navigator.userAgent.toLowerCase().indexOf(" electron/") > -1 ? "Steam" : "Browser";