diff --git a/doc/source/netscript/netscriptsingularityfunctions.rst b/doc/source/netscript/netscriptsingularityfunctions.rst
index d36d901ae..b9ed4ea56 100644
--- a/doc/source/netscript/netscriptsingularityfunctions.rst
+++ b/doc/source/netscript/netscriptsingularityfunctions.rst
@@ -16,8 +16,6 @@ You can use the Singularity Functions in other BitNodes if and only if you have
Source-File 4 will open up additional Singularity Functions that you can use in other BitNodes. If your Source-File 4 is upgraded all the way to
level 3, then you will be able to access all of the Singularity Functions.
-Note that Singularity Functions require twice as much RAM outside of BitNode-4
-
.. toctree::
:caption: Functions:
diff --git a/doc/source/netscript/tixapi/getStockSaleGain.rst b/doc/source/netscript/tixapi/getStockSaleGain.rst
index 09c81fdd2..4716f6514 100644
--- a/doc/source/netscript/tixapi/getStockSaleGain.rst
+++ b/doc/source/netscript/tixapi/getStockSaleGain.rst
@@ -4,7 +4,7 @@ getStockSaleGain() Netscript Function
.. js:function:: getStockSaleGain(sym, shares, posType)
:param string sym: Stock symbol
- :param number shares: Number of shares to purchase
+ :param number shares: Number of shares to sell
:param string posType: Specifies whether the order is a "Long" or "Short" position.
The values "L" or "S" can also be used.
:RAM cost: 2 GB
diff --git a/src/Hacknet/HacknetHelpers.jsx b/src/Hacknet/HacknetHelpers.jsx
index f40934c96..6172593e2 100644
--- a/src/Hacknet/HacknetHelpers.jsx
+++ b/src/Hacknet/HacknetHelpers.jsx
@@ -1,3 +1,13 @@
+/**
+ * Generic helper/utility functions for the Hacknet mechanic:
+ * - Purchase nodes/upgrades
+ * - Calculating maximum number of upgrades
+ * - Processing Hacknet earnings
+ * - Updating Hash Manager capacity
+ * - Purchasing hash upgrades
+ *
+ * TODO Should probably split the different types of functions into their own modules
+ */
import {
HacknetNode,
BaseCostForHacknetNode,
@@ -26,7 +36,7 @@ import {
ITutorial
} from "../InteractiveTutorial";
import { Player } from "../Player";
-import { AddToAllServers, AllServers } from "../Server/AllServers";
+import { AllServers } from "../Server/AllServers";
import { GetServerByHostname } from "../Server/ServerHelpers";
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { Page, routing } from "../ui/navigationTracking";
@@ -115,7 +125,7 @@ export function getCostOfNextHacknetServer() {
return BaseCostForHacknetServer * Math.pow(mult, numOwned) * Player.hacknet_node_purchase_cost_mult;
}
-//Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node
+// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's level
export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
if (maxLevel == null) {
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
@@ -149,6 +159,7 @@ export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
return 0;
}
+// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's RAM
export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
if (maxLevel == null) {
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
@@ -177,6 +188,7 @@ export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
return 0;
}
+// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cores
export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
if (maxLevel == null) {
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
@@ -193,7 +205,7 @@ export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
return levelsToMax;
}
- //Use a binary search to find the max possible number of upgrades
+ // Use a binary search to find the max possible number of upgrades
while (min <= max) {
let curr = (min + max) / 2 | 0;
if (curr != maxLevel &&
@@ -212,6 +224,7 @@ export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
return 0;
}
+// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cache
export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
if (maxLevel == null) {
throw new Error(`getMaxNumberCacheUpgrades() called without maxLevel arg`);
diff --git a/src/Hacknet/HacknetServer.ts b/src/Hacknet/HacknetServer.ts
index 236ff06e9..591704d26 100644
--- a/src/Hacknet/HacknetServer.ts
+++ b/src/Hacknet/HacknetServer.ts
@@ -176,33 +176,28 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
return totalCost;
}
- // Process this Hacknet Server in the game loop.
- // Returns the number of hashes generated
+ // Process this Hacknet Server in the game loop. Returns the number of hashes generated
process(numCycles: number=1): number {
const seconds = numCycles * CONSTANTS.MilliPerCycle / 1000;
return this.hashRate * seconds;
}
- // Returns a boolean indicating whether the cache was successfully upgraded
upgradeCache(levels: number): void {
this.cache = Math.min(HacknetServerMaxCache, Math.round(this.cache + levels));
this.updateHashCapacity();
}
- // Returns a boolean indicating whether the number of cores was successfully upgraded
upgradeCore(levels: number, prodMult: number): void {
this.cores = Math.min(HacknetServerMaxCores, Math.round(this.cores + levels));
this.updateHashRate(prodMult);
}
- // Returns a boolean indicating whether the level was successfully upgraded
upgradeLevel(levels: number, prodMult: number): void {
this.level = Math.min(HacknetServerMaxLevel, Math.round(this.level + levels));
this.updateHashRate(prodMult);
}
- // Returns a boolean indicating whether the RAM was successfully upgraded
upgradeRam(levels: number, prodMult: number): boolean {
for (let i = 0; i < levels; ++i) {
this.maxRam *= 2;
@@ -212,10 +207,8 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
return true;
}
-
- /**
- * Whenever a script is run, we must update this server's hash rate
- */
+
+ // Whenever a script is run, we must update this server's hash rate
runScript(script: RunningScript, prodMult?: number): void {
super.runScript(script);
if (prodMult != null && typeof prodMult === "number") {
diff --git a/src/Locations/LocationsHelpers.ts b/src/Locations/LocationsHelpers.ts
index f50a27c2a..602f1d330 100644
--- a/src/Locations/LocationsHelpers.ts
+++ b/src/Locations/LocationsHelpers.ts
@@ -40,13 +40,15 @@ import { createPopupCloseButton } from "../../utils/uiHelpers/createPopupCloseBu
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
/**
- * Create a pop-up box that lets the player confirm traveling to a different city
- * If settings are configured to suppress this popup, just instantly travel
+ * Create a pop-up box that lets the player confirm traveling to a different city.
+ * If settings are configured to suppress this popup, just instantly travel.
* The actual "Travel" implementation is implemented in the UI, and is passed in
- * as an argument
+ * as an argument.
+ * @param {CityName} destination - City that the player is traveling to
+ * @param {Function} travelFn - Function that changes the player's state for traveling
*/
type TravelFunction = (to: CityName) => void;
-export function createTravelPopup(destination: CityName, travelFn: TravelFunction) {
+export function createTravelPopup(destination: CityName, travelFn: TravelFunction): void {
const cost = CONSTANTS.TravelCost;
if (Settings.SuppressTravelConfirmation) {
@@ -80,10 +82,10 @@ export function createTravelPopup(destination: CityName, travelFn: TravelFunctio
/**
* Create a pop-up box that lets the player purchase a server.
- * @param ram - Amount of RAM (GB) on server
- * @param p - Player object
+ * @param {number} ram - Amount of RAM (GB) on server
+ * @param {IPlayer} p - Player object
*/
-export function createPurchaseServerPopup(ram: number, p: IPlayer) {
+export function createPurchaseServerPopup(ram: number, p: IPlayer): void {
const cost = getPurchaseServerCost(ram);
if (cost === Infinity) {
dialogBoxCreate("Something went wrong when trying to purchase this server. Please contact developer");
@@ -111,6 +113,7 @@ export function createPurchaseServerPopup(ram: number, p: IPlayer) {
/**
* Create a popup that lets the player start a Corporation
+ * @param {IPlayer} p - Player object
*/
export function createStartCorporationPopup(p: IPlayer) {
if (!p.canAccessCorporation() || p.hasCorporation()) { return; }
@@ -172,8 +175,10 @@ export function createStartCorporationPopup(p: IPlayer) {
if (worldHeader instanceof HTMLElement) {
worldHeader.click(); worldHeader.click();
}
- dialogBoxCreate("Congratulations! You just started your own corporation with government seed money. " +
- "You can visit and manage your company in the City");
+ dialogBoxCreate(
+ "Congratulations! You just started your own corporation with government seed money. " +
+ "You can visit and manage your company in the City"
+ );
removeElementById(popupId);
return false;
}
@@ -187,21 +192,23 @@ export function createStartCorporationPopup(p: IPlayer) {
/**
* Create a popup that lets the player upgrade the cores on his/her home computer
- * @param p - Player object
+ * @param {IPlayer} p - Player object
*/
export function createUpgradeHomeCoresPopup(p: IPlayer) {
const currentCores = p.getHomeComputer().cpuCores;
if (currentCores >= 8) { return; } // Max of 8 cores
- //Cost of purchasing another cost is found by indexing this array with number of current cores
- const allCosts = [0,
- 10e9, // 1->2 Cores - 10 bn
- 250e9, // 2->3 Cores - 250 bn
- 5e12, // 3->4 Cores - 5 trillion
- 100e12, // 4->5 Cores - 100 trillion
- 1e15, // 5->6 Cores - 1 quadrillion
- 20e15, // 6->7 Cores - 20 quadrillion
- 200e15]; // 7->8 Cores - 200 quadrillion
+ // Cost of purchasing another cost is found by indexing this array with number of current cores
+ const allCosts = [
+ 0,
+ 10e9,
+ 250e9,
+ 5e12,
+ 100e12,
+ 1e15,
+ 20e15,
+ 200e15
+ ];
const cost: number = allCosts[currentCores];
const yesBtn = yesNoBoxGetYesButton();
@@ -215,8 +222,10 @@ export function createUpgradeHomeCoresPopup(p: IPlayer) {
} else {
p.loseMoney(cost);
p.getHomeComputer().cpuCores++;
- dialogBoxCreate("You purchased an additional CPU Core for your home computer! It now has " +
- p.getHomeComputer().cpuCores + " cores.");
+ dialogBoxCreate(
+ "You purchased an additional CPU Core for your home computer! It now has " +
+ p.getHomeComputer().cpuCores + " cores."
+ );
}
yesNoBoxClose();
});
@@ -226,15 +235,17 @@ export function createUpgradeHomeCoresPopup(p: IPlayer) {
yesNoBoxClose();
});
- yesNoBoxCreate("Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " +
- "lets you start with an additional Core Node in Hacking Missions.
" +
- "Purchasing an additional core (for a total of " + (p.getHomeComputer().cpuCores + 1) + ") will " +
- "cost " + numeralWrapper.formatMoney(cost));
+ yesNoBoxCreate(
+ "Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " +
+ "lets you start with an additional Core Node in Hacking Missions.
" +
+ "Purchasing an additional core (for a total of " + (p.getHomeComputer().cpuCores + 1) + ") will " +
+ "cost " + numeralWrapper.formatMoney(cost)
+ );
}
/**
* Create a popup that lets the player upgrade the RAM on his/her home computer
- * @param p - Player object
+ * @param {IPlayer} p - Player object
*/
export function createUpgradeHomeRamPopup(p: IPlayer) {
const cost: number = p.getUpgradeHomeRamCost();
@@ -255,15 +266,17 @@ export function createUpgradeHomeRamPopup(p: IPlayer) {
yesNoBoxClose();
});
- yesNoBoxCreate("Would you like to purchase additional RAM for your home computer?
" +
- "This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB.
" +
- "This will cost " + numeralWrapper.format(cost, '$0.000a'));
+ yesNoBoxCreate(
+ "Would you like to purchase additional RAM for your home computer?
" +
+ "This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB.
" +
+ "This will cost " + numeralWrapper.format(cost, '$0.000a')
+ );
}
/**
* Attempt to purchase a TOR router
- * @param p - Player object
+ * @param {IPlayer} p - Player object
*/
export function purchaseTorRouter(p: IPlayer) {
if (p.hasTorRouter()) {
@@ -285,7 +298,9 @@ export function purchaseTorRouter(p: IPlayer) {
p.getHomeComputer().serversOnNetwork.push(darkweb.ip);
darkweb.serversOnNetwork.push(p.getHomeComputer().ip);
- dialogBoxCreate("You have purchased a Tor router!
" +
- "You now have access to the dark web from your home computer
" +
- "Use the scan/scan-analyze commands to search for the dark web connection.");
+ dialogBoxCreate(
+ "You have purchased a Tor router!
" +
+ "You now have access to the dark web from your home computer
" +
+ "Use the scan/scan-analyze commands to search for the dark web connection."
+ );
}
diff --git a/src/Script/RamCalculations.js b/src/Script/RamCalculations.js
index 3013b8c2f..1d2a77823 100644
--- a/src/Script/RamCalculations.js
+++ b/src/Script/RamCalculations.js
@@ -1,4 +1,10 @@
-// Calculate a script's RAM usage
+/**
+ * Implements RAM Calculation functionality.
+ *
+ * Uses the acorn.js library to parse a script's code into an AST and
+ * recursively walk through that AST, calculating RAM usage along
+ * the way
+ */
import * as walk from "acorn-walk";
import { RamCalculationErrorCode } from "./RamCalculationErrorCodes";
@@ -15,19 +21,26 @@ const specialReferenceWHILE = "__SPECIAL_referenceWhile";
// The global scope of a script is registered under this key during parsing.
const memCheckGlobalKey = ".__GLOBAL__";
-// Calcluates the amount of RAM a script uses. Uses parsing and AST walking only,
-// rather than NetscriptEvaluator. This is useful because NetscriptJS code does
-// not work under NetscriptEvaluator.
+/**
+ * Parses code into an AST and walks through it recursively to calculate
+ * RAM usage. Also accounts for imported modules.
+ * @param {Script[]} otherScripts - All other scripts on the server. Used to account for imported scripts
+ * @param {string} codeCopy - The code being parsed
+ * @param {WorkerScript} workerScript - Object containing RAM costs of Netscript functions. Also used to
+ * keep track of what functions have/havent been accounted for
+ */
async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
try {
- // Maps dependent identifiers to their dependencies.
- //
- // The initial identifier is __SPECIAL_INITIAL_MODULE__.__GLOBAL__.
- // It depends on all the functions declared in the module, all the global scopes
- // of its imports, and any identifiers referenced in this global scope. Each
- // function depends on all the identifiers referenced internally.
- // We walk the dependency graph to calculate RAM usage, given that some identifiers
- // reference Netscript functions which have a RAM cost.
+ /**
+ * Maps dependent identifiers to their dependencies.
+ *
+ * The initial identifier is __SPECIAL_INITIAL_MODULE__.__GLOBAL__.
+ * It depends on all the functions declared in the module, all the global scopes
+ * of its imports, and any identifiers referenced in this global scope. Each
+ * function depends on all the identifiers referenced internally.
+ * We walk the dependency graph to calculate RAM usage, given that some identifiers
+ * reference Netscript functions which have a RAM cost.
+ */
let dependencyMap = {};
// Scripts we've parsed.
@@ -48,19 +61,20 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
}
}
- // Splice all the references in.
- //Spread syntax not supported in edge, use Object.assign instead
- //dependencyMap = {...dependencyMap, ...result.dependencyMap};
+ // Splice all the references in
dependencyMap = Object.assign(dependencyMap, result.dependencyMap);
}
+ // Parse the initial module, which is the "main" script that is being run
const initialModule = "__SPECIAL_INITIAL_MODULE__";
parseCode(code, initialModule);
+ // Process additional modules, which occurs if the "main" script has any imports
while (parseQueue.length > 0) {
- // Get the code from the server.
const nextModule = parseQueue.shift();
+ // Additional modules can either be imported from the web (in which case we use
+ // a dynamic import), or from other in-game scripts
let code;
if (nextModule.startsWith("https://") || nextModule.startsWith("http://")) {
try {
@@ -91,7 +105,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
}
if (script == null) {
- return RamCalculationErrorCode.ImportError; // No such script on the server
+ return RamCalculationErrorCode.ImportError; // No such script on the server
}
code = script.code;
@@ -136,10 +150,8 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
}
}
- // Check if this identifier is a function in the workerscript env.
+ // Check if this identifier is a function in the workerScript environment.
// If it is, then we need to get its RAM cost.
- //
- // TODO it would be simpler to just reference a dictionary.
try {
function applyFuncRam(func) {
if (typeof func === "function") {
@@ -170,7 +182,7 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
workerScript.loadedFns[ref] = true;
}
- // This accounts for namespaces (Bladeburner, CodingCOntract)
+ // This accounts for namespaces (Bladeburner, CodingCpntract, etc.)
let func;
if (ref in workerScript.env.vars.bladeburner) {
func = workerScript.env.vars.bladeburner[ref];
@@ -196,9 +208,12 @@ async function parseOnlyRamCalculate(otherScripts, code, workerScript) {
}
}
-// Parses one script and calculates its ram usage, for the global scope and each function.
-// Returns a cost map and a dependencyMap for the module. Returns a reference map to be joined
-// onto the main reference map, and a list of modules that need to be parsed.
+/**
+ * Helper function that parses a single script. It returns a map of all dependencies,
+ * which are items in the code's AST that potentially need to be evaluated
+ * for RAM usage calculations. It also returns an array of additional modules
+ * that need to be parsed (i.e. are 'import'ed scripts).
+ */
function parseOnlyCalculateDeps(code, currentModule) {
const ast = parse(code, {sourceType:"module", ecmaVersion: 8});
@@ -296,6 +311,12 @@ function parseOnlyCalculateDeps(code, currentModule) {
return {dependencyMap: dependencyMap, additionalModules: additionalModules};
}
+/**
+ * Calculate's a scripts RAM Usage
+ * @param {string} codeCopy - The script's code
+ * @param {Script[]} otherScripts - All other scripts on the server.
+ * Used to account for imported scripts
+ */
export async function calculateRamUsage(codeCopy, otherScripts) {
// We don't need a real WorkerScript for this. Just an object that keeps
// track of whatever's needed for RAM calculations
diff --git a/src/Script/RunningScript.ts b/src/Script/RunningScript.ts
index eca819276..59bde86b2 100644
--- a/src/Script/RunningScript.ts
+++ b/src/Script/RunningScript.ts
@@ -69,22 +69,20 @@ export class RunningScript {
if (script == null) { return; }
this.filename = script.filename;
this.args = args;
-
- this.server = script.server; //IP Address only
+ this.server = script.server;
this.ramUsage = script.ramUsage;
}
log(txt: string): void {
if (this.logs.length > Settings.MaxLogCapacity) {
- //Delete first element and add new log entry to the end.
- //TODO Eventually it might be better to replace this with circular array
- //to improve performance
this.logs.shift();
}
+
let logEntry = txt;
if (FconfSettings.ENABLE_TIMESTAMPS) {
logEntry = "[" + getTimestamp() + "] " + logEntry;
}
+
this.logs.push(logEntry);
this.logUpd = true;
}
diff --git a/src/StockMarket/BuyingAndSelling.ts b/src/StockMarket/BuyingAndSelling.ts
index 21a32313b..e628595af 100644
--- a/src/StockMarket/BuyingAndSelling.ts
+++ b/src/StockMarket/BuyingAndSelling.ts
@@ -57,7 +57,7 @@ export function buyStock(stock: Stock, shares: number, workerScript: WorkerScrip
if (totalPrice == null) { return false; }
if (Player.money.lt(totalPrice)) {
if (tixApi) {
- workerScript!.log(`ERROR: buyStock() failed because you do not have enough money to purchase this potiion. You need ${numeralWrapper.formatMoney(totalPrice)}`);
+ workerScript!.log(`ERROR: buyStock() failed because you do not have enough money to purchase this position. You need ${numeralWrapper.formatMoney(totalPrice)}`);
} else if (opts.suppressDialog !== true) {
dialogBoxCreate(`You do not have enough money to purchase this. You need ${numeralWrapper.formatMoney(totalPrice)}`);
}