From b2689eaa5abcb26e0f3768705c3d4b51ff8d81cf Mon Sep 17 00:00:00 2001 From: TheMas3212 Date: Tue, 12 Apr 2022 16:51:10 +1000 Subject: [PATCH] Wrap Singularity API with wrapper also refactored the RamCosts IMap as it didnt quite work properly due to how the wrapper calculates function names --- src/Netscript/APIWrapper.ts | 4 + src/Netscript/RamCostGenerator.ts | 444 ++--- src/NetscriptFunctions.ts | 4 +- src/NetscriptFunctions/Singularity.ts | 2333 ++++++++++++------------- 4 files changed, 1405 insertions(+), 1380 deletions(-) diff --git a/src/Netscript/APIWrapper.ts b/src/Netscript/APIWrapper.ts index d3df414c8..3dc0845a7 100644 --- a/src/Netscript/APIWrapper.ts +++ b/src/Netscript/APIWrapper.ts @@ -4,6 +4,7 @@ import type { BaseServer } from "../Server/BaseServer"; import type { WorkerScript } from "./WorkerScript"; import { makeRuntimeRejectMsg } from "../NetscriptEvaluator"; import { Player } from "../Player"; +import { CityName } from "src/Locations/data/CityNames"; type ExternalFunction = (...args: any[]) => any; type ExternalAPI = { @@ -37,6 +38,7 @@ type NetscriptHelpers = { makeRuntimeErrorMsg: (caller: string, msg: string) => string; string: (funcName: string, argName: string, v: unknown) => string; number: (funcName: string, argName: string, v: unknown) => number; + city: (funcName: string, argName: string, v: unknown) => CityName; boolean: (v: unknown) => boolean; getServer: (hostname: string, callingFnName: string) => BaseServer; checkSingularityAccess: (func: string) => void; @@ -48,6 +50,7 @@ type WrappedNetscriptHelpers = { makeRuntimeErrorMsg: (msg: string) => string; string: (argName: string, v: unknown) => string; number: (argName: string, v: unknown) => number; + city: (argName: string, v: unknown) => CityName; boolean: (v: unknown) => boolean; getServer: (hostname: string) => BaseServer; checkSingularityAccess: () => void; @@ -80,6 +83,7 @@ function wrapFunction( makeRuntimeErrorMsg: (msg: string) => helpers.makeRuntimeErrorMsg(functionPath, msg), string: (argName: string, v: unknown) => helpers.string(functionPath, argName, v), number: (argName: string, v: unknown) => helpers.number(functionPath, argName, v), + city: (argName: string, v: unknown) => helpers.city(functionPath, argName, v), boolean: helpers.boolean, getServer: (hostname: string) => helpers.getServer(hostname, functionPath), checkSingularityAccess: () => helpers.checkSingularityAccess(functionName), diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index f3929568c..8d2633084 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -81,24 +81,239 @@ function SF4Cost(cost: number): (player: IPlayer) => number { }; } +// Hacknet API +const hacknet: IMap = { + numNodes: 0, + purchaseNode: 0, + getPurchaseNodeCost: 0, + getNodeStats: 0, + upgradeLevel: 0, + upgradeRam: 0, + upgradeCore: 0, + upgradeCache: 0, + getLevelUpgradeCost: 0, + getRamUpgradeCost: 0, + getCoreUpgradeCost: 0, + getCacheUpgradeCost: 0, + numHashes: 0, + hashCost: 0, + spendHashes: 0, +}; + +// Stock API +const stock: IMap = { + getSymbols: RamCostConstants.ScriptGetStockRamCost, + getPrice: RamCostConstants.ScriptGetStockRamCost, + getAskPrice: RamCostConstants.ScriptGetStockRamCost, + getBidPrice: RamCostConstants.ScriptGetStockRamCost, + getPosition: RamCostConstants.ScriptGetStockRamCost, + getMaxShares: RamCostConstants.ScriptGetStockRamCost, + getPurchaseCost: RamCostConstants.ScriptGetStockRamCost, + getSaleGain: RamCostConstants.ScriptGetStockRamCost, + buy: RamCostConstants.ScriptBuySellStockRamCost, + sell: RamCostConstants.ScriptBuySellStockRamCost, + short: RamCostConstants.ScriptBuySellStockRamCost, + sellShort: RamCostConstants.ScriptBuySellStockRamCost, + placeOrder: RamCostConstants.ScriptBuySellStockRamCost, + cancelOrder: RamCostConstants.ScriptBuySellStockRamCost, + getOrders: RamCostConstants.ScriptBuySellStockRamCost, + getVolatility: RamCostConstants.ScriptBuySellStockRamCost, + getForecast: RamCostConstants.ScriptBuySellStockRamCost, + purchase4SMarketData: RamCostConstants.ScriptBuySellStockRamCost, + purchase4SMarketDataTixApi: RamCostConstants.ScriptBuySellStockRamCost, + purchaseWseAccount: RamCostConstants.ScriptBuySellStockRamCost, + purchaseTixApi: RamCostConstants.ScriptBuySellStockRamCost, +}; + +// Singularity API +const singularity: IMap = { + universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + goToLocation: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + purchaseTor: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + purchaseProgram: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + getCurrentServer: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + connect: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + manualHack: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + installBackdoor: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), + getDarkwebProgramCost: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), + getDarkwebPrograms: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), + getStats: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), + getCharacterInformation: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), + hospitalize: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), + isBusy: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), + stopAction: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 2), + upgradeHomeRam: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + upgradeHomeCores: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + getUpgradeHomeRamCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2), + getUpgradeHomeCoresCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2), + workForCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + applyToCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + getCompanyRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), + getCompanyFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), + getCompanyFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4), + checkFactionInvitations: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + joinFaction: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + workForFaction: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), + getFactionRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), + getFactionFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), + getFactionFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4), + donateToFaction: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + createProgram: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + commitCrime: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getCrimeChance: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getCrimeStats: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getOwnedAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getAugmentationsFromFaction: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getAugmentationCost: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getAugmentationPrereq: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + getAugmentationPrice: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost / 2), + getAugmentationRepReq: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost / 2), + getAugmentationStats: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + purchaseAugmentation: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + softReset: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + installAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), + isFocused: SF4Cost(0.1), + setFocus: SF4Cost(0.1), +}; + +// Gang API +const gang: IMap = { + createGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, + inGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, + getMemberNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, + getGangInformation: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getOtherGangInformation: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getMemberInformation: RamCostConstants.ScriptGangApiBaseRamCost / 2, + canRecruitMember: RamCostConstants.ScriptGangApiBaseRamCost / 4, + recruitMember: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getTaskNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, + getTaskStats: RamCostConstants.ScriptGangApiBaseRamCost / 4, + setMemberTask: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getEquipmentNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, + getEquipmentCost: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getEquipmentType: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getEquipmentStats: RamCostConstants.ScriptGangApiBaseRamCost / 2, + purchaseEquipment: RamCostConstants.ScriptGangApiBaseRamCost, + ascendMember: RamCostConstants.ScriptGangApiBaseRamCost, + getAscensionResult: RamCostConstants.ScriptGangApiBaseRamCost / 2, + setTerritoryWarfare: RamCostConstants.ScriptGangApiBaseRamCost / 2, + getChanceToWinClash: RamCostConstants.ScriptGangApiBaseRamCost, + getBonusTime: 0, +}; + +// Bladeburner API +const bladeburner: IMap = { + getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, + getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, + getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, + getBlackOpRank: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 2, + getGeneralActionNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, + getSkillNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, + startAction: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + stopBladeburnerAction: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 2, + getCurrentAction: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 4, + getActionTime: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getActionEstimatedSuccessChance: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getActionRepGain: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getActionCountRemaining: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getActionMaxLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getActionCurrentLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getActionAutolevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + setActionAutolevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + setActionLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getRank: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getSkillPoints: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getSkillLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getSkillUpgradeCost: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + upgradeSkill: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getTeamSize: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + setTeamSize: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getCityEstimatedPopulation: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getCityCommunities: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getCityChaos: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getCity: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + switchCity: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getStamina: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + joinBladeburnerFaction: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + joinBladeburnerDivision: RamCostConstants.ScriptBladeburnerApiBaseRamCost, + getBonusTime: 0, +}; + +// Coding Contract API +const codingcontract: IMap = { + attempt: RamCostConstants.ScriptCodingContractBaseRamCost, + getContractType: RamCostConstants.ScriptCodingContractBaseRamCost / 2, + getData: RamCostConstants.ScriptCodingContractBaseRamCost / 2, + getDescription: RamCostConstants.ScriptCodingContractBaseRamCost / 2, + getNumTriesRemaining: RamCostConstants.ScriptCodingContractBaseRamCost / 5, +}; + +// Duplicate Sleeve API +const sleeve: IMap = { + getNumSleeves: RamCostConstants.ScriptSleeveBaseRamCost, + setToShockRecovery: RamCostConstants.ScriptSleeveBaseRamCost, + setToSynchronize: RamCostConstants.ScriptSleeveBaseRamCost, + setToCommitCrime: RamCostConstants.ScriptSleeveBaseRamCost, + setToUniversityCourse: RamCostConstants.ScriptSleeveBaseRamCost, + travel: RamCostConstants.ScriptSleeveBaseRamCost, + setToCompanyWork: RamCostConstants.ScriptSleeveBaseRamCost, + setToFactionWork: RamCostConstants.ScriptSleeveBaseRamCost, + setToGymWorkout: RamCostConstants.ScriptSleeveBaseRamCost, + getSleeveStats: RamCostConstants.ScriptSleeveBaseRamCost, + getTask: RamCostConstants.ScriptSleeveBaseRamCost, + getInformation: RamCostConstants.ScriptSleeveBaseRamCost, + getSleeveAugmentations: RamCostConstants.ScriptSleeveBaseRamCost, + getSleevePurchasableAugs: RamCostConstants.ScriptSleeveBaseRamCost, + purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost, +}; + +// Stanek API +const stanek: IMap = { + giftWidth: RamCostConstants.ScriptStanekWidth, + giftHeight: RamCostConstants.ScriptStanekHeight, + chargeFragment: RamCostConstants.ScriptStanekCharge, + fragmentDefinitions: RamCostConstants.ScriptStanekFragmentDefinitions, + activeFragments: RamCostConstants.ScriptStanekPlacedFragments, + clearGift: RamCostConstants.ScriptStanekClear, + canPlaceFragment: RamCostConstants.ScriptStanekCanPlace, + placeFragment: RamCostConstants.ScriptStanekPlace, + getFragment: RamCostConstants.ScriptStanekFragmentAt, + removeFragment: RamCostConstants.ScriptStanekDeleteAt, +}; + +// UI API +const ui: IMap = { + getTheme: 0, + setTheme: 0, + resetTheme: 0, + getStyles: 0, + setStyles: 0, + resetStyles: 0, + getGameInfo: 0, +}; + +// Grafting API +const grafting: IMap = { + getAugmentationGraftPrice: 3.75, + getAugmentationGraftTime: 3.75, + graftAugmentation: 7.5, +}; + export const RamCosts: IMap = { - hacknet: { - numNodes: 0, - purchaseNode: 0, - getPurchaseNodeCost: 0, - getNodeStats: 0, - upgradeLevel: 0, - upgradeRam: 0, - upgradeCore: 0, - upgradeCache: 0, - getLevelUpgradeCost: 0, - getRamUpgradeCost: 0, - getCoreUpgradeCost: 0, - getCacheUpgradeCost: 0, - numHashes: 0, - hashCost: 0, - spendHashes: 0, - }, + hacknet, + stock, + singularity, + ...singularity, // singularity is in namespace & toplevel + gang, + bladeburner, + codingcontract, + sleeve, + stanek, + ui, + grafting, + sprintf: 0, vsprintf: 0, scan: RamCostConstants.ScriptScanRamCost, @@ -162,29 +377,6 @@ export const RamCosts: IMap = { serverExists: RamCostConstants.ScriptGetServerRamCost, fileExists: RamCostConstants.ScriptFileExistsRamCost, isRunning: RamCostConstants.ScriptIsRunningRamCost, - stock: { - getSymbols: RamCostConstants.ScriptGetStockRamCost, - getPrice: RamCostConstants.ScriptGetStockRamCost, - getAskPrice: RamCostConstants.ScriptGetStockRamCost, - getBidPrice: RamCostConstants.ScriptGetStockRamCost, - getPosition: RamCostConstants.ScriptGetStockRamCost, - getMaxShares: RamCostConstants.ScriptGetStockRamCost, - getPurchaseCost: RamCostConstants.ScriptGetStockRamCost, - getSaleGain: RamCostConstants.ScriptGetStockRamCost, - buy: RamCostConstants.ScriptBuySellStockRamCost, - sell: RamCostConstants.ScriptBuySellStockRamCost, - short: RamCostConstants.ScriptBuySellStockRamCost, - sellShort: RamCostConstants.ScriptBuySellStockRamCost, - placeOrder: RamCostConstants.ScriptBuySellStockRamCost, - cancelOrder: RamCostConstants.ScriptBuySellStockRamCost, - getOrders: RamCostConstants.ScriptBuySellStockRamCost, - getVolatility: RamCostConstants.ScriptBuySellStockRamCost, - getForecast: RamCostConstants.ScriptBuySellStockRamCost, - purchase4SMarketData: RamCostConstants.ScriptBuySellStockRamCost, - purchase4SMarketDataTixApi: RamCostConstants.ScriptBuySellStockRamCost, - purchaseWseAccount: RamCostConstants.ScriptBuySellStockRamCost, - purchaseTixApi: RamCostConstants.ScriptBuySellStockRamCost, - }, getPurchasedServerLimit: RamCostConstants.ScriptGetPurchasedServerLimit, getPurchasedServerMaxRam: RamCostConstants.ScriptGetPurchasedServerMaxRam, getPurchasedServerCost: RamCostConstants.ScriptGetPurchaseServerRamCost, @@ -221,178 +413,6 @@ export const RamCosts: IMap = { getOwnedSourceFiles: RamCostConstants.ScriptGetOwnedSourceFiles, tail: 0, toast: 0, - - // Singularity Functions - universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - goToLocation: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - purchaseTor: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - purchaseProgram: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - getCurrentServer: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - connect: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - manualHack: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - installBackdoor: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost), - getDarkwebProgramCost: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), - getDarkwebPrograms: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), - getStats: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), - getCharacterInformation: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), - hospitalize: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), - isBusy: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4), - stopAction: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 2), - upgradeHomeRam: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - upgradeHomeCores: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - getUpgradeHomeRamCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2), - getUpgradeHomeCoresCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2), - workForCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - applyToCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - getCompanyRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), - getCompanyFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), - getCompanyFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4), - checkFactionInvitations: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - joinFaction: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - workForFaction: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost), - getFactionRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), - getFactionFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3), - getFactionFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4), - donateToFaction: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - createProgram: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - commitCrime: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getCrimeChance: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getCrimeStats: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getOwnedAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getAugmentationsFromFaction: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getAugmentationCost: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getAugmentationPrereq: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - getAugmentationPrice: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost / 2), - getAugmentationRepReq: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost / 2), - getAugmentationStats: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - purchaseAugmentation: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - softReset: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - installAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost), - isFocused: SF4Cost(0.1), - setFocus: SF4Cost(0.1), - - // Gang API - gang: { - createGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, - inGang: RamCostConstants.ScriptGangApiBaseRamCost / 4, - getMemberNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, - getGangInformation: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getOtherGangInformation: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getMemberInformation: RamCostConstants.ScriptGangApiBaseRamCost / 2, - canRecruitMember: RamCostConstants.ScriptGangApiBaseRamCost / 4, - recruitMember: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getTaskNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, - getTaskStats: RamCostConstants.ScriptGangApiBaseRamCost / 4, - setMemberTask: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getEquipmentNames: RamCostConstants.ScriptGangApiBaseRamCost / 4, - getEquipmentCost: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getEquipmentType: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getEquipmentStats: RamCostConstants.ScriptGangApiBaseRamCost / 2, - purchaseEquipment: RamCostConstants.ScriptGangApiBaseRamCost, - ascendMember: RamCostConstants.ScriptGangApiBaseRamCost, - getAscensionResult: RamCostConstants.ScriptGangApiBaseRamCost / 2, - setTerritoryWarfare: RamCostConstants.ScriptGangApiBaseRamCost / 2, - getChanceToWinClash: RamCostConstants.ScriptGangApiBaseRamCost, - getBonusTime: 0, - }, - - // Bladeburner API - bladeburner: { - getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, - getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, - getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, - getBlackOpRank: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 2, - getGeneralActionNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, - getSkillNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10, - startAction: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - stopBladeburnerAction: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 2, - getCurrentAction: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 4, - getActionTime: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getActionEstimatedSuccessChance: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getActionRepGain: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getActionCountRemaining: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getActionMaxLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getActionCurrentLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getActionAutolevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - setActionAutolevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - setActionLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getRank: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getSkillPoints: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getSkillLevel: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getSkillUpgradeCost: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - upgradeSkill: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getTeamSize: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - setTeamSize: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getCityEstimatedPopulation: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getCityCommunities: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getCityChaos: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getCity: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - switchCity: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getStamina: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - joinBladeburnerFaction: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - joinBladeburnerDivision: RamCostConstants.ScriptBladeburnerApiBaseRamCost, - getBonusTime: 0, - }, - - // Coding Contract API - codingcontract: { - attempt: RamCostConstants.ScriptCodingContractBaseRamCost, - getContractType: RamCostConstants.ScriptCodingContractBaseRamCost / 2, - getData: RamCostConstants.ScriptCodingContractBaseRamCost / 2, - getDescription: RamCostConstants.ScriptCodingContractBaseRamCost / 2, - getNumTriesRemaining: RamCostConstants.ScriptCodingContractBaseRamCost / 5, - }, - - // Duplicate Sleeve API - sleeve: { - getNumSleeves: RamCostConstants.ScriptSleeveBaseRamCost, - setToShockRecovery: RamCostConstants.ScriptSleeveBaseRamCost, - setToSynchronize: RamCostConstants.ScriptSleeveBaseRamCost, - setToCommitCrime: RamCostConstants.ScriptSleeveBaseRamCost, - setToUniversityCourse: RamCostConstants.ScriptSleeveBaseRamCost, - travel: RamCostConstants.ScriptSleeveBaseRamCost, - setToCompanyWork: RamCostConstants.ScriptSleeveBaseRamCost, - setToFactionWork: RamCostConstants.ScriptSleeveBaseRamCost, - setToGymWorkout: RamCostConstants.ScriptSleeveBaseRamCost, - getSleeveStats: RamCostConstants.ScriptSleeveBaseRamCost, - getTask: RamCostConstants.ScriptSleeveBaseRamCost, - getInformation: RamCostConstants.ScriptSleeveBaseRamCost, - getSleeveAugmentations: RamCostConstants.ScriptSleeveBaseRamCost, - getSleevePurchasableAugs: RamCostConstants.ScriptSleeveBaseRamCost, - purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost, - }, - - stanek: { - giftWidth: RamCostConstants.ScriptStanekWidth, - giftHeight: RamCostConstants.ScriptStanekHeight, - chargeFragment: RamCostConstants.ScriptStanekCharge, - fragmentDefinitions: RamCostConstants.ScriptStanekFragmentDefinitions, - activeFragments: RamCostConstants.ScriptStanekPlacedFragments, - clearGift: RamCostConstants.ScriptStanekClear, - canPlaceFragment: RamCostConstants.ScriptStanekCanPlace, - placeFragment: RamCostConstants.ScriptStanekPlace, - getFragment: RamCostConstants.ScriptStanekFragmentAt, - removeFragment: RamCostConstants.ScriptStanekDeleteAt, - }, - - ui: { - getTheme: 0, - setTheme: 0, - resetTheme: 0, - getStyles: 0, - setStyles: 0, - resetStyles: 0, - getGameInfo: 0, - }, - - grafting: { - getAugmentationGraftPrice: 3.75, - getAugmentationGraftTime: 3.75, - graftAugmentation: 7.5, - }, - heart: { // Easter egg function break: 0, diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index 0ced4545f..4477ee211 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -75,6 +75,7 @@ import { IPort } from "./NetscriptPort"; import { NS as INS, + Singularity as ISingularity, Player as INetscriptPlayer, Gang as IGang, Bladeburner as IBladeburner, @@ -498,7 +499,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS { const codingcontract = NetscriptCodingContract(Player, workerScript, helper); const corporation = NetscriptCorporation(Player, workerScript, helper); const formulas = NetscriptFormulas(Player, workerScript, helper); - const singularity = NetscriptSingularity(Player, workerScript, helper); + 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); diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index 034eb7051..7675ebdfd 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -1,4 +1,3 @@ -import { INetscriptHelper } from "./INetscriptHelper"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; import { purchaseAugmentation, joinFaction, getFactionAugmentationsFiltered } from "../Faction/FactionHelpers"; @@ -10,7 +9,6 @@ import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; import { killWorkerScript } from "../Netscript/killWorkerScript"; import { CONSTANTS } from "../Constants"; import { isString } from "../utils/helpers/isString"; -import { getRamCost } from "../Netscript/RamCostGenerator"; import { RunningScript } from "../Script/RunningScript"; import { @@ -48,32 +46,29 @@ import { calculateHackingTime } from "../Hacking"; import { Server } from "../Server/Server"; import { netscriptCanHack } from "../Hacking/netscriptCanHack"; import { FactionInfos } from "../Faction/FactionInfo"; +import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; -export function NetscriptSingularity( - player: IPlayer, - workerScript: WorkerScript, - helper: INetscriptHelper, -): ISingularity { - const getAugmentation = function (func: string, name: string): Augmentation { +export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI { + const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation { if (!augmentationExists(name)) { - throw helper.makeRuntimeErrorMsg(func, `Invalid augmentation: '${name}'`); + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid augmentation: '${name}'`); } return Augmentations[name]; }; - const getFaction = function (func: string, name: string): Faction { + const getFaction = function (_ctx: NetscriptContext, name: string): Faction { if (!factionExists(name)) { - throw helper.makeRuntimeErrorMsg(func, `Invalid faction name: '${name}`); + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid faction name: '${name}`); } return Factions[name]; }; - const getCompany = function (func: string, name: string): Company { + const getCompany = function (_ctx: NetscriptContext, name: string): Company { const company = Companies[name]; if (company == null || !(company instanceof Company)) { - throw helper.makeRuntimeErrorMsg(func, `Invalid company name: '${name}'`); + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid company name: '${name}'`); } return company; }; @@ -96,1226 +91,1230 @@ export function NetscriptSingularity( } }; - const updateRam = (funcName: string): void => helper.updateDynamicRam(funcName, getRamCost(player, funcName)); return { - getOwnedAugmentations: function (_purchased: unknown = false): string[] { - updateRam("getOwnedAugmentations"); - const purchased = helper.boolean(_purchased); - helper.checkSingularityAccess("getOwnedAugmentations"); - const res = []; - for (let i = 0; i < player.augmentations.length; ++i) { - res.push(player.augmentations[i].name); - } - if (purchased) { - for (let i = 0; i < player.queuedAugmentations.length; ++i) { - res.push(player.queuedAugmentations[i].name); + getOwnedAugmentations: (_ctx: NetscriptContext) => + function (_purchased: unknown = false): string[] { + const purchased = _ctx.helper.boolean(_purchased); + _ctx.helper.checkSingularityAccess(); + const res = []; + for (let i = 0; i < player.augmentations.length; ++i) { + res.push(player.augmentations[i].name); } - } - return res; - }, - getAugmentationsFromFaction: function (_facName: unknown): string[] { - updateRam("getAugmentationsFromFaction"); - const facName = helper.string("getAugmentationsFromFaction", "facName", _facName); - helper.checkSingularityAccess("getAugmentationsFromFaction"); - const faction = getFaction("getAugmentationsFromFaction", facName); - - return getFactionAugmentationsFiltered(player, faction); - }, - getAugmentationCost: function (_augName: unknown): [number, number] { - updateRam("getAugmentationCost"); - const augName = helper.string("getAugmentationCost", "augName", _augName); - helper.checkSingularityAccess("getAugmentationCost"); - const aug = getAugmentation("getAugmentationCost", augName); - return [aug.baseRepRequirement, aug.baseCost]; - }, - getAugmentationPrereq: function (_augName: unknown): string[] { - updateRam("getAugmentationPrereq"); - const augName = helper.string("getAugmentationPrereq", "augName", _augName); - helper.checkSingularityAccess("getAugmentationPrereq"); - const aug = getAugmentation("getAugmentationPrereq", augName); - return aug.prereqs.slice(); - }, - getAugmentationPrice: function (_augName: unknown): number { - updateRam("getAugmentationPrice"); - const augName = helper.string("getAugmentationPrice", "augName", _augName); - helper.checkSingularityAccess("getAugmentationPrice"); - const aug = getAugmentation("getAugmentationPrice", augName); - return aug.baseCost; - }, - getAugmentationRepReq: function (_augName: unknown): number { - updateRam("getAugmentationRepReq"); - const augName = helper.string("getAugmentationRepReq", "augName", _augName); - helper.checkSingularityAccess("getAugmentationRepReq"); - const aug = getAugmentation("getAugmentationRepReq", augName); - return aug.baseRepRequirement; - }, - getAugmentationStats: function (_augName: unknown): AugmentationStats { - updateRam("getAugmentationStats"); - const augName = helper.string("getAugmentationStats", "augName", _augName); - helper.checkSingularityAccess("getAugmentationStats"); - const aug = getAugmentation("getAugmentationStats", augName); - return Object.assign({}, aug.mults); - }, - purchaseAugmentation: function (_facName: unknown, _augName: unknown): boolean { - updateRam("purchaseAugmentation"); - const facName = helper.string("purchaseAugmentation", "facName", _facName); - const augName = helper.string("purchaseAugmentation", "augName", _augName); - helper.checkSingularityAccess("purchaseAugmentation"); - const fac = getFaction("purchaseAugmentation", facName); - const aug = getAugmentation("purchaseAugmentation", augName); - - const augs = getFactionAugmentationsFiltered(player, fac); - - if (!augs.includes(augName)) { - workerScript.log( - "purchaseAugmentation", - () => `Faction '${facName}' does not have the '${augName}' augmentation.`, - ); - return false; - } - - const isNeuroflux = aug.name === AugmentationNames.NeuroFluxGovernor; - if (!isNeuroflux) { - for (let j = 0; j < player.queuedAugmentations.length; ++j) { - if (player.queuedAugmentations[j].name === aug.name) { - workerScript.log("purchaseAugmentation", () => `You already have the '${augName}' augmentation.`); - return false; + if (purchased) { + for (let i = 0; i < player.queuedAugmentations.length; ++i) { + res.push(player.queuedAugmentations[i].name); } } - for (let j = 0; j < player.augmentations.length; ++j) { - if (player.augmentations[j].name === aug.name) { - workerScript.log("purchaseAugmentation", () => `You already have the '${augName}' augmentation.`); - return false; + return res; + }, + getAugmentationsFromFaction: (_ctx: NetscriptContext) => + function (_facName: unknown): string[] { + const facName = _ctx.helper.string("facName", _facName); + _ctx.helper.checkSingularityAccess(); + const faction = getFaction(_ctx, facName); + + return getFactionAugmentationsFiltered(player, faction); + }, + getAugmentationCost: (_ctx: NetscriptContext) => + function (_augName: unknown): [number, number] { + const augName = _ctx.helper.string("augName", _augName); + _ctx.helper.checkSingularityAccess(); + const aug = getAugmentation(_ctx, augName); + return [aug.baseRepRequirement, aug.baseCost]; + }, + getAugmentationPrereq: (_ctx: NetscriptContext) => + function (_augName: unknown): string[] { + const augName = _ctx.helper.string("augName", _augName); + _ctx.helper.checkSingularityAccess(); + const aug = getAugmentation(_ctx, augName); + return aug.prereqs.slice(); + }, + getAugmentationPrice: (_ctx: NetscriptContext) => + function (_augName: unknown): number { + const augName = _ctx.helper.string("augName", _augName); + _ctx.helper.checkSingularityAccess(); + const aug = getAugmentation(_ctx, augName); + return aug.baseCost; + }, + getAugmentationRepReq: (_ctx: NetscriptContext) => + function (_augName: unknown): number { + const augName = _ctx.helper.string("augName", _augName); + _ctx.helper.checkSingularityAccess(); + const aug = getAugmentation(_ctx, augName); + return aug.baseRepRequirement; + }, + getAugmentationStats: (_ctx: NetscriptContext) => + function (_augName: unknown): AugmentationStats { + const augName = _ctx.helper.string("augName", _augName); + _ctx.helper.checkSingularityAccess(); + const aug = getAugmentation(_ctx, augName); + return Object.assign({}, aug.mults); + }, + purchaseAugmentation: (_ctx: NetscriptContext) => + function (_facName: unknown, _augName: unknown): boolean { + const facName = _ctx.helper.string("facName", _facName); + const augName = _ctx.helper.string("augName", _augName); + _ctx.helper.checkSingularityAccess(); + const fac = getFaction(_ctx, facName); + const aug = getAugmentation(_ctx, augName); + + const augs = getFactionAugmentationsFiltered(player, fac); + + if (!augs.includes(augName)) { + workerScript.log( + "purchaseAugmentation", + () => `Faction '${facName}' does not have the '${augName}' augmentation.`, + ); + return false; + } + + const isNeuroflux = aug.name === AugmentationNames.NeuroFluxGovernor; + if (!isNeuroflux) { + for (let j = 0; j < player.queuedAugmentations.length; ++j) { + if (player.queuedAugmentations[j].name === aug.name) { + workerScript.log("purchaseAugmentation", () => `You already have the '${augName}' augmentation.`); + return false; + } + } + for (let j = 0; j < player.augmentations.length; ++j) { + if (player.augmentations[j].name === aug.name) { + workerScript.log("purchaseAugmentation", () => `You already have the '${augName}' augmentation.`); + return false; + } } } - } - if (fac.playerReputation < aug.baseRepRequirement) { - workerScript.log("purchaseAugmentation", () => `You do not have enough reputation with '${fac.name}'.`); - return false; - } - - const res = purchaseAugmentation(aug, fac, true); - workerScript.log("purchaseAugmentation", () => res); - if (isString(res) && res.startsWith("You purchased")) { - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10); - return true; - } else { - return false; - } - }, - softReset: function (_cbScript: unknown): void { - updateRam("softReset"); - const cbScript = helper.string("softReset", "cbScript", _cbScript); - helper.checkSingularityAccess("softReset"); - - workerScript.log("softReset", () => "Soft resetting. This will cause this script to be killed"); - setTimeout(() => { - installAugmentations(true); - runAfterReset(cbScript); - }, 0); - - // Prevent workerScript from "finishing execution naturally" - workerScript.running = false; - killWorkerScript(workerScript); - }, - installAugmentations: function (_cbScript: unknown = ""): boolean { - updateRam("installAugmentations"); - const cbScript = helper.string("installAugmentations", "cbScript", _cbScript); - helper.checkSingularityAccess("installAugmentations"); - - if (player.queuedAugmentations.length === 0) { - workerScript.log("installAugmentations", () => "You do not have any Augmentations to be installed."); - return false; - } - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10); - workerScript.log( - "installAugmentations", - () => "Installing Augmentations. This will cause this script to be killed", - ); - setTimeout(() => { - installAugmentations(); - runAfterReset(cbScript); - }, 0); - - workerScript.running = false; // Prevent workerScript from "finishing execution naturally" - killWorkerScript(workerScript); - return true; - }, - - goToLocation: function (_locationName: unknown): boolean { - updateRam("goToLocation"); - const locationName = helper.string("goToLocation", "locationName", _locationName); - helper.checkSingularityAccess("goToLocation"); - const location = Object.values(Locations).find((l) => l.name === locationName); - if (!location) { - workerScript.log("goToLocation", () => `No location named ${locationName}`); - return false; - } - if (player.city !== location.city) { - workerScript.log("goToLocation", () => `No location named ${locationName} in ${player.city}`); - return false; - } - Router.toLocation(location); - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000); - return true; - }, - universityCourse: function (_universityName: unknown, _className: unknown, _focus: unknown = true): boolean { - updateRam("universityCourse"); - const universityName = helper.string("universityCourse", "universityName", _universityName); - const className = helper.string("universityCourse", "className", _className); - const focus = helper.boolean(_focus); - helper.checkSingularityAccess("universityCourse"); - const wasFocusing = player.focus; - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("universityCourse", () => txt); - } - - let costMult, expMult; - switch (universityName.toLowerCase()) { - case LocationName.AevumSummitUniversity.toLowerCase(): - if (player.city != CityName.Aevum) { - workerScript.log( - "universityCourse", - () => `You cannot study at 'Summit University' because you are not in '${CityName.Aevum}'.`, - ); - return false; - } - player.gotoLocation(LocationName.AevumSummitUniversity); - costMult = 4; - expMult = 3; - break; - case LocationName.Sector12RothmanUniversity.toLowerCase(): - if (player.city != CityName.Sector12) { - workerScript.log( - "universityCourse", - () => `You cannot study at 'Rothman University' because you are not in '${CityName.Sector12}'.`, - ); - return false; - } - player.location = LocationName.Sector12RothmanUniversity; - costMult = 3; - expMult = 2; - break; - case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): - if (player.city != CityName.Volhaven) { - workerScript.log( - "universityCourse", - () => `You cannot study at 'ZB Institute of Technology' because you are not in '${CityName.Volhaven}'.`, - ); - return false; - } - player.location = LocationName.VolhavenZBInstituteOfTechnology; - costMult = 5; - expMult = 4; - break; - default: - workerScript.log("universityCourse", () => `Invalid university name: '${universityName}'.`); + if (fac.playerReputation < aug.baseRepRequirement) { + workerScript.log("purchaseAugmentation", () => `You do not have enough reputation with '${fac.name}'.`); return false; - } + } - let task = ""; - switch (className.toLowerCase()) { - case "Study Computer Science".toLowerCase(): - task = CONSTANTS.ClassStudyComputerScience; - break; - case "Data Structures".toLowerCase(): - task = CONSTANTS.ClassDataStructures; - break; - case "Networks".toLowerCase(): - task = CONSTANTS.ClassNetworks; - break; - case "Algorithms".toLowerCase(): - task = CONSTANTS.ClassAlgorithms; - break; - case "Management".toLowerCase(): - task = CONSTANTS.ClassManagement; - break; - case "Leadership".toLowerCase(): - task = CONSTANTS.ClassLeadership; - break; - default: - workerScript.log("universityCourse", () => `Invalid class name: ${className}.`); - return false; - } - player.startClass(costMult, expMult, task); - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log("universityCourse", () => `Started ${task} at ${universityName}`); - return true; - }, - - gymWorkout: function (_gymName: unknown, _stat: unknown, _focus: unknown = true): boolean { - updateRam("gymWorkout"); - const gymName = helper.string("gymWorkout", "gymName", _gymName); - const stat = helper.string("gymWorkout", "stat", _stat); - const focus = helper.boolean(_focus); - helper.checkSingularityAccess("gymWorkout"); - const wasFocusing = player.focus; - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("gymWorkout", () => txt); - } - let costMult, expMult; - switch (gymName.toLowerCase()) { - case LocationName.AevumCrushFitnessGym.toLowerCase(): - if (player.city != CityName.Aevum) { - workerScript.log( - "gymWorkout", - () => - `You cannot workout at '${LocationName.AevumCrushFitnessGym}' because you are not in '${CityName.Aevum}'.`, - ); - return false; - } - player.location = LocationName.AevumCrushFitnessGym; - costMult = 3; - expMult = 2; - break; - case LocationName.AevumSnapFitnessGym.toLowerCase(): - if (player.city != CityName.Aevum) { - workerScript.log( - "gymWorkout", - () => - `You cannot workout at '${LocationName.AevumSnapFitnessGym}' because you are not in '${CityName.Aevum}'.`, - ); - return false; - } - player.location = LocationName.AevumSnapFitnessGym; - costMult = 10; - expMult = 5; - break; - case LocationName.Sector12IronGym.toLowerCase(): - if (player.city != CityName.Sector12) { - workerScript.log( - "gymWorkout", - () => - `You cannot workout at '${LocationName.Sector12IronGym}' because you are not in '${CityName.Sector12}'.`, - ); - return false; - } - player.location = LocationName.Sector12IronGym; - costMult = 1; - expMult = 1; - break; - case LocationName.Sector12PowerhouseGym.toLowerCase(): - if (player.city != CityName.Sector12) { - workerScript.log( - "gymWorkout", - () => - `You cannot workout at '${LocationName.Sector12PowerhouseGym}' because you are not in '${CityName.Sector12}'.`, - ); - return false; - } - player.location = LocationName.Sector12PowerhouseGym; - costMult = 20; - expMult = 10; - break; - case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): - if (player.city != CityName.Volhaven) { - workerScript.log( - "gymWorkout", - () => - `You cannot workout at '${LocationName.VolhavenMilleniumFitnessGym}' because you are not in '${CityName.Volhaven}'.`, - ); - return false; - } - player.location = LocationName.VolhavenMilleniumFitnessGym; - costMult = 7; - expMult = 4; - break; - default: - workerScript.log("gymWorkout", () => `Invalid gym name: ${gymName}. gymWorkout() failed`); - return false; - } - - switch (stat.toLowerCase()) { - case "strength".toLowerCase(): - case "str".toLowerCase(): - player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength); - break; - case "defense".toLowerCase(): - case "def".toLowerCase(): - player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense); - break; - case "dexterity".toLowerCase(): - case "dex".toLowerCase(): - player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity); - break; - case "agility".toLowerCase(): - case "agi".toLowerCase(): - player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility); - break; - default: - workerScript.log("gymWorkout", () => `Invalid stat: ${stat}.`); - return false; - } - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log("gymWorkout", () => `Started training ${stat} at ${gymName}`); - return true; - }, - - travelToCity: function (_cityName: unknown): boolean { - updateRam("travelToCity"); - const cityName = helper.city("travelToCity", "cityName", _cityName); - helper.checkSingularityAccess("travelToCity"); - - switch (cityName) { - case CityName.Aevum: - case CityName.Chongqing: - case CityName.Sector12: - case CityName.NewTokyo: - case CityName.Ishima: - case CityName.Volhaven: - if (player.money < CONSTANTS.TravelCost) { - workerScript.log("travelToCity", () => "Not enough money to travel."); - return false; - } - player.loseMoney(CONSTANTS.TravelCost, "other"); - player.city = cityName; - workerScript.log("travelToCity", () => `Traveled to ${cityName}`); - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000); + const res = purchaseAugmentation(aug, fac, true); + workerScript.log("purchaseAugmentation", () => res); + if (isString(res) && res.startsWith("You purchased")) { + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10); return true; - default: - throw helper.makeRuntimeErrorMsg("travelToCity", `Invalid city name: '${cityName}'.`); - } - }, + } else { + return false; + } + }, + softReset: (_ctx: NetscriptContext) => + function (_cbScript: unknown = ""): void { + const cbScript = _ctx.helper.string("cbScript", _cbScript); + _ctx.helper.checkSingularityAccess(); - purchaseTor: function (): boolean { - updateRam("purchaseTor"); - helper.checkSingularityAccess("purchaseTor"); + workerScript.log("softReset", () => "Soft resetting. This will cause this script to be killed"); + setTimeout(() => { + installAugmentations(true); + runAfterReset(cbScript); + }, 0); - if (player.hasTorRouter()) { - workerScript.log("purchaseTor", () => "You already have a TOR router!"); + // Prevent workerScript from "finishing execution naturally" + workerScript.running = false; + killWorkerScript(workerScript); + }, + installAugmentations: (_ctx: NetscriptContext) => + function (_cbScript: unknown = ""): boolean { + const cbScript = _ctx.helper.string("cbScript", _cbScript); + _ctx.helper.checkSingularityAccess(); + + if (player.queuedAugmentations.length === 0) { + workerScript.log("installAugmentations", () => "You do not have any Augmentations to be installed."); + return false; + } + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 10); + workerScript.log( + "installAugmentations", + () => "Installing Augmentations. This will cause this script to be killed", + ); + setTimeout(() => { + installAugmentations(); + runAfterReset(cbScript); + }, 0); + + workerScript.running = false; // Prevent workerScript from "finishing execution naturally" + killWorkerScript(workerScript); return true; - } + }, - if (player.money < CONSTANTS.TorRouterCost) { - workerScript.log("purchaseTor", () => "You cannot afford to purchase a Tor router."); - return false; - } - player.loseMoney(CONSTANTS.TorRouterCost, "other"); + goToLocation: (_ctx: NetscriptContext) => + function (_locationName: unknown): boolean { + const locationName = _ctx.helper.string("locationName", _locationName); + _ctx.helper.checkSingularityAccess(); + const location = Object.values(Locations).find((l) => l.name === locationName); + if (!location) { + workerScript.log("goToLocation", () => `No location named ${locationName}`); + return false; + } + if (player.city !== location.city) { + workerScript.log("goToLocation", () => `No location named ${locationName} in ${player.city}`); + return false; + } + Router.toLocation(location); + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000); + return true; + }, + universityCourse: (_ctx: NetscriptContext) => + function (_universityName: unknown, _className: unknown, _focus: unknown = true): boolean { + const universityName = _ctx.helper.string("universityName", _universityName); + const className = _ctx.helper.string("className", _className); + const focus = _ctx.helper.boolean(_focus); + _ctx.helper.checkSingularityAccess(); + const wasFocusing = player.focus; + if (player.isWorking) { + const txt = player.singularityStopWork(); + workerScript.log("universityCourse", () => txt); + } - const darkweb = safetlyCreateUniqueServer({ - ip: createUniqueRandomIp(), - hostname: "darkweb", - organizationName: "", - isConnectedTo: false, - adminRights: false, - purchasedByPlayer: false, - maxRam: 1, - }); - AddToAllServers(darkweb); + let costMult, expMult; + switch (universityName.toLowerCase()) { + case LocationName.AevumSummitUniversity.toLowerCase(): + if (player.city != CityName.Aevum) { + workerScript.log( + "universityCourse", + () => `You cannot study at 'Summit University' because you are not in '${CityName.Aevum}'.`, + ); + return false; + } + player.gotoLocation(LocationName.AevumSummitUniversity); + costMult = 4; + expMult = 3; + break; + case LocationName.Sector12RothmanUniversity.toLowerCase(): + if (player.city != CityName.Sector12) { + workerScript.log( + "universityCourse", + () => `You cannot study at 'Rothman University' because you are not in '${CityName.Sector12}'.`, + ); + return false; + } + player.location = LocationName.Sector12RothmanUniversity; + costMult = 3; + expMult = 2; + break; + case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): + if (player.city != CityName.Volhaven) { + workerScript.log( + "universityCourse", + () => `You cannot study at 'ZB Institute of Technology' because you are not in '${CityName.Volhaven}'.`, + ); + return false; + } + player.location = LocationName.VolhavenZBInstituteOfTechnology; + costMult = 5; + expMult = 4; + break; + default: + workerScript.log("universityCourse", () => `Invalid university name: '${universityName}'.`); + return false; + } - player.getHomeComputer().serversOnNetwork.push(darkweb.hostname); - darkweb.serversOnNetwork.push(player.getHomeComputer().hostname); - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 500); - workerScript.log("purchaseTor", () => "You have purchased a Tor router!"); - return true; - }, - purchaseProgram: function (_programName: unknown): boolean { - updateRam("purchaseProgram"); - const programName = helper.string("purchaseProgram", "programName", _programName).toLowerCase(); - helper.checkSingularityAccess("purchaseProgram"); + let task = ""; + switch (className.toLowerCase()) { + case "Study Computer Science".toLowerCase(): + task = CONSTANTS.ClassStudyComputerScience; + break; + case "Data Structures".toLowerCase(): + task = CONSTANTS.ClassDataStructures; + break; + case "Networks".toLowerCase(): + task = CONSTANTS.ClassNetworks; + break; + case "Algorithms".toLowerCase(): + task = CONSTANTS.ClassAlgorithms; + break; + case "Management".toLowerCase(): + task = CONSTANTS.ClassManagement; + break; + case "Leadership".toLowerCase(): + task = CONSTANTS.ClassLeadership; + break; + default: + workerScript.log("universityCourse", () => `Invalid class name: ${className}.`); + return false; + } + player.startClass(costMult, expMult, task); + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } + workerScript.log("universityCourse", () => `Started ${task} at ${universityName}`); + return true; + }, - if (!player.hasTorRouter()) { - workerScript.log("purchaseProgram", () => "You do not have the TOR router."); - return false; - } + gymWorkout: (_ctx: NetscriptContext) => + function (_gymName: unknown, _stat: unknown, _focus: unknown = true): boolean { + const gymName = _ctx.helper.string("gymName", _gymName); + const stat = _ctx.helper.string("stat", _stat); + const focus = _ctx.helper.boolean(_focus); + _ctx.helper.checkSingularityAccess(); + const wasFocusing = player.focus; + if (player.isWorking) { + const txt = player.singularityStopWork(); + workerScript.log("gymWorkout", () => txt); + } + let costMult, expMult; + switch (gymName.toLowerCase()) { + case LocationName.AevumCrushFitnessGym.toLowerCase(): + if (player.city != CityName.Aevum) { + workerScript.log( + "gymWorkout", + () => + `You cannot workout at '${LocationName.AevumCrushFitnessGym}' because you are not in '${CityName.Aevum}'.`, + ); + return false; + } + player.location = LocationName.AevumCrushFitnessGym; + costMult = 3; + expMult = 2; + break; + case LocationName.AevumSnapFitnessGym.toLowerCase(): + if (player.city != CityName.Aevum) { + workerScript.log( + "gymWorkout", + () => + `You cannot workout at '${LocationName.AevumSnapFitnessGym}' because you are not in '${CityName.Aevum}'.`, + ); + return false; + } + player.location = LocationName.AevumSnapFitnessGym; + costMult = 10; + expMult = 5; + break; + case LocationName.Sector12IronGym.toLowerCase(): + if (player.city != CityName.Sector12) { + workerScript.log( + "gymWorkout", + () => + `You cannot workout at '${LocationName.Sector12IronGym}' because you are not in '${CityName.Sector12}'.`, + ); + return false; + } + player.location = LocationName.Sector12IronGym; + costMult = 1; + expMult = 1; + break; + case LocationName.Sector12PowerhouseGym.toLowerCase(): + if (player.city != CityName.Sector12) { + workerScript.log( + "gymWorkout", + () => + `You cannot workout at '${LocationName.Sector12PowerhouseGym}' because you are not in '${CityName.Sector12}'.`, + ); + return false; + } + player.location = LocationName.Sector12PowerhouseGym; + costMult = 20; + expMult = 10; + break; + case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): + if (player.city != CityName.Volhaven) { + workerScript.log( + "gymWorkout", + () => + `You cannot workout at '${LocationName.VolhavenMilleniumFitnessGym}' because you are not in '${CityName.Volhaven}'.`, + ); + return false; + } + player.location = LocationName.VolhavenMilleniumFitnessGym; + costMult = 7; + expMult = 4; + break; + default: + workerScript.log("gymWorkout", () => `Invalid gym name: ${gymName}. gymWorkout() failed`); + return false; + } - const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName); - if (item == null) { - workerScript.log("purchaseProgram", () => `Invalid program name: '${programName}.`); - return false; - } + switch (stat.toLowerCase()) { + case "strength".toLowerCase(): + case "str".toLowerCase(): + player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength); + break; + case "defense".toLowerCase(): + case "def".toLowerCase(): + player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense); + break; + case "dexterity".toLowerCase(): + case "dex".toLowerCase(): + player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity); + break; + case "agility".toLowerCase(): + case "agi".toLowerCase(): + player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility); + break; + default: + workerScript.log("gymWorkout", () => `Invalid stat: ${stat}.`); + return false; + } + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } + workerScript.log("gymWorkout", () => `Started training ${stat} at ${gymName}`); + return true; + }, - if (player.money < item.price) { + travelToCity: (_ctx: NetscriptContext) => + function (_cityName: unknown): boolean { + const cityName = _ctx.helper.city("cityName", _cityName); + _ctx.helper.checkSingularityAccess(); + + switch (cityName) { + case CityName.Aevum: + case CityName.Chongqing: + case CityName.Sector12: + case CityName.NewTokyo: + case CityName.Ishima: + case CityName.Volhaven: + if (player.money < CONSTANTS.TravelCost) { + workerScript.log("travelToCity", () => "Not enough money to travel."); + return false; + } + player.loseMoney(CONSTANTS.TravelCost, "other"); + player.city = cityName; + workerScript.log("travelToCity", () => `Traveled to ${cityName}`); + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000); + return true; + default: + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid city name: '${cityName}'.`); + } + }, + + purchaseTor: (_ctx: NetscriptContext) => + function (): boolean { + _ctx.helper.checkSingularityAccess(); + + if (player.hasTorRouter()) { + workerScript.log("purchaseTor", () => "You already have a TOR router!"); + return true; + } + + if (player.money < CONSTANTS.TorRouterCost) { + workerScript.log("purchaseTor", () => "You cannot afford to purchase a Tor router."); + return false; + } + player.loseMoney(CONSTANTS.TorRouterCost, "other"); + + const darkweb = safetlyCreateUniqueServer({ + ip: createUniqueRandomIp(), + hostname: "darkweb", + organizationName: "", + isConnectedTo: false, + adminRights: false, + purchasedByPlayer: false, + maxRam: 1, + }); + AddToAllServers(darkweb); + + player.getHomeComputer().serversOnNetwork.push(darkweb.hostname); + darkweb.serversOnNetwork.push(player.getHomeComputer().hostname); + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 500); + workerScript.log("purchaseTor", () => "You have purchased a Tor router!"); + return true; + }, + purchaseProgram: (_ctx: NetscriptContext) => + function (_programName: unknown): boolean { + const programName = _ctx.helper.string("programName", _programName).toLowerCase(); + _ctx.helper.checkSingularityAccess(); + + if (!player.hasTorRouter()) { + workerScript.log("purchaseProgram", () => "You do not have the TOR router."); + return false; + } + + const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName); + if (item == null) { + workerScript.log("purchaseProgram", () => `Invalid program name: '${programName}.`); + return false; + } + + if (player.money < item.price) { + workerScript.log( + "purchaseProgram", + () => `Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`, + ); + return false; + } + + if (player.hasProgram(item.program)) { + workerScript.log("purchaseProgram", () => `You already have the '${item.program}' program`); + return true; + } + + player.loseMoney(item.price, "other"); + player.getHomeComputer().programs.push(item.program); workerScript.log( "purchaseProgram", - () => `Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`, + () => `You have purchased the '${item.program}' program. The new program can be found on your home computer.`, ); - return false; - } - - if (player.hasProgram(item.program)) { - workerScript.log("purchaseProgram", () => `You already have the '${item.program}' program`); + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 5000); return true; - } + }, + getCurrentServer: (_ctx: NetscriptContext) => + function (): string { + _ctx.helper.checkSingularityAccess(); + return player.getCurrentServer().hostname; + }, + connect: (_ctx: NetscriptContext) => + function (_hostname: unknown): boolean { + const hostname = _ctx.helper.string("hostname", _hostname); + _ctx.helper.checkSingularityAccess(); + if (!hostname) { + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid hostname: '${hostname}'`); + } - player.loseMoney(item.price, "other"); - player.getHomeComputer().programs.push(item.program); - workerScript.log( - "purchaseProgram", - () => `You have purchased the '${item.program}' program. The new program can be found on your home computer.`, - ); - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 5000); - return true; - }, - getCurrentServer: function (): string { - updateRam("getCurrentServer"); - helper.checkSingularityAccess("getCurrentServer"); - return player.getCurrentServer().hostname; - }, - connect: function (_hostname: unknown): boolean { - updateRam("connect"); - const hostname = helper.string("purchaseProgram", "hostname", _hostname); - helper.checkSingularityAccess("connect"); - if (!hostname) { - throw helper.makeRuntimeErrorMsg("connect", `Invalid hostname: '${hostname}'`); - } + const target = GetServer(hostname); + if (target == null) { + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid hostname: '${hostname}'`); + } - const target = GetServer(hostname); - if (target == null) { - throw helper.makeRuntimeErrorMsg("connect", `Invalid hostname: '${hostname}'`); - } - - if (hostname === "home") { - player.getCurrentServer().isConnectedTo = false; - player.currentServer = player.getHomeComputer().hostname; - player.getCurrentServer().isConnectedTo = true; - Terminal.setcwd("/"); - return true; - } - - const server = player.getCurrentServer(); - for (let i = 0; i < server.serversOnNetwork.length; i++) { - const other = getServerOnNetwork(server, i); - if (other === null) continue; - if (other.hostname == hostname) { + if (hostname === "home") { player.getCurrentServer().isConnectedTo = false; - player.currentServer = target.hostname; + player.currentServer = player.getHomeComputer().hostname; player.getCurrentServer().isConnectedTo = true; Terminal.setcwd("/"); return true; } - } - return false; - }, - manualHack: function (): Promise { - updateRam("manualHack"); - helper.checkSingularityAccess("manualHack"); - const server = player.getCurrentServer(); - return helper.hack(server.hostname, true); - }, - installBackdoor: function (): Promise { - updateRam("installBackdoor"); - helper.checkSingularityAccess("installBackdoor"); - const baseserver = player.getCurrentServer(); - if (!(baseserver instanceof Server)) { - workerScript.log("installBackdoor", () => "cannot backdoor this kind of server"); - return Promise.resolve(); - } - const server = baseserver as Server; - const installTime = (calculateHackingTime(server, player) / 4) * 1000; - - // No root access or skill level too low - const canHack = netscriptCanHack(server, player); - if (!canHack.res) { - throw helper.makeRuntimeErrorMsg("installBackdoor", canHack.msg || ""); - } - - workerScript.log( - "installBackdoor", - () => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`, - ); - - return netscriptDelay(installTime, workerScript).then(function () { - workerScript.log("installBackdoor", () => `Successfully installed backdoor on '${server.hostname}'`); - - server.backdoorInstalled = true; - - if (SpecialServers.WorldDaemon === server.hostname) { - Router.toBitVerse(false, false); + const server = player.getCurrentServer(); + for (let i = 0; i < server.serversOnNetwork.length; i++) { + const other = getServerOnNetwork(server, i); + if (other === null) continue; + if (other.hostname == hostname) { + player.getCurrentServer().isConnectedTo = false; + player.currentServer = target.hostname; + player.getCurrentServer().isConnectedTo = true; + Terminal.setcwd("/"); + return true; + } } - return Promise.resolve(); - }); - }, - isFocused: function (): boolean { - updateRam("isFocused"); - helper.checkSingularityAccess("isFocused"); - return player.focus; - }, - setFocus: function (_focus: unknown): boolean { - updateRam("setFocus"); - const focus = helper.boolean(_focus); - helper.checkSingularityAccess("setFocus"); - if (!player.isWorking) { - throw helper.makeRuntimeErrorMsg("setFocus", "Not currently working"); - } - if ( - !( - player.workType == CONSTANTS.WorkTypeFaction || - player.workType == CONSTANTS.WorkTypeCompany || - player.workType == CONSTANTS.WorkTypeCompanyPartTime || - player.workType == CONSTANTS.WorkTypeCreateProgram || - player.workType == CONSTANTS.WorkTypeStudyClass - ) - ) { - throw helper.makeRuntimeErrorMsg("setFocus", "Cannot change focus for current job"); - } - if (!player.focus && focus) { - player.startFocusing(); - Router.toWork(); - return true; - } else if (player.focus && !focus) { - player.stopFocusing(); - Router.toTerminal(); - return true; - } - return false; - }, - getStats: function (): PlayerSkills { - updateRam("getStats"); - helper.checkSingularityAccess("getStats"); - workerScript.log("getStats", () => `getStats is deprecated, please use getplayer`); - return { - hacking: player.hacking, - strength: player.strength, - defense: player.defense, - dexterity: player.dexterity, - agility: player.agility, - charisma: player.charisma, - intelligence: player.intelligence, - }; - }, - getCharacterInformation: function (): CharacterInfo { - updateRam("getCharacterInformation"); - helper.checkSingularityAccess("getCharacterInformation"); - workerScript.log("getCharacterInformation", () => `getCharacterInformation is deprecated, please use getplayer`); + return false; + }, + manualHack: (_ctx: NetscriptContext) => + function (): Promise { + _ctx.helper.checkSingularityAccess(); + const server = player.getCurrentServer(); + return _ctx.helper.hack(server.hostname, true); + }, + installBackdoor: (_ctx: NetscriptContext) => + function (): Promise { + _ctx.helper.checkSingularityAccess(); + const baseserver = player.getCurrentServer(); + if (!(baseserver instanceof Server)) { + workerScript.log("installBackdoor", () => "cannot backdoor this kind of server"); + return Promise.resolve(); + } + const server = baseserver as Server; + const installTime = (calculateHackingTime(server, player) / 4) * 1000; - return { - bitnode: player.bitNodeN, - city: player.city, - factions: player.factions.slice(), - hp: player.hp, - jobs: Object.keys(player.jobs), - jobTitles: Object.values(player.jobs), - maxHp: player.max_hp, - mult: { - agility: player.agility_mult, - agilityExp: player.agility_exp_mult, + // No root access or skill level too low + const canHack = netscriptCanHack(server, player); + if (!canHack.res) { + throw _ctx.helper.makeRuntimeErrorMsg(canHack.msg || ""); + } + + workerScript.log( + "installBackdoor", + () => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`, + ); + + return netscriptDelay(installTime, workerScript).then(function () { + workerScript.log("installBackdoor", () => `Successfully installed backdoor on '${server.hostname}'`); + + server.backdoorInstalled = true; + + if (SpecialServers.WorldDaemon === server.hostname) { + Router.toBitVerse(false, false); + } + return Promise.resolve(); + }); + }, + isFocused: (_ctx: NetscriptContext) => + function (): boolean { + _ctx.helper.checkSingularityAccess(); + return player.focus; + }, + setFocus: (_ctx: NetscriptContext) => + function (_focus: unknown): boolean { + const focus = _ctx.helper.boolean(_focus); + _ctx.helper.checkSingularityAccess(); + if (!player.isWorking) { + throw _ctx.helper.makeRuntimeErrorMsg("Not currently working"); + } + if ( + !( + player.workType == CONSTANTS.WorkTypeFaction || + player.workType == CONSTANTS.WorkTypeCompany || + player.workType == CONSTANTS.WorkTypeCompanyPartTime || + player.workType == CONSTANTS.WorkTypeCreateProgram || + player.workType == CONSTANTS.WorkTypeStudyClass + ) + ) { + throw _ctx.helper.makeRuntimeErrorMsg("Cannot change focus for current job"); + } + if (!player.focus && focus) { + player.startFocusing(); + Router.toWork(); + return true; + } else if (player.focus && !focus) { + player.stopFocusing(); + Router.toTerminal(); + return true; + } + return false; + }, + getStats: (_ctx: NetscriptContext) => + function (): PlayerSkills { + _ctx.helper.checkSingularityAccess(); + workerScript.log("getStats", () => `getStats is deprecated, please use getplayer`); + + return { + hacking: player.hacking, + strength: player.strength, + defense: player.defense, + dexterity: player.dexterity, + agility: player.agility, charisma: player.charisma, + intelligence: player.intelligence, + }; + }, + getCharacterInformation: (_ctx: NetscriptContext) => + function (): CharacterInfo { + _ctx.helper.checkSingularityAccess(); + workerScript.log( + "getCharacterInformation", + () => `getCharacterInformation is deprecated, please use getplayer`, + ); + + return { + bitnode: player.bitNodeN, + city: player.city, + factions: player.factions.slice(), + hp: player.hp, + jobs: Object.keys(player.jobs), + jobTitles: Object.values(player.jobs), + maxHp: player.max_hp, + mult: { + agility: player.agility_mult, + agilityExp: player.agility_exp_mult, + charisma: player.charisma, + charismaExp: player.charisma_exp, + companyRep: player.company_rep_mult, + crimeMoney: player.crime_money_mult, + crimeSuccess: player.crime_success_mult, + defense: player.defense_mult, + defenseExp: player.defense_exp_mult, + dexterity: player.dexterity_mult, + dexterityExp: player.dexterity_exp_mult, + factionRep: player.faction_rep_mult, + hacking: player.hacking_mult, + hackingExp: player.hacking_exp_mult, + strength: player.strength_mult, + strengthExp: player.strength_exp_mult, + workMoney: player.work_money_mult, + }, + timeWorked: player.timeWorked, + tor: player.hasTorRouter(), + workHackExpGain: player.workHackExpGained, + workStrExpGain: player.workStrExpGained, + workDefExpGain: player.workDefExpGained, + workDexExpGain: player.workDexExpGained, + workAgiExpGain: player.workAgiExpGained, + workChaExpGain: player.workChaExpGained, + workRepGain: player.workRepGained, + workMoneyGain: player.workMoneyGained, + hackingExp: player.hacking_exp, + strengthExp: player.strength_exp, + defenseExp: player.defense_exp, + dexterityExp: player.dexterity_exp, + agilityExp: player.agility_exp, charismaExp: player.charisma_exp, - companyRep: player.company_rep_mult, - crimeMoney: player.crime_money_mult, - crimeSuccess: player.crime_success_mult, - defense: player.defense_mult, - defenseExp: player.defense_exp_mult, - dexterity: player.dexterity_mult, - dexterityExp: player.dexterity_exp_mult, - factionRep: player.faction_rep_mult, - hacking: player.hacking_mult, - hackingExp: player.hacking_exp_mult, - strength: player.strength_mult, - strengthExp: player.strength_exp_mult, - workMoney: player.work_money_mult, - }, - timeWorked: player.timeWorked, - tor: player.hasTorRouter(), - workHackExpGain: player.workHackExpGained, - workStrExpGain: player.workStrExpGained, - workDefExpGain: player.workDefExpGained, - workDexExpGain: player.workDexExpGained, - workAgiExpGain: player.workAgiExpGained, - workChaExpGain: player.workChaExpGained, - workRepGain: player.workRepGained, - workMoneyGain: player.workMoneyGained, - hackingExp: player.hacking_exp, - strengthExp: player.strength_exp, - defenseExp: player.defense_exp, - dexterityExp: player.dexterity_exp, - agilityExp: player.agility_exp, - charismaExp: player.charisma_exp, - }; - }, - hospitalize: function (): void { - updateRam("hospitalize"); - helper.checkSingularityAccess("hospitalize"); - if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) { - workerScript.log("hospitalize", () => "Cannot go to the hospital because the player is busy."); - return; - } - player.hospitalize(); - }, - isBusy: function (): boolean { - updateRam("isBusy"); - helper.checkSingularityAccess("isBusy"); - return player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse; - }, - stopAction: function (): boolean { - updateRam("stopAction"); - helper.checkSingularityAccess("stopAction"); - if (player.isWorking) { - if (player.focus) { + }; + }, + hospitalize: (_ctx: NetscriptContext) => + function (): void { + _ctx.helper.checkSingularityAccess(); + if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) { + workerScript.log("hospitalize", () => "Cannot go to the hospital because the player is busy."); + return; + } + player.hospitalize(); + }, + isBusy: (_ctx: NetscriptContext) => + function (): boolean { + _ctx.helper.checkSingularityAccess(); + return player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse; + }, + stopAction: (_ctx: NetscriptContext) => + function (): boolean { + _ctx.helper.checkSingularityAccess(); + if (player.isWorking) { + if (player.focus) { + player.stopFocusing(); + Router.toTerminal(); + } + const txt = player.singularityStopWork(); + workerScript.log("stopAction", () => txt); + return true; + } + return false; + }, + upgradeHomeCores: (_ctx: NetscriptContext) => + function (): boolean { + _ctx.helper.checkSingularityAccess(); + + // Check if we're at max cores + const homeComputer = player.getHomeComputer(); + if (homeComputer.cpuCores >= 8) { + workerScript.log("upgradeHomeCores", () => `Your home computer is at max cores.`); + return false; + } + + const cost = player.getUpgradeHomeCoresCost(); + if (player.money < cost) { + workerScript.log( + "upgradeHomeCores", + () => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`, + ); + return false; + } + + homeComputer.cpuCores += 1; + player.loseMoney(cost, "servers"); + + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2); + workerScript.log( + "upgradeHomeCores", + () => `Purchased an additional core for home computer! It now has ${homeComputer.cpuCores} cores.`, + ); + return true; + }, + getUpgradeHomeCoresCost: (_ctx: NetscriptContext) => + function (): number { + _ctx.helper.checkSingularityAccess(); + + return player.getUpgradeHomeCoresCost(); + }, + upgradeHomeRam: (_ctx: NetscriptContext) => + function (): boolean { + _ctx.helper.checkSingularityAccess(); + + // Check if we're at max RAM + const homeComputer = player.getHomeComputer(); + if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) { + workerScript.log("upgradeHomeRam", () => `Your home computer is at max RAM.`); + return false; + } + + const cost = player.getUpgradeHomeRamCost(); + if (player.money < cost) { + workerScript.log( + "upgradeHomeRam", + () => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`, + ); + return false; + } + + homeComputer.maxRam *= 2; + player.loseMoney(cost, "servers"); + + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2); + workerScript.log( + "upgradeHomeRam", + () => + `Purchased additional RAM for home computer! It now has ${numeralWrapper.formatRAM( + homeComputer.maxRam, + )} of RAM.`, + ); + return true; + }, + getUpgradeHomeRamCost: (_ctx: NetscriptContext) => + function (): number { + _ctx.helper.checkSingularityAccess(); + + return player.getUpgradeHomeRamCost(); + }, + workForCompany: (_ctx: NetscriptContext) => + function (_companyName: unknown, _focus: unknown = true): boolean { + let companyName = _ctx.helper.string("companyName", _companyName); + const focus = _ctx.helper.boolean(_focus); + _ctx.helper.checkSingularityAccess(); + + // Sanitize input + if (companyName == null) { + companyName = player.companyName; + } + + // Make sure its a valid company + if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) { + workerScript.log("workForCompany", () => `Invalid company: '${companyName}'`); + return false; + } + + // Make sure player is actually employed at the comapny + if (!Object.keys(player.jobs).includes(companyName)) { + workerScript.log("workForCompany", () => `You do not have a job at '${companyName}'`); + return false; + } + + // Check to make sure company position data is valid + const companyPositionName = player.jobs[companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) { + workerScript.log("workForCompany", () => "You do not have a job"); + return false; + } + + const wasFocused = player.focus; + if (player.isWorking) { + const txt = player.singularityStopWork(); + workerScript.log("workForCompany", () => txt); + } + + if (companyPosition.isPartTimeJob()) { + player.startWorkPartTime(companyName); + } else { + player.startWork(companyName); + } + + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocused) { player.stopFocusing(); Router.toTerminal(); } - const txt = player.singularityStopWork(); - workerScript.log("stopAction", () => txt); + workerScript.log( + "workForCompany", + () => `Began working at '${player.companyName}' as a '${companyPositionName}'`, + ); return true; - } - return false; - }, - upgradeHomeCores: function (): boolean { - updateRam("upgradeHomeCores"); - helper.checkSingularityAccess("upgradeHomeCores"); + }, + applyToCompany: (_ctx: NetscriptContext) => + function (_companyName: unknown, _field: unknown): boolean { + const companyName = _ctx.helper.string("companyName", _companyName); + const field = _ctx.helper.string("field", _field); + _ctx.helper.checkSingularityAccess(); + getCompany(_ctx, companyName); - // Check if we're at max cores - const homeComputer = player.getHomeComputer(); - if (homeComputer.cpuCores >= 8) { - workerScript.log("upgradeHomeCores", () => `Your home computer is at max cores.`); - return false; - } - - const cost = player.getUpgradeHomeCoresCost(); - if (player.money < cost) { - workerScript.log( - "upgradeHomeCores", - () => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`, - ); - return false; - } - - homeComputer.cpuCores += 1; - player.loseMoney(cost, "servers"); - - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2); - workerScript.log( - "upgradeHomeCores", - () => `Purchased an additional core for home computer! It now has ${homeComputer.cpuCores} cores.`, - ); - return true; - }, - getUpgradeHomeCoresCost: function (): number { - updateRam("getUpgradeHomeCoresCost"); - helper.checkSingularityAccess("getUpgradeHomeCoresCost"); - - return player.getUpgradeHomeCoresCost(); - }, - upgradeHomeRam: function (): boolean { - updateRam("upgradeHomeRam"); - helper.checkSingularityAccess("upgradeHomeRam"); - - // Check if we're at max RAM - const homeComputer = player.getHomeComputer(); - if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) { - workerScript.log("upgradeHomeRam", () => `Your home computer is at max RAM.`); - return false; - } - - const cost = player.getUpgradeHomeRamCost(); - if (player.money < cost) { - workerScript.log( - "upgradeHomeRam", - () => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`, - ); - return false; - } - - homeComputer.maxRam *= 2; - player.loseMoney(cost, "servers"); - - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 2); - workerScript.log( - "upgradeHomeRam", - () => - `Purchased additional RAM for home computer! It now has ${numeralWrapper.formatRAM( - homeComputer.maxRam, - )} of RAM.`, - ); - return true; - }, - getUpgradeHomeRamCost: function (): number { - updateRam("getUpgradeHomeRamCost"); - helper.checkSingularityAccess("getUpgradeHomeRamCost"); - - return player.getUpgradeHomeRamCost(); - }, - workForCompany: function (_companyName: unknown, _focus: unknown = true): boolean { - updateRam("workForCompany"); - let companyName = helper.string("workForCompany", "companyName", _companyName); - const focus = helper.boolean(_focus); - helper.checkSingularityAccess("workForCompany"); - - // Sanitize input - if (companyName == null) { - companyName = player.companyName; - } - - // Make sure its a valid company - if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) { - workerScript.log("workForCompany", () => `Invalid company: '${companyName}'`); - return false; - } - - // Make sure player is actually employed at the comapny - if (!Object.keys(player.jobs).includes(companyName)) { - workerScript.log("workForCompany", () => `You do not have a job at '${companyName}'`); - return false; - } - - // Check to make sure company position data is valid - const companyPositionName = player.jobs[companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) { - workerScript.log("workForCompany", () => "You do not have a job"); - return false; - } - - const wasFocused = player.focus; - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("workForCompany", () => txt); - } - - if (companyPosition.isPartTimeJob()) { - player.startWorkPartTime(companyName); - } else { - player.startWork(companyName); - } - - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocused) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log( - "workForCompany", - () => `Began working at '${player.companyName}' as a '${companyPositionName}'`, - ); - return true; - }, - applyToCompany: function (_companyName: unknown, _field: unknown): boolean { - updateRam("applyToCompany"); - const companyName = helper.string("applyToCompany", "companyName", _companyName); - const field = helper.string("applyToCompany", "field", _field); - helper.checkSingularityAccess("applyToCompany"); - getCompany("applyToCompany", companyName); - - player.location = companyName as LocationName; - let res; - switch (field.toLowerCase()) { - case "software": - res = player.applyForSoftwareJob(true); - break; - case "software consultant": - res = player.applyForSoftwareConsultantJob(true); - break; - case "it": - res = player.applyForItJob(true); - break; - case "security engineer": - res = player.applyForSecurityEngineerJob(true); - break; - case "network engineer": - res = player.applyForNetworkEngineerJob(true); - break; - case "business": - res = player.applyForBusinessJob(true); - break; - case "business consultant": - res = player.applyForBusinessConsultantJob(true); - break; - case "security": - res = player.applyForSecurityJob(true); - break; - case "agent": - res = player.applyForAgentJob(true); - break; - case "employee": - res = player.applyForEmployeeJob(true); - break; - case "part-time employee": - res = player.applyForPartTimeEmployeeJob(true); - break; - case "waiter": - res = player.applyForWaiterJob(true); - break; - case "part-time waiter": - res = player.applyForPartTimeWaiterJob(true); - break; - default: - workerScript.log("applyToCompany", () => `Invalid job: '${field}'.`); - return false; - } - // TODO https://github.com/danielyxie/bitburner/issues/1378 - // The player object's applyForJob function can return string with special error messages - // if (isString(res)) { - // workerScript.log("applyToCompany",()=> res); - // return false; - // } - if (res) { - workerScript.log( - "applyToCompany", - () => `You were offered a new job at '${companyName}' as a '${player.jobs[companyName]}'`, - ); - } else { - workerScript.log( - "applyToCompany", - () => `You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`, - ); - } - return res; - }, - getCompanyRep: function (_companyName: unknown): number { - updateRam("getCompanyRep"); - const companyName = helper.string("getCompanyRep", "companyName", _companyName); - helper.checkSingularityAccess("getCompanyRep"); - const company = getCompany("getCompanyRep", companyName); - return company.playerReputation; - }, - getCompanyFavor: function (_companyName: unknown): number { - updateRam("getCompanyFavor"); - const companyName = helper.string("getCompanyFavor", "companyName", _companyName); - helper.checkSingularityAccess("getCompanyFavor"); - const company = getCompany("getCompanyFavor", companyName); - return company.favor; - }, - getCompanyFavorGain: function (_companyName: unknown): number { - updateRam("getCompanyFavorGain"); - const companyName = helper.string("getCompanyFavorGain", "companyName", _companyName); - helper.checkSingularityAccess("getCompanyFavorGain"); - const company = getCompany("getCompanyFavorGain", companyName); - return company.getFavorGain(); - }, - checkFactionInvitations: function (): string[] { - helper.updateDynamicRam("checkFactionInvitations", getRamCost(player, "checkFactionInvitations")); - helper.checkSingularityAccess("checkFactionInvitations"); - // Make a copy of player.factionInvitations - return player.factionInvitations.slice(); - }, - joinFaction: function (_facName: unknown): boolean { - updateRam("joinFaction"); - const facName = helper.string("joinFaction", "facName", _facName); - helper.checkSingularityAccess("joinFaction"); - getFaction("joinFaction", facName); - - if (!player.factionInvitations.includes(facName)) { - workerScript.log("joinFaction", () => `You have not been invited by faction '${facName}'`); - return false; - } - const fac = Factions[facName]; - joinFaction(fac); - - // Update Faction Invitation list to account for joined + banned factions - for (let i = 0; i < player.factionInvitations.length; ++i) { - if (player.factionInvitations[i] == facName || Factions[player.factionInvitations[i]].isBanned) { - player.factionInvitations.splice(i, 1); - i--; + player.location = companyName as LocationName; + let res; + switch (field.toLowerCase()) { + case "software": + res = player.applyForSoftwareJob(true); + break; + case "software consultant": + res = player.applyForSoftwareConsultantJob(true); + break; + case "it": + res = player.applyForItJob(true); + break; + case "security engineer": + res = player.applyForSecurityEngineerJob(true); + break; + case "network engineer": + res = player.applyForNetworkEngineerJob(true); + break; + case "business": + res = player.applyForBusinessJob(true); + break; + case "business consultant": + res = player.applyForBusinessConsultantJob(true); + break; + case "security": + res = player.applyForSecurityJob(true); + break; + case "agent": + res = player.applyForAgentJob(true); + break; + case "employee": + res = player.applyForEmployeeJob(true); + break; + case "part-time employee": + res = player.applyForPartTimeEmployeeJob(true); + break; + case "waiter": + res = player.applyForWaiterJob(true); + break; + case "part-time waiter": + res = player.applyForPartTimeWaiterJob(true); + break; + default: + workerScript.log("applyToCompany", () => `Invalid job: '${field}'.`); + return false; } - } - player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 5); - workerScript.log("joinFaction", () => `Joined the '${facName}' faction.`); - return true; - }, - workForFaction: function (_facName: unknown, _type: unknown, _focus: unknown = true): boolean { - updateRam("workForFaction"); - const facName = helper.string("workForFaction", "facName", _facName); - const type = helper.string("workForFaction", "type", _type); - const focus = helper.boolean(_focus); - helper.checkSingularityAccess("workForFaction"); - getFaction("workForFaction", facName); + // TODO https://github.com/danielyxie/bitburner/issues/1378 + // The player object's applyForJob function can return string with special error messages + // if (isString(res)) { + // workerScript.log("applyToCompany",()=> res); + // return false; + // } + if (res) { + workerScript.log( + "applyToCompany", + () => `You were offered a new job at '${companyName}' as a '${player.jobs[companyName]}'`, + ); + } else { + workerScript.log( + "applyToCompany", + () => `You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`, + ); + } + return res; + }, + getCompanyRep: (_ctx: NetscriptContext) => + function (_companyName: unknown): number { + const companyName = _ctx.helper.string("companyName", _companyName); + _ctx.helper.checkSingularityAccess(); + const company = getCompany(_ctx, companyName); + return company.playerReputation; + }, + getCompanyFavor: (_ctx: NetscriptContext) => + function (_companyName: unknown): number { + const companyName = _ctx.helper.string("companyName", _companyName); + _ctx.helper.checkSingularityAccess(); + const company = getCompany(_ctx, companyName); + return company.favor; + }, + getCompanyFavorGain: (_ctx: NetscriptContext) => + function (_companyName: unknown): number { + const companyName = _ctx.helper.string("companyName", _companyName); + _ctx.helper.checkSingularityAccess(); + const company = getCompany(_ctx, companyName); + return company.getFavorGain(); + }, + checkFactionInvitations: (_ctx: NetscriptContext) => + function (): string[] { + _ctx.helper.checkSingularityAccess(); + // Make a copy of player.factionInvitations + return player.factionInvitations.slice(); + }, + joinFaction: (_ctx: NetscriptContext) => + function (_facName: unknown): boolean { + const facName = _ctx.helper.string("facName", _facName); + _ctx.helper.checkSingularityAccess(); + getFaction(_ctx, facName); - // if the player is in a gang and the target faction is any of the gang faction, fail - if (player.inGang() && AllGangs[facName] !== undefined) { - workerScript.log("workForFaction", () => `Faction '${facName}' does not offer work at the moment.`); - return false; - } - - if (!player.factions.includes(facName)) { - workerScript.log("workForFaction", () => `You are not a member of '${facName}'`); - return false; - } - - const wasFocusing = player.focus; - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("workForFaction", () => txt); - } - - const fac = Factions[facName]; - // Arrays listing factions that allow each time of work - - switch (type.toLowerCase()) { - case "hacking": - case "hacking contracts": - case "hackingcontracts": - if (!FactionInfos[fac.name].offerHackingWork) { - workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with hacking contracts.`); - return false; - } - player.startFactionHackWork(fac); - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log("workForFaction", () => `Started carrying out hacking contracts for '${fac.name}'`); - return true; - case "field": - case "fieldwork": - case "field work": - if (!FactionInfos[fac.name].offerFieldWork) { - workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with field missions.`); - return false; - } - player.startFactionFieldWork(fac); - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log("workForFaction", () => `Started carrying out field missions for '${fac.name}'`); - return true; - case "security": - case "securitywork": - case "security work": - if (!FactionInfos[fac.name].offerSecurityWork) { - workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with security work.`); - return false; - } - player.startFactionSecurityWork(fac); - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log("workForFaction", () => `Started carrying out security work for '${fac.name}'`); - return true; - default: - workerScript.log("workForFaction", () => `Invalid work type: '${type}`); + if (!player.factionInvitations.includes(facName)) { + workerScript.log("joinFaction", () => `You have not been invited by faction '${facName}'`); return false; - } - return true; - }, - getFactionRep: function (_facName: unknown): number { - updateRam("getFactionRep"); - const facName = helper.string("getFactionRep", "facName", _facName); - helper.checkSingularityAccess("getFactionRep"); - const faction = getFaction("getFactionRep", facName); - return faction.playerReputation; - }, - getFactionFavor: function (_facName: unknown): number { - updateRam("getFactionFavor"); - const facName = helper.string("getFactionRep", "facName", _facName); - helper.checkSingularityAccess("getFactionFavor"); - const faction = getFaction("getFactionFavor", facName); - return faction.favor; - }, - getFactionFavorGain: function (_facName: unknown): number { - updateRam("getFactionFavorGain"); - const facName = helper.string("getFactionFavorGain", "facName", _facName); - helper.checkSingularityAccess("getFactionFavorGain"); - const faction = getFaction("getFactionFavorGain", facName); - return faction.getFavorGain(); - }, - donateToFaction: function (_facName: unknown, _amt: unknown): boolean { - updateRam("donateToFaction"); - const facName = helper.string("donateToFaction", "facName", _facName); - const amt = helper.number("donateToFaction", "amt", _amt); - helper.checkSingularityAccess("donateToFaction"); - const faction = getFaction("donateToFaction", facName); - if (!player.factions.includes(faction.name)) { - workerScript.log("donateToFaction", () => `You can't donate to '${facName}' because you aren't a member`); - return false; - } - if (player.inGang() && faction.name === player.getGangFaction().name) { - workerScript.log( - "donateToFaction", - () => `You can't donate to '${facName}' because youre managing a gang for it`, - ); - return false; - } - if (typeof amt !== "number" || amt <= 0 || isNaN(amt)) { - workerScript.log("donateToFaction", () => `Invalid donation amount: '${amt}'.`); - return false; - } - if (player.money < amt) { - workerScript.log( - "donateToFaction", - () => `You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${facName}'`, - ); - return false; - } - const repNeededToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction); - if (faction.favor < repNeededToDonate) { + } + const fac = Factions[facName]; + joinFaction(fac); + + // Update Faction Invitation list to account for joined + banned factions + for (let i = 0; i < player.factionInvitations.length; ++i) { + if (player.factionInvitations[i] == facName || Factions[player.factionInvitations[i]].isBanned) { + player.factionInvitations.splice(i, 1); + i--; + } + } + player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 5); + workerScript.log("joinFaction", () => `Joined the '${facName}' faction.`); + return true; + }, + workForFaction: (_ctx: NetscriptContext) => + function (_facName: unknown, _type: unknown, _focus: unknown = true): boolean { + const facName = _ctx.helper.string("facName", _facName); + const type = _ctx.helper.string("type", _type); + const focus = _ctx.helper.boolean(_focus); + _ctx.helper.checkSingularityAccess(); + getFaction(_ctx, facName); + + // if the player is in a gang and the target faction is any of the gang faction, fail + if (player.inGang() && AllGangs[facName] !== undefined) { + workerScript.log("workForFaction", () => `Faction '${facName}' does not offer work at the moment.`); + return false; + } + + if (!player.factions.includes(facName)) { + workerScript.log("workForFaction", () => `You are not a member of '${facName}'`); + return false; + } + + const wasFocusing = player.focus; + if (player.isWorking) { + const txt = player.singularityStopWork(); + workerScript.log("workForFaction", () => txt); + } + + const fac = Factions[facName]; + // Arrays listing factions that allow each time of work + + switch (type.toLowerCase()) { + case "hacking": + case "hacking contracts": + case "hackingcontracts": + if (!FactionInfos[fac.name].offerHackingWork) { + workerScript.log( + "workForFaction", + () => `Faction '${fac.name}' do not need help with hacking contracts.`, + ); + return false; + } + player.startFactionHackWork(fac); + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } + workerScript.log("workForFaction", () => `Started carrying out hacking contracts for '${fac.name}'`); + return true; + case "field": + case "fieldwork": + case "field work": + if (!FactionInfos[fac.name].offerFieldWork) { + workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with field missions.`); + return false; + } + player.startFactionFieldWork(fac); + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } + workerScript.log("workForFaction", () => `Started carrying out field missions for '${fac.name}'`); + return true; + case "security": + case "securitywork": + case "security work": + if (!FactionInfos[fac.name].offerSecurityWork) { + workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with security work.`); + return false; + } + player.startFactionSecurityWork(fac); + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } + workerScript.log("workForFaction", () => `Started carrying out security work for '${fac.name}'`); + return true; + default: + workerScript.log("workForFaction", () => `Invalid work type: '${type}`); + return false; + } + return true; + }, + getFactionRep: (_ctx: NetscriptContext) => + function (_facName: unknown): number { + const facName = _ctx.helper.string("facName", _facName); + _ctx.helper.checkSingularityAccess(); + const faction = getFaction(_ctx, facName); + return faction.playerReputation; + }, + getFactionFavor: (_ctx: NetscriptContext) => + function (_facName: unknown): number { + const facName = _ctx.helper.string("facName", _facName); + _ctx.helper.checkSingularityAccess(); + const faction = getFaction(_ctx, facName); + return faction.favor; + }, + getFactionFavorGain: (_ctx: NetscriptContext) => + function (_facName: unknown): number { + const facName = _ctx.helper.string("facName", _facName); + _ctx.helper.checkSingularityAccess(); + const faction = getFaction(_ctx, facName); + return faction.getFavorGain(); + }, + donateToFaction: (_ctx: NetscriptContext) => + function (_facName: unknown, _amt: unknown): boolean { + const facName = _ctx.helper.string("facName", _facName); + const amt = _ctx.helper.number("amt", _amt); + _ctx.helper.checkSingularityAccess(); + const faction = getFaction(_ctx, facName); + if (!player.factions.includes(faction.name)) { + workerScript.log("donateToFaction", () => `You can't donate to '${facName}' because you aren't a member`); + return false; + } + if (player.inGang() && faction.name === player.getGangFaction().name) { + workerScript.log( + "donateToFaction", + () => `You can't donate to '${facName}' because youre managing a gang for it`, + ); + return false; + } + if (typeof amt !== "number" || amt <= 0 || isNaN(amt)) { + workerScript.log("donateToFaction", () => `Invalid donation amount: '${amt}'.`); + return false; + } + if (player.money < amt) { + workerScript.log( + "donateToFaction", + () => `You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${facName}'`, + ); + return false; + } + const repNeededToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction); + if (faction.favor < repNeededToDonate) { + workerScript.log( + "donateToFaction", + () => + `You do not have enough favor to donate to this faction. Have ${faction.favor}, need ${repNeededToDonate}`, + ); + return false; + } + const repGain = (amt / CONSTANTS.DonateMoneyToRepDivisor) * player.faction_rep_mult; + faction.playerReputation += repGain; + player.loseMoney(amt, "other"); workerScript.log( "donateToFaction", () => - `You do not have enough favor to donate to this faction. Have ${faction.favor}, need ${repNeededToDonate}`, + `${numeralWrapper.formatMoney(amt)} donated to '${facName}' for ${numeralWrapper.formatReputation( + repGain, + )} reputation`, ); - return false; - } - const repGain = (amt / CONSTANTS.DonateMoneyToRepDivisor) * player.faction_rep_mult; - faction.playerReputation += repGain; - player.loseMoney(amt, "other"); - workerScript.log( - "donateToFaction", - () => - `${numeralWrapper.formatMoney(amt)} donated to '${facName}' for ${numeralWrapper.formatReputation( - repGain, - )} reputation`, - ); - return true; - }, - createProgram: function (_programName: unknown, _focus: unknown = true): boolean { - updateRam("createProgram"); - const programName = helper.string("createProgram", "programName", _programName).toLowerCase(); - const focus = helper.boolean(_focus); - helper.checkSingularityAccess("createProgram"); + return true; + }, + createProgram: (_ctx: NetscriptContext) => + function (_programName: unknown, _focus: unknown = true): boolean { + const programName = _ctx.helper.string("programName", _programName).toLowerCase(); + const focus = _ctx.helper.boolean(_focus); + _ctx.helper.checkSingularityAccess(); - const wasFocusing = player.focus; - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("createProgram", () => txt); - } + const wasFocusing = player.focus; + if (player.isWorking) { + const txt = player.singularityStopWork(); + workerScript.log("createProgram", () => txt); + } - const p = Object.values(Programs).find((p) => p.name.toLowerCase() === programName); + const p = Object.values(Programs).find((p) => p.name.toLowerCase() === programName); - if (p == null) { - workerScript.log("createProgram", () => `The specified program does not exist: '${programName}`); - return false; - } + if (p == null) { + workerScript.log("createProgram", () => `The specified program does not exist: '${programName}`); + return false; + } - if (player.hasProgram(p.name)) { - workerScript.log("createProgram", () => `You already have the '${p.name}' program`); - return false; - } + if (player.hasProgram(p.name)) { + workerScript.log("createProgram", () => `You already have the '${p.name}' program`); + return false; + } - const create = p.create; - if (create === null) { - workerScript.log("createProgram", () => `You cannot create the '${p.name}' program`); - return false; - } + const create = p.create; + if (create === null) { + workerScript.log("createProgram", () => `You cannot create the '${p.name}' program`); + return false; + } - if (!create.req(player)) { - workerScript.log( - "createProgram", - () => `Hacking level is too low to create '${p.name}' (level ${create.level} req)`, - ); - return false; - } + if (!create.req(player)) { + workerScript.log( + "createProgram", + () => `Hacking level is too low to create '${p.name}' (level ${create.level} req)`, + ); + return false; + } - player.startCreateProgramWork(p.name, create.time, create.level); - if (focus) { - player.startFocusing(); - Router.toWork(); - } else if (wasFocusing) { - player.stopFocusing(); - Router.toTerminal(); - } - workerScript.log("createProgram", () => `Began creating program: '${programName}'`); - return true; - }, - commitCrime: function (_crimeRoughName: unknown): number { - updateRam("commitCrime"); - const crimeRoughName = helper.string("commitCrime", "crimeRoughName", _crimeRoughName); - helper.checkSingularityAccess("commitCrime"); + player.startCreateProgramWork(p.name, create.time, create.level); + if (focus) { + player.startFocusing(); + Router.toWork(); + } else if (wasFocusing) { + player.stopFocusing(); + Router.toTerminal(); + } + workerScript.log("createProgram", () => `Began creating program: '${programName}'`); + return true; + }, + commitCrime: (_ctx: NetscriptContext) => + function (_crimeRoughName: unknown): number { + const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName); + _ctx.helper.checkSingularityAccess(); - if (player.isWorking) { - const txt = player.singularityStopWork(); - workerScript.log("commitCrime", () => txt); - } + if (player.isWorking) { + const txt = player.singularityStopWork(); + workerScript.log("commitCrime", () => txt); + } - // Set Location to slums - player.gotoLocation(LocationName.Slums); + // Set Location to slums + player.gotoLocation(LocationName.Slums); - const crime = findCrime(crimeRoughName.toLowerCase()); - if (crime == null) { - // couldn't find crime - throw helper.makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`); - } - workerScript.log("commitCrime", () => `Attempting to commit ${crime.name}...`); - return crime.commit(Router, player, 1, workerScript); - }, - getCrimeChance: function (_crimeRoughName: unknown): number { - updateRam("getCrimeChance"); - const crimeRoughName = helper.string("getCrimeChance", "crimeRoughName", _crimeRoughName); - helper.checkSingularityAccess("getCrimeChance"); + const crime = findCrime(crimeRoughName.toLowerCase()); + if (crime == null) { + // couldn't find crime + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid crime: '${crimeRoughName}'`); + } + workerScript.log("commitCrime", () => `Attempting to commit ${crime.name}...`); + return crime.commit(Router, player, 1, workerScript); + }, + getCrimeChance: (_ctx: NetscriptContext) => + function (_crimeRoughName: unknown): number { + const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName); + _ctx.helper.checkSingularityAccess(); - const crime = findCrime(crimeRoughName.toLowerCase()); - if (crime == null) { - throw helper.makeRuntimeErrorMsg("getCrimeChance", `Invalid crime: ${crimeRoughName}`); - } + const crime = findCrime(crimeRoughName.toLowerCase()); + if (crime == null) { + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid crime: ${crimeRoughName}`); + } - return crime.successRate(player); - }, - getCrimeStats: function (_crimeRoughName: unknown): CrimeStats { - updateRam("getCrimeStats"); - const crimeRoughName = helper.string("getCrimeStats", "crimeRoughName", _crimeRoughName); - helper.checkSingularityAccess("getCrimeStats"); + return crime.successRate(player); + }, + getCrimeStats: (_ctx: NetscriptContext) => + function (_crimeRoughName: unknown): CrimeStats { + const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName); + _ctx.helper.checkSingularityAccess(); - const crime = findCrime(crimeRoughName.toLowerCase()); - if (crime == null) { - throw helper.makeRuntimeErrorMsg("getCrimeStats", `Invalid crime: ${crimeRoughName}`); - } + const crime = findCrime(crimeRoughName.toLowerCase()); + if (crime == null) { + throw _ctx.helper.makeRuntimeErrorMsg(`Invalid crime: ${crimeRoughName}`); + } - return Object.assign({}, crime); - }, - getDarkwebPrograms: function (): string[] { - updateRam("getDarkwebPrograms"); - helper.checkSingularityAccess("getDarkwebPrograms"); + return Object.assign({}, crime); + }, + getDarkwebPrograms: (_ctx: NetscriptContext) => + function (): string[] { + _ctx.helper.checkSingularityAccess(); - // If we don't have Tor, log it and return [] (empty list) - if (!player.hasTorRouter()) { - workerScript.log("getDarkwebPrograms", () => "You do not have the TOR router."); - return []; - } - return Object.values(DarkWebItems).map((p) => p.program); - }, - getDarkwebProgramCost: function (_programName: unknown): number { - updateRam("getDarkwebProgramCost"); - const programName = helper.string("getDarkwebProgramCost", "programName", _programName).toLowerCase(); - helper.checkSingularityAccess("getDarkwebProgramCost"); + // If we don't have Tor, log it and return [] (empty list) + if (!player.hasTorRouter()) { + workerScript.log("getDarkwebPrograms", () => "You do not have the TOR router."); + return []; + } + return Object.values(DarkWebItems).map((p) => p.program); + }, + getDarkwebProgramCost: (_ctx: NetscriptContext) => + function (_programName: unknown): number { + const programName = _ctx.helper.string("programName", _programName).toLowerCase(); + _ctx.helper.checkSingularityAccess(); - // If we don't have Tor, log it and return -1 - if (!player.hasTorRouter()) { - workerScript.log("getDarkwebProgramCost", () => "You do not have the TOR router."); - // returning -1 rather than throwing an error to be consistent with purchaseProgram - // which returns false if tor has - return -1; - } + // If we don't have Tor, log it and return -1 + if (!player.hasTorRouter()) { + workerScript.log("getDarkwebProgramCost", () => "You do not have the TOR router."); + // returning -1 rather than throwing an error to be consistent with purchaseProgram + // which returns false if tor has + return -1; + } - const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName); + const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName); - // If the program doesn't exist, throw an error. The reasoning here is that the 99% case is that - // the player will be using this in automation scripts, and if they're asking for a program that - // doesn't exist, it's the first time they've run the script. So throw an error to let them know - // that they need to fix it. - if (item == null) { - throw helper.makeRuntimeErrorMsg( - "getDarkwebProgramCost", - `No such exploit ('${programName}') found on the darkweb! ` + - `\nThis function is not case-sensitive. Did you perhaps forget .exe at the end?`, - ); - } + // If the program doesn't exist, throw an error. The reasoning here is that the 99% case is that + // the player will be using this in automation scripts, and if they're asking for a program that + // doesn't exist, it's the first time they've run the script. So throw an error to let them know + // that they need to fix it. + if (item == null) { + throw _ctx.helper.makeRuntimeErrorMsg( + `No such exploit ('${programName}') found on the darkweb! ` + + `\nThis function is not case-sensitive. Did you perhaps forget .exe at the end?`, + ); + } - if (player.hasProgram(item.program)) { - workerScript.log("getDarkwebProgramCost", () => `You already have the '${item.program}' program`); - return 0; - } - return item.price; - }, + if (player.hasProgram(item.program)) { + workerScript.log("getDarkwebProgramCost", () => `You already have the '${item.program}' program`); + return 0; + } + return item.price; + }, }; }