Fixed comment styling for all top-level src files

This commit is contained in:
danielyxie 2019-04-12 18:22:46 -07:00 committed by danielyxie
parent df89cc5002
commit 221b81d802
20 changed files with 1149 additions and 1063 deletions

@ -32,7 +32,7 @@ import { removeElement } from "../utils/uiHelpers/removeElement";
* ... * ...
*/ */
const ActiveScriptsUI = {}; const ActiveScriptsUI = {};
const ActiveScriptsTasks = []; //Sequentially schedule the creation/deletion of UI elements const ActiveScriptsTasks = []; // Sequentially schedule the creation/deletion of UI elements
const getHeaderHtml = (server) => { const getHeaderHtml = (server) => {
// TODO: calculate the longest hostname length rather than hard coding it // TODO: calculate the longest hostname length rather than hard coding it
@ -51,7 +51,7 @@ const updateHeaderHtml = (server) => {
return; return;
} }
// convert it to a string, as that's how it's stored it will come out of the data attributes // Convert it to a string, as that's how it's stored it will come out of the data attributes
const ramPercentage = '' + roundToTwo(server.ramUsed / server.maxRam); const ramPercentage = '' + roundToTwo(server.ramUsed / server.maxRam);
if (accordion.header.dataset.ramPercentage !== ramPercentage) { if (accordion.header.dataset.ramPercentage !== ramPercentage) {
accordion.header.dataset.ramPercentage = ramPercentage; accordion.header.dataset.ramPercentage = ramPercentage;
@ -84,16 +84,18 @@ function createActiveScriptsServerPanel(server) {
header: hdr, header: hdr,
panel: panel, panel: panel,
panelList: panelScriptList, panelList: panelScriptList,
scripts: {}, //Holds references to li elements for each active script scripts: {}, // Holds references to li elements for each active script
scriptHdrs: {}, //Holds references to header elements for each active script scriptHdrs: {}, // Holds references to header elements for each active script
scriptStats: {} //Holds references to the p elements containing text for each active script scriptStats: {}, // Holds references to the p elements containing text for each active script
}; };
return li; return li;
} }
//Deletes the info for a particular server (Dropdown header + Panel with all info) /**
//in the Active Scripts page if it exists * Deletes the info for a particular server (Dropdown header + Panel with all info)
* in the Active Scripts page if it exists
*/
function deleteActiveScriptsServerPanel(server) { function deleteActiveScriptsServerPanel(server) {
let hostname = server.hostname; let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) { if (ActiveScriptsUI[hostname] == null) {
@ -101,9 +103,9 @@ function deleteActiveScriptsServerPanel(server) {
return; return;
} }
//Make sure it's empty // Make sure it's empty
if (Object.keys(ActiveScriptsUI[hostname].scripts).length > 0) { if (Object.keys(ActiveScriptsUI[hostname].scripts).length > 0) {
console.log("WARNING: Tried to delete Active Scripts Server panel that still has scripts. Aborting"); console.warn("Tried to delete Active Scripts Server panel that still has scripts. Aborting");
return; return;
} }
@ -115,7 +117,7 @@ function deleteActiveScriptsServerPanel(server) {
function addActiveScriptsItem(workerscript) { function addActiveScriptsItem(workerscript) {
var server = getServer(workerscript.serverIp); var server = getServer(workerscript.serverIp);
if (server == null) { if (server == null) {
console.log("ERROR: Invalid server IP for workerscript in addActiveScriptsItem()"); console.warn("Invalid server IP for workerscript in addActiveScriptsItem()");
return; return;
} }
let hostname = server.hostname; let hostname = server.hostname;
@ -125,7 +127,7 @@ function addActiveScriptsItem(workerscript) {
createActiveScriptsServerPanel(server); createActiveScriptsServerPanel(server);
} }
//Create the unique identifier (key) for this script // Create the unique identifier (key) for this script
var itemNameArray = ["active", "scripts", hostname, workerscript.name]; var itemNameArray = ["active", "scripts", hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) { for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(String(workerscript.args[i])); itemNameArray.push(String(workerscript.args[i]));
@ -142,8 +144,10 @@ function addActiveScriptsItem(workerscript) {
panel.classList.remove("accordion-panel"); panel.classList.remove("accordion-panel");
panel.classList.add("active-scripts-script-panel"); panel.classList.add("active-scripts-script-panel");
//Handle the constant elements on the panel that don't change after creation /**
//Threads, args, kill/log button * Handle the constant elements on the panel that don't change after creation:
* Threads, args, kill/log button
*/
panel.appendChild(createElement("p", { panel.appendChild(createElement("p", {
innerHTML: "Threads: " + workerscript.scriptRef.threads + "<br>" + innerHTML: "Threads: " + workerscript.scriptRef.threads + "<br>" +
"Args: " + arrayToString(workerscript.args) "Args: " + arrayToString(workerscript.args)
@ -176,7 +180,7 @@ function addActiveScriptsItem(workerscript) {
} }
})); }));
//Append element to list // Append element to list
ActiveScriptsUI[hostname]["panelList"].appendChild(li); ActiveScriptsUI[hostname]["panelList"].appendChild(li);
ActiveScriptsUI[hostname].scripts[itemName] = li; ActiveScriptsUI[hostname].scripts[itemName] = li;
ActiveScriptsUI[hostname].scriptHdrs[itemName] = hdr; ActiveScriptsUI[hostname].scriptHdrs[itemName] = hdr;
@ -221,11 +225,13 @@ function deleteActiveScriptsItem(workerscript) {
}.bind(null, workerscript)); }.bind(null, workerscript));
} }
//Update the ActiveScriptsItems array
function updateActiveScriptsItems(maxTasks=150) { function updateActiveScriptsItems(maxTasks=150) {
//Run tasks that need to be done sequentially (adding items, creating/deleting server panels) /**
//We'll limit this to 150 at a time in case someone decides to start a bunch of scripts all at once... * Run tasks that need to be done sequentially (adding items, creating/deleting server panels)
let numTasks = Math.min(maxTasks, ActiveScriptsTasks.length); * We'll limit this to 150 at a time for performance (in case someone decides to start a
* bunch of scripts all at once...)
*/
const numTasks = Math.min(maxTasks, ActiveScriptsTasks.length);
for (let i = 0; i < numTasks; ++i) { for (let i = 0; i < numTasks; ++i) {
let task = ActiveScriptsTasks.shift(); let task = ActiveScriptsTasks.shift();
try { try {
@ -236,8 +242,8 @@ function updateActiveScriptsItems(maxTasks=150) {
} }
} }
if (!routing.isOn(Page.ActiveScripts)) {return;} if (!routing.isOn(Page.ActiveScripts)) { return; }
var total = 0; let total = 0;
for (var i = 0; i < workerScripts.length; ++i) { for (var i = 0; i < workerScripts.length; ++i) {
try { try {
total += updateActiveScriptsItemContent(workerScripts[i]); total += updateActiveScriptsItemContent(workerScripts[i]);
@ -249,10 +255,10 @@ function updateActiveScriptsItems(maxTasks=150) {
getElementById("active-scripts-total-production-active").innerText = numeralWrapper.formatMoney(total); getElementById("active-scripts-total-production-active").innerText = numeralWrapper.formatMoney(total);
getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug); getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug);
getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000)); getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
return total; return total;
} }
//Updates the content of the given item in the Active Scripts list
function updateActiveScriptsItemContent(workerscript) { function updateActiveScriptsItemContent(workerscript) {
var server = getServer(workerscript.serverIp); var server = getServer(workerscript.serverIp);
if (server == null) { if (server == null) {
@ -261,7 +267,7 @@ function updateActiveScriptsItemContent(workerscript) {
} }
let hostname = server.hostname; let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) { if (ActiveScriptsUI[hostname] == null) {
return; //Hasn't been created yet. We'll skip it return; // Hasn't been created yet. We'll skip it
} }
updateHeaderHtml(server); updateHeaderHtml(server);
@ -273,11 +279,11 @@ function updateActiveScriptsItemContent(workerscript) {
var itemName = itemNameArray.join("-"); var itemName = itemNameArray.join("-");
if (ActiveScriptsUI[hostname].scriptStats[itemName] == null) { if (ActiveScriptsUI[hostname].scriptStats[itemName] == null) {
return; //Hasn't been fully added yet. We'll skip it return; // Hasn't been fully added yet. We'll skip it
} }
var item = ActiveScriptsUI[hostname].scriptStats[itemName]; var item = ActiveScriptsUI[hostname].scriptStats[itemName];
//Update the text if necessary. This fn returns the online $/s production // Update the text if necessary. This fn returns the online $/s production
return updateActiveScriptsText(workerscript, item, itemName); return updateActiveScriptsText(workerscript, item, itemName);
} }
@ -296,7 +302,7 @@ function updateActiveScriptsText(workerscript, item, itemName) {
updateHeaderHtml(server); updateHeaderHtml(server);
var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime; var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime;
//Only update if the item is visible // Only update if the item is visible
if (ActiveScriptsUI[hostname].header.classList.contains("active") === false) {return onlineMps;} if (ActiveScriptsUI[hostname].header.classList.contains("active") === false) {return onlineMps;}
if (ActiveScriptsUI[hostname].scriptHdrs[itemName].classList.contains("active") === false) {return onlineMps;} if (ActiveScriptsUI[hostname].scriptHdrs[itemName].classList.contains("active") === false) {return onlineMps;}
@ -305,7 +311,7 @@ function updateActiveScriptsText(workerscript, item, itemName) {
var onlineTime = "Online Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.onlineRunningTime * 1e3); var onlineTime = "Online Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.onlineRunningTime * 1e3);
var offlineTime = "Offline Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.offlineRunningTime * 1e3); var offlineTime = "Offline Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.offlineRunningTime * 1e3);
//Online // Online
var onlineTotalMoneyMade = "Total online production: " + numeralWrapper.formatMoney(workerscript.scriptRef.onlineMoneyMade); var onlineTotalMoneyMade = "Total online production: " + numeralWrapper.formatMoney(workerscript.scriptRef.onlineMoneyMade);
var onlineTotalExpEarned = (Array(26).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.onlineExpGained) + " hacking exp").replace( / /g, "&nbsp;"); var onlineTotalExpEarned = (Array(26).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.onlineExpGained) + " hacking exp").replace( / /g, "&nbsp;");
@ -313,7 +319,7 @@ function updateActiveScriptsText(workerscript, item, itemName) {
var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime; var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime;
var onlineEpsText = (Array(25).join(" ") + numeralWrapper.formatBigNumber(onlineEps) + " hacking exp / second").replace( / /g, "&nbsp;"); var onlineEpsText = (Array(25).join(" ") + numeralWrapper.formatBigNumber(onlineEps) + " hacking exp / second").replace( / /g, "&nbsp;");
//Offline // Offline
var offlineTotalMoneyMade = "Total offline production: " + numeralWrapper.formatMoney(workerscript.scriptRef.offlineMoneyMade); var offlineTotalMoneyMade = "Total offline production: " + numeralWrapper.formatMoney(workerscript.scriptRef.offlineMoneyMade);
var offlineTotalExpEarned = (Array(27).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.offlineExpGained) + " hacking exp").replace( / /g, "&nbsp;"); var offlineTotalExpEarned = (Array(27).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.offlineExpGained) + " hacking exp").replace( / /g, "&nbsp;");

@ -20,7 +20,7 @@ export function loadGlobalAliases(saveString: string): void {
} }
} }
//Print all aliases to terminal // Prints all aliases to terminal
export function printAliases(): void { export function printAliases(): void {
for (var name in Aliases) { for (var name in Aliases) {
if (Aliases.hasOwnProperty(name)) { if (Aliases.hasOwnProperty(name)) {
@ -34,7 +34,7 @@ export function printAliases(): void {
} }
} }
//True if successful, false otherwise // Returns true if successful, false otherwise
export function parseAliasDeclaration(dec: string, global: boolean=false) { export function parseAliasDeclaration(dec: string, global: boolean=false) {
var re = /^([_|\w|!|%|,|@]+)="(.+)"$/; var re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
var matches = dec.match(re); var matches = dec.match(re);
@ -90,8 +90,10 @@ export function removeAlias(name: string): boolean {
return false; return false;
} }
//Returns the original string with any aliases substituted in /**
//Aliases only applied to "whole words", one level deep * Returns the original string with any aliases substituted in.
* Aliases are only applied to "whole words", one level deep
*/
export function substituteAliases(origCommand: string): string { export function substituteAliases(origCommand: string): string {
const commandArray = origCommand.split(" "); const commandArray = origCommand.split(" ");
if (commandArray.length > 0){ if (commandArray.length > 0){

File diff suppressed because it is too large Load Diff

@ -1,3 +1,4 @@
import { Engine } from "./engine"; import { Engine } from "./engine";
import { setTimeoutRef } from "./utils/SetTimeoutRef"; import { setTimeoutRef } from "./utils/SetTimeoutRef";
@ -8,7 +9,12 @@ import { isString } from "../utils/helpers/isString";
export let cinematicTextFlag = false; export let cinematicTextFlag = false;
// Lines must be an array of strings /**
* Print a message using a hacking-style "typing" effect.
* Note that this clears the UI so that the text from this is the only thing visible.
*
* @param lines {string[]} Array of strings to print, where each element is a separate line
*/
export function writeCinematicText(lines) { export function writeCinematicText(lines) {
cinematicTextFlag = true; cinematicTextFlag = true;

@ -130,14 +130,15 @@ function getRandomReward() {
}); });
switch (reward.type) { switch (reward.type) {
case CodingContractRewardType.FactionReputation: case CodingContractRewardType.FactionReputation: {
// Get a random faction that player is a part of. That // Get a random faction that player is a part of. That
// faction must allow hacking contracts // faction must allow hacking contracts
var numFactions = factionsThatAllowHacking.length; var numFactions = factionsThatAllowHacking.length;
var randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)]; var randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
reward.name = randFaction; reward.name = randFaction;
break; break;
case CodingContractRewardType.CompanyReputation: }
case CodingContractRewardType.CompanyReputation: {
const allJobs = Object.keys(Player.jobs); const allJobs = Object.keys(Player.jobs);
if (allJobs.length > 0) { if (allJobs.length > 0) {
reward.name = allJobs[getRandomInt(0, allJobs.length - 1)]; reward.name = allJobs[getRandomInt(0, allJobs.length - 1)];
@ -145,6 +146,7 @@ function getRandomReward() {
reward.type = CodingContractRewardType.Money; reward.type = CodingContractRewardType.Money;
} }
break; break;
}
default: default:
break; break;
} }

@ -8,93 +8,93 @@ import { IMap } from "./types";
export let CONSTANTS: IMap<any> = { export let CONSTANTS: IMap<any> = {
Version: "0.46.1", Version: "0.46.1",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience /** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then * and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
//the player will have this level assuming no multipliers. Multipliers can cause skills to go above this. * the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
*/
MaxSkillLevel: 975, MaxSkillLevel: 975,
//Milliseconds per game cycle // Milliseconds per game cycle
MilliPerCycle: 200, MilliPerCycle: 200,
//How much reputation is needed to join a megacorporation's faction // How much reputation is needed to join a megacorporation's faction
CorpFactionRepRequirement: 200e3, CorpFactionRepRequirement: 200e3,
/* Base costs */ // Base RAM costs
BaseCostFor1GBOfRamHome: 32000, BaseCostFor1GBOfRamHome: 32000,
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
// Cost to travel to another city
TravelCost: 200e3, TravelCost: 200e3,
/* Faction and Company favor */ // Faction and Company favor-related things
BaseFavorToDonate: 150, BaseFavorToDonate: 150,
DonateMoneyToRepDivisor: 1e6, DonateMoneyToRepDivisor: 1e6,
FactionReputationToFavorBase: 500, FactionReputationToFavorBase: 500,
FactionReputationToFavorMult: 1.02, FactionReputationToFavorMult: 1.02,
CompanyReputationToFavorBase: 500, CompanyReputationToFavorBase: 500,
CompanyReputationToFavorMult: 1.02, CompanyReputationToFavorMult: 1.02,
/* Augmentation */ // NeuroFlux Governor Augmentation cost multiplier
//NeuroFlux Governor cost multiplier as you level up
NeuroFluxGovernorLevelMult: 1.14, NeuroFluxGovernorLevelMult: 1.14,
/* Netscript Constants */ // RAM Costs for Netscript functions
//RAM Costs for different commands ScriptBaseRamCost: 1.6,
ScriptBaseRamCost: 1.6, ScriptDomRamCost: 25,
ScriptDomRamCost: 25, ScriptWhileRamCost: 0,
ScriptWhileRamCost: 0, ScriptForRamCost: 0,
ScriptForRamCost: 0, ScriptIfRamCost: 0,
ScriptIfRamCost: 0, ScriptHackRamCost: 0.1,
ScriptHackRamCost: 0.1, ScriptHackAnalyzeRamCost: 1,
ScriptHackAnalyzeRamCost: 1, ScriptGrowRamCost: 0.15,
ScriptGrowRamCost: 0.15, ScriptGrowthAnalyzeRamCost: 1,
ScriptGrowthAnalyzeRamCost: 1, ScriptWeakenRamCost: 0.15,
ScriptWeakenRamCost: 0.15, ScriptScanRamCost: 0.2,
ScriptScanRamCost: 0.2, ScriptPortProgramRamCost: 0.05,
ScriptPortProgramRamCost: 0.05, ScriptRunRamCost: 1.0,
ScriptRunRamCost: 1.0, ScriptExecRamCost: 1.3,
ScriptExecRamCost: 1.3, ScriptSpawnRamCost: 2.0,
ScriptSpawnRamCost: 2.0, ScriptScpRamCost: 0.6,
ScriptScpRamCost: 0.6, ScriptKillRamCost: 0.5,
ScriptKillRamCost: 0.5, //Kill and killall ScriptHasRootAccessRamCost: 0.05,
ScriptHasRootAccessRamCost: 0.05, ScriptGetHostnameRamCost: 0.05,
ScriptGetHostnameRamCost: 0.05, //getHostname() and getIp() ScriptGetHackingLevelRamCost: 0.05,
ScriptGetHackingLevelRamCost: 0.05, //getHackingLevel() ScriptGetMultipliersRamCost: 4.0,
ScriptGetMultipliersRamCost: 4.0, //getHackingMultipliers() and getBitNodeMultipliers() ScriptGetServerRamCost: 0.1,
ScriptGetServerRamCost: 0.1, ScriptFileExistsRamCost: 0.1,
ScriptFileExistsRamCost: 0.1, ScriptIsRunningRamCost: 0.1,
ScriptIsRunningRamCost: 0.1, ScriptHacknetNodesRamCost: 4.0,
ScriptHacknetNodesRamCost: 4.0, //Base cost for accessing Hacknet Node API ScriptHNUpgLevelRamCost: 0.4,
ScriptHNUpgLevelRamCost: 0.4, ScriptHNUpgRamRamCost: 0.6,
ScriptHNUpgRamRamCost: 0.6, ScriptHNUpgCoreRamCost: 0.8,
ScriptHNUpgCoreRamCost: 0.8, ScriptGetStockRamCost: 2.0,
ScriptGetStockRamCost: 2.0, ScriptBuySellStockRamCost: 2.5,
ScriptBuySellStockRamCost: 2.5,
ScriptGetPurchaseServerRamCost: 0.25, ScriptGetPurchaseServerRamCost: 0.25,
ScriptPurchaseServerRamCost: 2.25, ScriptPurchaseServerRamCost: 2.25,
ScriptGetPurchasedServerLimit: 0.05, ScriptGetPurchasedServerLimit: 0.05,
ScriptGetPurchasedServerMaxRam: 0.05, ScriptGetPurchasedServerMaxRam: 0.05,
ScriptRoundRamCost: 0.05, ScriptRoundRamCost: 0.05,
ScriptReadWriteRamCost: 1.0, ScriptReadWriteRamCost: 1.0,
ScriptArbScriptRamCost: 1.0, // Functions that apply to all scripts regardless of args ScriptArbScriptRamCost: 1.0,
ScriptGetScriptRamCost: 0.1, ScriptGetScriptRamCost: 0.1,
ScriptGetHackTimeRamCost: 0.05, ScriptGetHackTimeRamCost: 0.05,
ScriptGetFavorToDonate: 0.10, ScriptGetFavorToDonate: 0.10,
ScriptCodingContractBaseRamCost:10, ScriptCodingContractBaseRamCost: 10,
ScriptSleeveBaseRamCost: 4, ScriptSleeveBaseRamCost: 4,
ScriptSingularityFn1RamCost: 1, ScriptSingularityFn1RamCost: 1,
ScriptSingularityFn2RamCost: 2, ScriptSingularityFn2RamCost: 2,
ScriptSingularityFn3RamCost: 3, ScriptSingularityFn3RamCost: 3,
ScriptSingularityFnRamMult: 2, // Multiplier for RAM cost outside of BN-4 ScriptSingularityFnRamMult: 2, // Multiplier for RAM cost outside of BN-4
ScriptGangApiBaseRamCost: 4, ScriptGangApiBaseRamCost: 4,
ScriptBladeburnerApiBaseRamCost: 4, ScriptBladeburnerApiBaseRamCost: 4,
NumNetscriptPorts: 20, NumNetscriptPorts: 20,
//Server constants // Server-related constants
HomeComputerMaxRam: 1073741824, // 2 ^ 30 HomeComputerMaxRam: 1073741824, // 2 ^ 30
ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate
ServerMaxGrowthRate: 1.0035, // Maximum possible growth rate (max rate accounting for server security) ServerMaxGrowthRate: 1.0035, // Maximum possible growth rate (max rate accounting for server security)
@ -102,49 +102,50 @@ export let CONSTANTS: IMap<any> = {
ServerWeakenAmount: 0.05, // Amount by which server's security decreases when weakened ServerWeakenAmount: 0.05, // Amount by which server's security decreases when weakened
PurchasedServerLimit: 25, PurchasedServerLimit: 25,
PurchasedServerMaxRam: 1048576, //2^20 PurchasedServerMaxRam: 1048576, // 2^20
//Augmentation Constants // Augmentation Constants
AugmentationCostMultiplier: 5, //Used for balancing costs without having to readjust every Augmentation cost AugmentationCostMultiplier: 5, // Used for balancing costs without having to readjust every Augmentation cost
AugmentationRepMultiplier: 2.5, //Used for balancing rep cost without having to readjust every value AugmentationRepMultiplier: 2.5, // Used for balancing rep cost without having to readjust every value
MultipleAugMultiplier: 1.9, MultipleAugMultiplier: 1.9,
//How much a TOR router costs // TOR Router
TorRouterCost: 200000, TorRouterCost: 200e3,
//Infiltration constants // Infiltration
InfiltrationBribeBaseAmount: 100e3, //Amount per clearance level InfiltrationBribeBaseAmount: 100e3, //Amount per clearance level
InfiltrationMoneyValue: 5e3, //Convert "secret" value to money InfiltrationMoneyValue: 5e3, //Convert "secret" value to money
InfiltrationRepValue: 1.4, //Convert "secret" value to faction reputation InfiltrationRepValue: 1.4, //Convert "secret" value to faction reputation
InfiltrationExpPow: 0.8, InfiltrationExpPow: 0.8,
//Stock market constants // Stock market
WSEAccountCost: 200e6, WSEAccountCost: 200e6,
TIXAPICost: 5e9, TIXAPICost: 5e9,
MarketData4SCost: 1e9, MarketData4SCost: 1e9,
MarketDataTixApi4SCost: 25e9, MarketDataTixApi4SCost: 25e9,
StockMarketCommission: 100e3, StockMarketCommission: 100e3,
//Hospital/Health // Hospital/Health
HospitalCostPerHp: 100e3, HospitalCostPerHp: 100e3,
//Intelligence-related constants // Intelligence-related constants
IntelligenceCrimeWeight: 0.05, //Weight for how much int affects crime success rates IntelligenceCrimeWeight: 0.05, // Weight for how much int affects crime success rates
IntelligenceInfiltrationWeight: 0.1, //Weight for how much int affects infiltration success rates IntelligenceInfiltrationWeight: 0.1, // Weight for how much int affects infiltration success rates
IntelligenceCrimeBaseExpGain: 0.001, IntelligenceCrimeBaseExpGain: 0.001,
IntelligenceProgramBaseExpGain: 500, //Program required hack level divided by this to determine int exp gain IntelligenceProgramBaseExpGain: 500, // Program required hack level divided by this to determine int exp gain
IntelligenceTerminalHackBaseExpGain: 200, //Hacking exp divided by this to determine int exp gain IntelligenceTerminalHackBaseExpGain: 200, // Hacking exp divided by this to determine int exp gain
IntelligenceSingFnBaseExpGain: 0.002, IntelligenceSingFnBaseExpGain: 0.002,
IntelligenceClassBaseExpGain: 0.000001, IntelligenceClassBaseExpGain: 0.000001,
IntelligenceHackingMissionBaseExpGain: 0.03, //Hacking Mission difficulty multiplied by this to get exp gain IntelligenceHackingMissionBaseExpGain: 0.03, // Hacking Mission difficulty multiplied by this to get exp gain
//Hacking Missions // Hacking Missions
HackingMissionRepToDiffConversion: 10000, //Faction rep is divided by this to get mission difficulty // TODO Move this into Hacking Mission implementation
HackingMissionRepToRewardConversion: 7, //Faction rep divided byt his to get mission rep reward HackingMissionRepToDiffConversion: 10000, // Faction rep is divided by this to get mission difficulty
HackingMissionSpamTimeIncrease: 25000, //How much time limit increase is gained when conquering a Spam Node (ms) HackingMissionRepToRewardConversion: 7, // Faction rep divided byt his to get mission rep reward
HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node HackingMissionSpamTimeIncrease: 25000, // How much time limit increase is gained when conquering a Spam Node (ms)
HackingMissionMiscDefenseIncrease: 1.05, //The amount by which every misc node's defense is multiplied when one is conquered HackingMissionTransferAttackIncrease: 1.05, // Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
HackingMissionDifficultyToHacking: 135, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc) HackingMissionMiscDefenseIncrease: 1.05, // The amount by which every misc node's defense is multiplied when one is conquered
HackingMissionDifficultyToHacking: 135, // Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc)
HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.<br><br>" + HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.<br><br>" +
"In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " + "In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " +
"are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " + "are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " +
@ -192,7 +193,7 @@ export let CONSTANTS: IMap<any> = {
"-Miscellaneous Nodes slowly raise their defense over time<br><br>" + "-Miscellaneous Nodes slowly raise their defense over time<br><br>" +
"-Nodes slowly regenerate health over time.", "-Nodes slowly regenerate health over time.",
/* Time Constants */ // Time-related constants
MillisecondsPer20Hours: 72000000, MillisecondsPer20Hours: 72000000,
GameCyclesPer20Hours: 72000000 / 200, GameCyclesPer20Hours: 72000000 / 200,
@ -220,7 +221,7 @@ export let CONSTANTS: IMap<any> = {
MillisecondsPerFiveMinutes: 300000, MillisecondsPerFiveMinutes: 300000,
GameCyclesPerFiveMinutes: 300000 / 200, GameCyclesPerFiveMinutes: 300000 / 200,
/* Player Work / Action related Constants */ // Player Work & Action
FactionWorkHacking: "Faction Hacking Work", FactionWorkHacking: "Faction Hacking Work",
FactionWorkField: "Faction Field Work", FactionWorkField: "Faction Field Work",
FactionWorkSecurity: "Faction Security Work", FactionWorkSecurity: "Faction Security Work",
@ -263,10 +264,11 @@ export let CONSTANTS: IMap<any> = {
CrimeAssassination: "assassinate a high-profile target", CrimeAssassination: "assassinate a high-profile target",
CrimeHeist: "pull off the ultimate heist", CrimeHeist: "pull off the ultimate heist",
/* Coding Contract Constants */ // Coding Contract
CodingContractBaseFactionRepGain: 2500, // TODO Move this into Coding contract impelmentation?
CodingContractBaseCompanyRepGain: 4000, CodingContractBaseFactionRepGain: 2500,
CodingContractBaseMoneyGain: 75e6, CodingContractBaseCompanyRepGain: 4000,
CodingContractBaseMoneyGain: 75e6,
// BitNode/Source-File related stuff // BitNode/Source-File related stuff
TotalNumBitNodes: 24, TotalNumBitNodes: 24,

@ -33,7 +33,12 @@ import ReactDOM from "react-dom";
const Component = React.Component; const Component = React.Component;
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12]; // Update as additional BitNodes get implemented
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
// Some dev menu buttons just add a lot of something for convenience
const tonsPP = 1e27;
const tonsP = 1e12;
class ValueAdjusterComponent extends Component { class ValueAdjusterComponent extends Component {
@ -189,13 +194,13 @@ class DevMenuComponent extends Component {
} }
tonsOfExp() { tonsOfExp() {
Player.gainHackingExp(1e27); Player.gainHackingExp(tonsPP);
Player.gainStrengthExp(1e27); Player.gainStrengthExp(tonsPP);
Player.gainDefenseExp(1e27); Player.gainDefenseExp(tonsPP);
Player.gainDexterityExp(1e27); Player.gainDexterityExp(tonsPP);
Player.gainAgilityExp(1e27); Player.gainAgilityExp(tonsPP);
Player.gainCharismaExp(1e27); Player.gainCharismaExp(tonsPP);
Player.gainIntelligenceExp(1e27); Player.gainIntelligenceExp(tonsPP);
Player.updateSkillLevels(); Player.updateSkillLevels();
} }
@ -298,7 +303,7 @@ class DevMenuComponent extends Component {
tonsOfRep() { tonsOfRep() {
for (const i in Factions) { for (const i in Factions) {
Factions[i].playerReputation = 1e27; Factions[i].playerReputation = tonsPP;
} }
} }
@ -310,7 +315,7 @@ class DevMenuComponent extends Component {
tonsOfFactionFavor() { tonsOfFactionFavor() {
for (const i in Factions) { for (const i in Factions) {
Factions[i].favor = 1e27; Factions[i].favor = tonsPP;
} }
} }
@ -456,7 +461,7 @@ class DevMenuComponent extends Component {
tonsOfRepCompanies() { tonsOfRepCompanies() {
for (const c in Companies) { for (const c in Companies) {
Companies[c].playerReputation = 1e12; Companies[c].playerReputation = tonsP;
} }
} }
@ -468,7 +473,7 @@ class DevMenuComponent extends Component {
tonsOfFavorCompanies() { tonsOfFavorCompanies() {
for (const c in Companies) { for (const c in Companies) {
Companies[c].favor = 1e12; Companies[c].favor = tonsP;
} }
} }
@ -493,7 +498,7 @@ class DevMenuComponent extends Component {
addTonsBladeburnerRank() { addTonsBladeburnerRank() {
if (!!Player.bladeburner) { if (!!Player.bladeburner) {
Player.bladeburner.changeRank(1e12); Player.bladeburner.changeRank(tonsP);
} }
} }
@ -513,13 +518,13 @@ class DevMenuComponent extends Component {
addTonsBladeburnerCycles() { addTonsBladeburnerCycles() {
if (!!Player.bladeburner) { if (!!Player.bladeburner) {
Player.bladeburner.storedCycles += 1e12; Player.bladeburner.storedCycles += tonsP;
} }
} }
addTonsGangCycles() { addTonsGangCycles() {
if (!!Player.gang) { if (!!Player.gang) {
Player.gang.storedCycles = 1e12; Player.gang.storedCycles = tonsP;
} }
} }
@ -539,7 +544,7 @@ class DevMenuComponent extends Component {
addTonsCorporationCycles() { addTonsCorporationCycles() {
if (!!Player.corporation) { if (!!Player.corporation) {
Player.corporation.storedCycles = 1e12; Player.corporation.storedCycles = tonsP;
} }
} }
@ -646,16 +651,16 @@ class DevMenuComponent extends Component {
let sourceFiles = []; let sourceFiles = [];
validSFN.forEach( i => sourceFiles.push( validSFN.forEach( i => sourceFiles.push(
<tr key={'sf-'+i}> <tr key={'sf-'+i}>
<td><span className="text">SF-{i}:</span></td> <td><span className="text">SF-{i}:</span></td>
<td> <td>
<button className="std-button touch-right" onClick={this.setSF(i, 0)}>0</button> <button className="std-button touch-right" onClick={this.setSF(i, 0)}>0</button>
<button className="std-button touch-sides" onClick={this.setSF(i, 1)}>1</button> <button className="std-button touch-sides" onClick={this.setSF(i, 1)}>1</button>
<button className="std-button touch-sides" onClick={this.setSF(i, 2)}>2</button> <button className="std-button touch-sides" onClick={this.setSF(i, 2)}>2</button>
<button className="std-button touch-left" onClick={this.setSF(i, 3)}>3</button> <button className="std-button touch-left" onClick={this.setSF(i, 3)}>3</button>
</td> </td>
</tr> </tr>
)); ));
@ -1187,7 +1192,6 @@ class DevMenuComponent extends Component {
} }
} }
const devMenuContainerId = "dev-menu-container"; const devMenuContainerId = "dev-menu-container";
export function createDevMenu() { export function createDevMenu() {
@ -1201,11 +1205,11 @@ export function createDevMenu() {
id: devMenuContainerId, id: devMenuContainerId,
}); });
const entireGameContainer = document.getElementById("entire-game-container"); const entireGameContainer = document.getElementById("entire-game-container");
if (entireGameContainer == null) { if (entireGameContainer == null) {
throw new Error("Could not find entire-game-container DOM element"); throw new Error("Could not find entire-game-container DOM element");
} }
entireGameContainer.appendChild(devMenuContainer); entireGameContainer.appendChild(devMenuContainer);
ReactDOM.render(<DevMenuComponent />, devMenuContainer); ReactDOM.render(<DevMenuComponent />, devMenuContainer);
} }

@ -1,6 +1,7 @@
/* /**
Also add police clashes * TODO
balance point to keep them from running out of control * Add police clashes
* balance point to keep them from running out of control
*/ */
import { gangMemberTasksMetadata } from "./data/gangmembertasks"; import { gangMemberTasksMetadata } from "./data/gangmembertasks";
@ -57,7 +58,7 @@ $(document).keydown(function(event) {
} }
}); });
//Delete upgrade box when clicking outside // Delete upgrade box when clicking outside
$(document).mousedown(function(event) { $(document).mousedown(function(event) {
var boxId = "gang-member-upgrade-popup-box"; var boxId = "gang-member-upgrade-popup-box";
var contentId = "gang-member-upgrade-popup-box-content"; var contentId = "gang-member-upgrade-popup-box-content";
@ -144,12 +145,12 @@ export function loadAllGangs(saveString) {
} }
/** /**
* @param facName - Name of corresponding faction * @param facName {string} Name of corresponding faction
* @param hacking - Boolean indicating whether or not its a hacking gang * @param hacking {bollean} Whether or not its a hacking gang
*/ */
export function Gang(facName, hacking=false) { export function Gang(facName, hacking=false) {
this.facName = facName; this.facName = facName;
this.members = []; //Array of GangMembers this.members = [];
this.wanted = 1; this.wanted = 1;
this.respect = 1; this.respect = 1;
@ -204,7 +205,7 @@ Gang.prototype.process = function(numCycles=1, player) {
} }
Gang.prototype.processGains = function(numCycles=1, player) { Gang.prototype.processGains = function(numCycles=1, player) {
//Get gains per cycle // Get gains per cycle
var moneyGains = 0, respectGains = 0, wantedLevelGains = 0; var moneyGains = 0, respectGains = 0, wantedLevelGains = 0;
for (var i = 0; i < this.members.length; ++i) { for (var i = 0; i < this.members.length; ++i) {
respectGains += (this.members[i].calculateRespectGain(this)); respectGains += (this.members[i].calculateRespectGain(this));
@ -569,10 +570,9 @@ Gang.fromJSON = function(value) {
Reviver.constructors.Gang = Gang; Reviver.constructors.Gang = Gang;
/*** Gang Member object ***/
function GangMember(name) { function GangMember(name) {
this.name = name; this.name = name;
this.task = "Unassigned"; //GangMemberTask object this.task = "Unassigned";
this.earnedRespect = 0; this.earnedRespect = 0;
@ -604,11 +604,11 @@ function GangMember(name) {
this.agi_asc_mult = 1; this.agi_asc_mult = 1;
this.cha_asc_mult = 1; this.cha_asc_mult = 1;
this.upgrades = []; //Names of upgrades this.upgrades = []; // Names of upgrades
this.augmentations = []; //Names only this.augmentations = []; // Names of augmentations only
} }
//Same formula for Player // Same skill calculation formula as Player
GangMember.prototype.calculateSkill = function(exp, mult=1) { GangMember.prototype.calculateSkill = function(exp, mult=1) {
return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1); return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1);
} }
@ -652,7 +652,7 @@ GangMember.prototype.getTask = function() {
return GangMemberTasks["Unassigned"]; return GangMemberTasks["Unassigned"];
} }
//Gains are per cycle // Gains are per cycle
GangMember.prototype.calculateRespectGain = function(gang) { GangMember.prototype.calculateRespectGain = function(gang) {
const task = this.getTask(); const task = this.getTask();
if (task == null || !(task instanceof GangMemberTask) || task.baseRespect === 0) {return 0;} if (task == null || !(task instanceof GangMemberTask) || task.baseRespect === 0) {return 0;}
@ -777,9 +777,11 @@ GangMember.prototype.ascend = function() {
// Returns the multipliers that would be gained from ascension // Returns the multipliers that would be gained from ascension
GangMember.prototype.getAscensionResults = function() { GangMember.prototype.getAscensionResults = function() {
// Calculate ascension bonus to stat multipliers. /**
// This is based on the current number of multipliers from Non-Augmentation upgrades * Calculate ascension bonus to stat multipliers.
// + Ascension Bonus = N% of current bonus from Augmentations * This is based on the current number of multipliers from Non-Augmentation upgrades
* + Ascension Bonus = N% of current bonus from Augmentations
*/
let hack = 1; let hack = 1;
let str = 1; let str = 1;
let def = 1; let def = 1;
@ -844,7 +846,7 @@ GangMember.fromJSON = function(value) {
Reviver.constructors.GangMember = GangMember; Reviver.constructors.GangMember = GangMember;
//Defines tasks that Gang Members can work on // Defines tasks that Gang Members can work on
function GangMemberTask(name="", desc="", isHacking=false, isCombat=false, function GangMemberTask(name="", desc="", isHacking=false, isCombat=false,
params={baseRespect: 0, baseWanted: 0, baseMoney: 0, params={baseRespect: 0, baseWanted: 0, baseMoney: 0,
hackWeight: 0, strWeight: 0, defWeight: 0, hackWeight: 0, strWeight: 0, defWeight: 0,
@ -942,7 +944,7 @@ GangMemberUpgrade.prototype.createDescription = function() {
this.desc = lines.join("<br>"); this.desc = lines.join("<br>");
} }
//Passes in a GangMember object // Passes in a GangMember object
GangMemberUpgrade.prototype.apply = function(member) { GangMemberUpgrade.prototype.apply = function(member) {
if (this.mults.str != null) { member.str_mult *= this.mults.str; } if (this.mults.str != null) { member.str_mult *= this.mults.str; }
if (this.mults.def != null) { member.def_mult *= this.mults.def; } if (this.mults.def != null) { member.def_mult *= this.mults.def; }
@ -978,7 +980,7 @@ gangMemberUpgradesMetadata.forEach((e) => {
Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") { Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
const boxId = "gang-member-upgrade-popup-box"; const boxId = "gang-member-upgrade-popup-box";
if (UIElems.gangMemberUpgradeBoxOpened) { if (UIElems.gangMemberUpgradeBoxOpened) {
//Already opened, refreshing // Already opened, refreshing
if (UIElems.gangMemberUpgradeBoxElements == null || UIElems.gangMemberUpgradeBox == null || UIElems.gangMemberUpgradeBoxContent == null) { if (UIElems.gangMemberUpgradeBoxElements == null || UIElems.gangMemberUpgradeBox == null || UIElems.gangMemberUpgradeBoxContent == null) {
console.error("Refreshing Gang member upgrade box throws error because required elements are null"); console.error("Refreshing Gang member upgrade box throws error because required elements are null");
return; return;
@ -998,7 +1000,7 @@ Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
} }
} }
} else { } else {
//New popup // New popup
UIElems.gangMemberUpgradeBoxFilter = createElement("input", { UIElems.gangMemberUpgradeBoxFilter = createElement("input", {
type:"text", placeholder:"Filter gang members", type:"text", placeholder:"Filter gang members",
value:initialFilter, value:initialFilter,
@ -1030,7 +1032,7 @@ Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
} }
} }
//Create upgrade panels for each individual Gang Member // Create upgrade panels for each individual Gang Member
GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) { GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
var container = createElement("div", { var container = createElement("div", {
border:"1px solid white", border:"1px solid white",
@ -1052,7 +1054,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
"Cha: " + this.cha + " (x" + formatNumber(this.cha_mult * this.cha_asc_mult, 2) + ")\n", "Cha: " + this.cha + " (x" + formatNumber(this.cha_mult * this.cha_asc_mult, 2) + ")\n",
}); });
//Already purchased upgrades // Already purchased upgrades
const ownedUpgradesElements = []; const ownedUpgradesElements = [];
function pushOwnedUpgrade(upgName) { function pushOwnedUpgrade(upgName) {
const upg = GangMemberUpgrades[upgName]; const upg = GangMemberUpgrades[upgName];
@ -1078,7 +1080,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
container.appendChild(ownedUpgrades); container.appendChild(ownedUpgrades);
container.appendChild(createElement("br", {})); container.appendChild(createElement("br", {}));
//Upgrade buttons. Only show upgrades that can be afforded // Upgrade buttons. Only show upgrades that can be afforded
const weaponUpgrades = []; const weaponUpgrades = [];
const armorUpgrades = []; const armorUpgrades = [];
const vehicleUpgrades = []; const vehicleUpgrades = [];
@ -1210,18 +1212,18 @@ Gang.prototype.displayGangContent = function(player) {
if (!UIElems.gangContentCreated || UIElems.gangContainer == null) { if (!UIElems.gangContentCreated || UIElems.gangContainer == null) {
UIElems.gangContentCreated = true; UIElems.gangContentCreated = true;
//Create gang container // Create gang container
UIElems.gangContainer = createElement("div", { UIElems.gangContainer = createElement("div", {
id:"gang-container", class:"generic-menupage-container", id:"gang-container", class:"generic-menupage-container",
}); });
//Get variables // Get variables
var facName = this.facName, var facName = this.facName,
members = this.members, members = this.members,
wanted = this.wanted, wanted = this.wanted,
respect = this.respect; respect = this.respect;
//Back button // Back button
UIElems.gangContainer.appendChild(createElement("a", { UIElems.gangContainer.appendChild(createElement("a", {
class:"a-link-button", display:"inline-block", innerText:"Back", class:"a-link-button", display:"inline-block", innerText:"Back",
clickListener:()=>{ clickListener:()=>{
@ -1231,7 +1233,7 @@ Gang.prototype.displayGangContent = function(player) {
} }
})); }));
//Buttons to switch between panels // Buttons to switch between panels
UIElems.managementButton = createElement("a", { UIElems.managementButton = createElement("a", {
id:"gang-management-subpage-button", class:"a-link-button-inactive", id:"gang-management-subpage-button", class:"a-link-button-inactive",
display:"inline-block", innerHTML: "Gang Management (Alt+1)", display:"inline-block", innerHTML: "Gang Management (Alt+1)",
@ -1263,7 +1265,7 @@ Gang.prototype.displayGangContent = function(player) {
UIElems.gangContainer.appendChild(UIElems.managementButton); UIElems.gangContainer.appendChild(UIElems.managementButton);
UIElems.gangContainer.appendChild(UIElems.territoryButton); UIElems.gangContainer.appendChild(UIElems.territoryButton);
//Subpage for managing gang members // Subpage for managing gang members
UIElems.gangManagementSubpage = createElement("div", { UIElems.gangManagementSubpage = createElement("div", {
display:"block", id:"gang-management-subpage", display:"block", id:"gang-management-subpage",
}); });
@ -1359,7 +1361,7 @@ Gang.prototype.displayGangContent = function(player) {
}); });
UIElems.gangManagementSubpage.appendChild(UIElems.gangRecruitRequirementText); UIElems.gangManagementSubpage.appendChild(UIElems.gangRecruitRequirementText);
//Gang Member List management buttons (Expand/Collapse All, select a single member) // Gang Member List management buttons (Expand/Collapse All, select a single member)
UIElems.gangManagementSubpage.appendChild(createElement("br", {})); UIElems.gangManagementSubpage.appendChild(createElement("br", {}));
UIElems.gangExpandAllButton = createElement("a", { UIElems.gangExpandAllButton = createElement("a", {
class:"a-link-button", display:"inline-block", class:"a-link-button", display:"inline-block",
@ -1407,17 +1409,17 @@ Gang.prototype.displayGangContent = function(player) {
UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberFilter); UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberFilter);
UIElems.gangManagementSubpage.appendChild(UIElems.gangManageEquipmentButton); UIElems.gangManagementSubpage.appendChild(UIElems.gangManageEquipmentButton);
//Gang Member list // Gang Member list
UIElems.gangMemberList = createElement("ul", {id:"gang-member-list"}); UIElems.gangMemberList = createElement("ul", {id:"gang-member-list"});
this.displayGangMemberList(); this.displayGangMemberList();
UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberList); UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberList);
//Subpage for seeing gang territory information // Subpage for seeing gang territory information
UIElems.gangTerritorySubpage = createElement("div", { UIElems.gangTerritorySubpage = createElement("div", {
id:"gang-territory-subpage", display:"none" id:"gang-territory-subpage", display:"none"
}); });
//Info text for territory page // Info text for territory page
UIElems.gangTerritoryDescText = createElement("p", { UIElems.gangTerritoryDescText = createElement("p", {
width:"70%", width:"70%",
innerHTML: innerHTML:
@ -1582,7 +1584,7 @@ Gang.prototype.updateGangContent = function() {
} }
} }
} else { } else {
//Update information for overall gang // Update information for overall gang
if (UIElems.gangInfo instanceof Element) { if (UIElems.gangInfo instanceof Element) {
var faction = Factions[this.facName]; var faction = Factions[this.facName];
var rep; var rep;
@ -1592,7 +1594,7 @@ Gang.prototype.updateGangContent = function() {
rep = faction.playerReputation; rep = faction.playerReputation;
} }
removeChildrenFromElement(UIElems.gangInfo); removeChildrenFromElement(UIElems.gangInfo);
UIElems.gangInfo.appendChild(createElement("p", { // Respect UIElems.gangInfo.appendChild(createElement("p", { // Respect
display: "inline-block", display: "inline-block",
innerText: "Respect: " + formatNumber(this.respect, 6) + innerText: "Respect: " + formatNumber(this.respect, 6) +
" (" + formatNumber(5*this.respectGainRate, 6) + " / sec)", " (" + formatNumber(5*this.respectGainRate, 6) + " / sec)",
@ -1603,7 +1605,7 @@ Gang.prototype.updateGangContent = function() {
})); }));
UIElems.gangInfo.appendChild(createElement("br")); UIElems.gangInfo.appendChild(createElement("br"));
UIElems.gangInfo.appendChild(createElement("p", { // Wanted level UIElems.gangInfo.appendChild(createElement("p", { // Wanted level
display: "inline-block", display: "inline-block",
innerText: "Wanted Level: " + formatNumber(this.wanted, 6) + innerText: "Wanted Level: " + formatNumber(this.wanted, 6) +
" (" + formatNumber(5*this.wantedGainRate, 6) + " / sec)", " (" + formatNumber(5*this.wantedGainRate, 6) + " / sec)",
@ -1615,20 +1617,20 @@ Gang.prototype.updateGangContent = function() {
var wantedPenalty = this.getWantedPenalty(); var wantedPenalty = this.getWantedPenalty();
wantedPenalty = (1 - wantedPenalty) * 100; wantedPenalty = (1 - wantedPenalty) * 100;
UIElems.gangInfo.appendChild(createElement("p", { // Wanted Level multiplier UIElems.gangInfo.appendChild(createElement("p", { // Wanted Level multiplier
display: "inline-block", display: "inline-block",
innerText: `Wanted Level Penalty: -${formatNumber(wantedPenalty, 2)}%`, innerText: `Wanted Level Penalty: -${formatNumber(wantedPenalty, 2)}%`,
tooltip: "Penalty for respect and money gain rates due to Wanted Level" tooltip: "Penalty for respect and money gain rates due to Wanted Level"
})); }));
UIElems.gangInfo.appendChild(createElement("br")); UIElems.gangInfo.appendChild(createElement("br"));
UIElems.gangInfo.appendChild(createElement("p", { // Money gain rate UIElems.gangInfo.appendChild(createElement("p", { // Money gain rate
display: "inline-block", display: "inline-block",
innerText: `Money gain rate: ${numeralWrapper.format(5 * this.moneyGainRate, "$0.000a")} / sec`, innerText: `Money gain rate: ${numeralWrapper.format(5 * this.moneyGainRate, "$0.000a")} / sec`,
})); }));
UIElems.gangInfo.appendChild(createElement("br")); UIElems.gangInfo.appendChild(createElement("br"));
//Fix some rounding issues graphically // Fix some rounding issues graphically
var territoryMult = AllGangs[this.facName].territory * 100; var territoryMult = AllGangs[this.facName].territory * 100;
let displayNumber; let displayNumber;
if (territoryMult <= 0) { if (territoryMult <= 0) {
@ -1663,7 +1665,7 @@ Gang.prototype.updateGangContent = function() {
console.error("gang-info DOM element DNE"); console.error("gang-info DOM element DNE");
} }
//Toggle the 'Recruit member button' if valid // Toggle the 'Recruit member button' if valid
const numMembers = this.members.length; const numMembers = this.members.length;
const respectCost = this.getRespectNeededToRecruitMember(); const respectCost = this.getRespectNeededToRecruitMember();
@ -1681,14 +1683,14 @@ Gang.prototype.updateGangContent = function() {
UIElems.gangRecruitRequirementText.innerHTML = `${formatNumber(respectCost, 2)} respect needed to recruit next member`; UIElems.gangRecruitRequirementText.innerHTML = `${formatNumber(respectCost, 2)} respect needed to recruit next member`;
} }
//Update information for each gang member // Update information for each gang member
for (let i = 0; i < this.members.length; ++i) { for (let i = 0; i < this.members.length; ++i) {
this.updateGangMemberDisplayElement(this.members[i]); this.updateGangMemberDisplayElement(this.members[i]);
} }
} }
} }
//Takes in a GangMember object // Takes in a GangMember object
Gang.prototype.createGangMemberDisplayElement = function(memberObj) { Gang.prototype.createGangMemberDisplayElement = function(memberObj) {
if (!UIElems.gangContentCreated) { return; } if (!UIElems.gangContentCreated) { return; }
const name = memberObj.name; const name = memberObj.name;
@ -1829,7 +1831,7 @@ Gang.prototype.createGangMemberDisplayElement = function(memberObj) {
taskDiv.appendChild(taskSelector); taskDiv.appendChild(taskSelector);
taskDiv.appendChild(gainInfo); taskDiv.appendChild(gainInfo);
//Panel for Description of task // Panel for Description of task
var taskDescDiv = createElement("div", { var taskDescDiv = createElement("div", {
class:"gang-member-info-div", class:"gang-member-info-div",
id: name + "gang-member-task-desc", id: name + "gang-member-task-desc",

@ -17,21 +17,21 @@ let InfiltrationScenarios = {
} }
function InfiltrationInstance(companyName, startLevel, val, maxClearance, diff) { function InfiltrationInstance(companyName, startLevel, val, maxClearance, diff) {
this.companyName = companyName; this.companyName = companyName;
this.clearanceLevel = 0; this.clearanceLevel = 0;
this.maxClearanceLevel = maxClearance; this.maxClearanceLevel = maxClearance;
this.securityLevel = startLevel; this.securityLevel = startLevel;
this.difficulty = diff; //Affects how much security level increases. Represents a percentage this.difficulty = diff; // Affects how much security level increases. Represents a percentage
this.baseValue = val; //Base value of company secrets this.baseValue = val; // Base value of company secrets
this.secretsStolen = []; //Numbers representing value of stolen secrets this.secretsStolen = []; // Numbers representing value of stolen secrets
this.hackingExpGained = 0; this.hackingExpGained = 0;
this.strExpGained = 0; this.strExpGained = 0;
this.defExpGained = 0; this.defExpGained = 0;
this.dexExpGained = 0; this.dexExpGained = 0;
this.agiExpGained = 0; this.agiExpGained = 0;
this.chaExpGained = 0; this.chaExpGained = 0;
this.intExpGained = 0; this.intExpGained = 0;
} }
InfiltrationInstance.prototype.expMultiplier = function() { InfiltrationInstance.prototype.expMultiplier = function() {
@ -106,7 +106,7 @@ InfiltrationInstance.prototype.gainIntelligenceExp = function(amt) {
InfiltrationInstance.prototype.calcGainedIntelligenceExp = function() { InfiltrationInstance.prototype.calcGainedIntelligenceExp = function() {
if(!this.intExpGained || isNaN(this.intExpGained)) return 0; if(!this.intExpGained || isNaN(this.intExpGained)) return 0;
return Math.pow(this.intExpGained*this.expMultiplier(), CONSTANTS.InfiltrationExpPow); return Math.pow(this.intExpGained * this.expMultiplier(), CONSTANTS.InfiltrationExpPow);
} }
function beginInfiltration(companyName, startLevel, val, maxClearance, diff) { function beginInfiltration(companyName, startLevel, val, maxClearance, diff) {
@ -159,7 +159,7 @@ function nextInfiltrationLevel(inst) {
bribeButton.style.display = "none"; bribeButton.style.display = "none";
escapeButton.style.display = "none"; escapeButton.style.display = "none";
var rand = getRandomInt(0, 5); //This needs to change if more scenarios are added var rand = getRandomInt(0, 5); // This needs to change if more scenarios are added
var scenario = null; var scenario = null;
switch (rand) { switch (rand) {
case 1: case 1:
@ -442,7 +442,7 @@ function nextInfiltrationLevel(inst) {
function endInfiltrationLevel(inst) { function endInfiltrationLevel(inst) {
//Check if you gained any secrets // Check if you gained any secrets
if (inst.clearanceLevel % 5 == 0) { if (inst.clearanceLevel % 5 == 0) {
var baseSecretValue = inst.baseValue * inst.clearanceLevel / 2; var baseSecretValue = inst.baseValue * inst.clearanceLevel / 2;
var secretValue = baseSecretValue * Player.faction_rep_mult * var secretValue = baseSecretValue * Player.faction_rep_mult *
@ -456,12 +456,12 @@ function endInfiltrationLevel(inst) {
"could be given to factions for reputation (<span class='light-yellow'>" + formatNumber(secretValue, 3) + " rep</span>)"); "could be given to factions for reputation (<span class='light-yellow'>" + formatNumber(secretValue, 3) + " rep</span>)");
} }
//Increase security level based on difficulty // Increase security level based on difficulty
inst.securityLevel *= (1 + (inst.difficulty / 100)); inst.securityLevel *= (1 + (inst.difficulty / 100));
writeInfiltrationStatusText("You move on to the facility's next clearance level. This " + writeInfiltrationStatusText("You move on to the facility's next clearance level. This " +
"clearance level has " + inst.difficulty + "% higher security"); "clearance level has " + inst.difficulty + "% higher security");
//If this is max level, force endInfiltration // If this is max level, force endInfiltration
if (inst.clearanceLevel >= inst.maxClearanceLevel) { if (inst.clearanceLevel >= inst.maxClearanceLevel) {
endInfiltration(inst, true); endInfiltration(inst, true);
} else { } else {
@ -629,8 +629,8 @@ function updateInfiltrationButtons(inst, scenario) {
let intWgt = CONSTANTS.IntelligenceInfiltrationWeight; let intWgt = CONSTANTS.IntelligenceInfiltrationWeight;
//Kill // Kill
//Success: 5%, Failure 10%, -Karma // Success: 5%, Failure 10%, -Karma
function attemptInfiltrationKill(inst) { function attemptInfiltrationKill(inst) {
var chance = getInfiltrationKillChance(inst); var chance = getInfiltrationKillChance(inst);
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult; inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
@ -655,8 +655,8 @@ function getInfiltrationKillChance(inst) {
} }
//Knockout // Knockout
//Success: 3%, Failure: 10% // Success: 3%, Failure: 10%
function attemptInfiltrationKnockout(inst) { function attemptInfiltrationKnockout(inst) {
var chance = getInfiltrationKnockoutChance(inst); var chance = getInfiltrationKnockoutChance(inst);
inst.gainStrengthExp(inst.securityLevel / 70) * Player.strength_exp_mult; inst.gainStrengthExp(inst.securityLevel / 70) * Player.strength_exp_mult;
@ -680,8 +680,8 @@ function getInfiltrationKnockoutChance(inst) {
Player.agility) / (1.7 * lvl)); Player.agility) / (1.7 * lvl));
} }
//Stealth knockout // Stealth knockout
//Success: 0%, Failure: 10% // Success: 0%, Failure: 10%
function attemptInfiltrationStealthKnockout(inst) { function attemptInfiltrationStealthKnockout(inst) {
var chance = getInfiltrationStealthKnockoutChance(inst); var chance = getInfiltrationStealthKnockoutChance(inst);
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult; inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
@ -704,8 +704,8 @@ function getInfiltrationStealthKnockoutChance(inst) {
intWgt * Player.intelligence) / (3 * lvl)); intWgt * Player.intelligence) / (3 * lvl));
} }
//Assassination // Assassination
//Success: 0%, Failure: 5%, -Karma // Success: 0%, Failure: 5%, -Karma
function attemptInfiltrationAssassinate(inst) { function attemptInfiltrationAssassinate(inst) {
var chance = getInfiltrationAssassinateChance(inst); var chance = getInfiltrationAssassinateChance(inst);
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult; inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
@ -728,8 +728,8 @@ function getInfiltrationAssassinateChance(inst) {
} }
//Destroy security // Destroy security
//Success: 5%, Failure: 10% // Success: 5%, Failure: 10%
function attemptInfiltrationDestroySecurity(inst) { function attemptInfiltrationDestroySecurity(inst) {
var chance = getInfiltrationDestroySecurityChance(inst); var chance = getInfiltrationDestroySecurityChance(inst);
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult; inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
@ -755,8 +755,8 @@ function getInfiltrationDestroySecurityChance(inst) {
} }
//Hack security // Hack security
//Success: 3%, Failure: 5% // Success: 3%, Failure: 5%
function attemptInfiltrationHack(inst) { function attemptInfiltrationHack(inst) {
var chance = getInfiltrationHackChance(inst); var chance = getInfiltrationHackChance(inst);
inst.gainHackingExp(inst.securityLevel / 30) * Player.hacking_exp_mult; inst.gainHackingExp(inst.securityLevel / 30) * Player.hacking_exp_mult;
@ -778,8 +778,8 @@ function getInfiltrationHackChance(inst) {
(intWgt * Player.intelligence)) / lvl); (intWgt * Player.intelligence)) / lvl);
} }
//Sneak past security // Sneak past security
//Success: 0%, Failure: 8% // Success: 0%, Failure: 8%
function attemptInfiltrationSneak(inst) { function attemptInfiltrationSneak(inst) {
var chance = getInfiltrationSneakChance(inst); var chance = getInfiltrationSneakChance(inst);
inst.gainAgilityExp(inst.securityLevel / 30) * Player.agility_exp_mult; inst.gainAgilityExp(inst.securityLevel / 30) * Player.agility_exp_mult;
@ -799,8 +799,8 @@ function getInfiltrationSneakChance(inst) {
intWgt * Player.intelligence) / (2 * lvl)); intWgt * Player.intelligence) / (2 * lvl));
} }
//Pick locked door // Pick locked door
//Success: 1%, Failure: 3% // Success: 1%, Failure: 3%
function attemptInfiltrationPickLockedDoor(inst) { function attemptInfiltrationPickLockedDoor(inst) {
var chance = getInfiltrationPickLockedDoorChance(inst); var chance = getInfiltrationPickLockedDoorChance(inst);
inst.gainDexterityExp(inst.securityLevel / 25) * Player.dexterity_exp_mult; inst.gainDexterityExp(inst.securityLevel / 25) * Player.dexterity_exp_mult;
@ -820,8 +820,8 @@ function getInfiltrationPickLockedDoorChance(inst) {
intWgt * Player.intelligence) / lvl); intWgt * Player.intelligence) / lvl);
} }
//Bribe // Bribe
//Success: 0%, Failure: 15%, // Success: 0%, Failure: 15%,
function attemptInfiltrationBribe(inst) { function attemptInfiltrationBribe(inst) {
var chance = getInfiltrationBribeChance(inst); var chance = getInfiltrationBribeChance(inst);
inst.gainCharismaExp(inst.securityLevel / 8) * Player.charisma_exp_mult; inst.gainCharismaExp(inst.securityLevel / 8) * Player.charisma_exp_mult;
@ -839,8 +839,8 @@ function getInfiltrationBribeChance(inst) {
(Player.charisma) / lvl); (Player.charisma) / lvl);
} }
//Escape // Escape
//Failure: 5% // Failure: 5%
function attemptInfiltrationEscape(inst) { function attemptInfiltrationEscape(inst) {
var chance = getInfiltrationEscapeChance(inst); var chance = getInfiltrationEscapeChance(inst);
inst.gainAgilityExp(inst.securityLevel / 30) * Player.agility_exp_mult; inst.gainAgilityExp(inst.securityLevel / 30) * Player.agility_exp_mult;

@ -11,27 +11,27 @@ import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElementById } from "../utils/uiHelpers/removeElementById"; import { removeElementById } from "../utils/uiHelpers/removeElementById";
//Ordered array of keys to Interactive Tutorial Steps // Ordered array of keys to Interactive Tutorial Steps
const orderedITutorialSteps = [ const orderedITutorialSteps = [
"Start", "Start",
"GoToCharacterPage", //Click on 'Stats' page "GoToCharacterPage", // Click on 'Stats' page
"CharacterPage", //Introduction to 'Stats' page "CharacterPage", // Introduction to 'Stats' page
"CharacterGoToTerminalPage", //Go back to Terminal "CharacterGoToTerminalPage", // Go back to Terminal
"TerminalIntro", //Introduction to Terminal "TerminalIntro", // Introduction to Terminal
"TerminalHelp", //Using 'help' Terminal command "TerminalHelp", // Using 'help' Terminal command
"TerminalLs", //Using 'ls' Terminal command "TerminalLs", // Using 'ls' Terminal command
"TerminalScan", //Using 'scan' Terminal command "TerminalScan", // Using 'scan' Terminal command
"TerminalScanAnalyze1", //Using 'scan-analyze' Terminal command "TerminalScanAnalyze1", // Using 'scan-analyze' Terminal command
"TerminalScanAnalyze2", //Using 'scan-analyze 3' Terminal command "TerminalScanAnalyze2", // Using 'scan-analyze 3' Terminal command
"TerminalConnect", //Connecting to foodnstuff "TerminalConnect", // Connecting to foodnstuff
"TerminalAnalyze", //Analyzing foodnstuff "TerminalAnalyze", // Analyzing foodnstuff
"TerminalNuke", //NUKE foodnstuff "TerminalNuke", // NUKE foodnstuff
"TerminalManualHack", //Hack foodnstuff "TerminalManualHack", // Hack foodnstuff
"TerminalHackingMechanics", //Explanation of hacking mechanics "TerminalHackingMechanics", // Explanation of hacking mechanics
"TerminalCreateScript", //Create a script using 'nano' "TerminalCreateScript", // Create a script using 'nano'
"TerminalTypeScript", //Script Editor page - Type script and then save & close "TerminalTypeScript", // Script Editor page - Type script and then save & close
"TerminalFree", //Using 'Free' Terminal command "TerminalFree", // Using 'Free' Terminal command
"TerminalRunScript", //Running script using 'run' Terminal command "TerminalRunScript", // Running script using 'run' Terminal command
"TerminalGoToActiveScriptsPage", "TerminalGoToActiveScriptsPage",
"ActiveScriptsPage", "ActiveScriptsPage",
"ActiveScriptsToTerminal", "ActiveScriptsToTerminal",
@ -44,22 +44,22 @@ const orderedITutorialSteps = [
"End" "End"
] ]
//Create an 'enum' for the Steps // Create an 'enum' for the Steps
const iTutorialSteps = {}; const iTutorialSteps = {};
for (let i = 0; i < orderedITutorialSteps.length; ++i) { for (let i = 0; i < orderedITutorialSteps.length; ++i) {
iTutorialSteps[orderedITutorialSteps[i]] = i; iTutorialSteps[orderedITutorialSteps[i]] = i;
} }
var ITutorial = { var ITutorial = {
currStep: 0, //iTutorialSteps.Start currStep: 0, // iTutorialSteps.Start
isRunning: false, isRunning: false,
//Keeps track of whether each step has been done // Keeps track of whether each step has been done
stepIsDone: {}, stepIsDone: {},
} }
function iTutorialStart() { function iTutorialStart() {
//Initialize Interactive Tutorial state by settings 'done' for each state to false // Initialize Interactive Tutorial state by settings 'done' for each state to false
ITutorial.stepIsDone = {}; ITutorial.stepIsDone = {};
for (let i = 0; i < orderedITutorialSteps.length; ++i) { for (let i = 0; i < orderedITutorialSteps.length; ++i) {
ITutorial.stepIsDone[i] = false; ITutorial.stepIsDone[i] = false;
@ -67,7 +67,7 @@ function iTutorialStart() {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
//Don't autosave during this interactive tutorial // Don't autosave during this interactive tutorial
Engine.Counters.autoSaveCounter = Infinity; Engine.Counters.autoSaveCounter = Infinity;
console.log("Interactive Tutorial started"); console.log("Interactive Tutorial started");
ITutorial.currStep = 0; ITutorial.currStep = 0;
@ -75,21 +75,21 @@ function iTutorialStart() {
document.getElementById("interactive-tutorial-container").style.display = "block"; document.getElementById("interactive-tutorial-container").style.display = "block";
//Exit tutorial button // Exit tutorial button
var exitButton = clearEventListeners("interactive-tutorial-exit"); var exitButton = clearEventListeners("interactive-tutorial-exit");
exitButton.addEventListener("click", function() { exitButton.addEventListener("click", function() {
iTutorialEnd(); iTutorialEnd();
return false; return false;
}); });
//Back button // Back button
var backButton = clearEventListeners("interactive-tutorial-back"); var backButton = clearEventListeners("interactive-tutorial-back");
backButton.addEventListener("click", function() { backButton.addEventListener("click", function() {
iTutorialPrevStep(); iTutorialPrevStep();
return false; return false;
}); });
//Next button // Next button
var nextButton = clearEventListeners("interactive-tutorial-next"); var nextButton = clearEventListeners("interactive-tutorial-next");
nextButton.addEventListener("click", function() { nextButton.addEventListener("click", function() {
iTutorialNextStep(); iTutorialNextStep();
@ -102,7 +102,7 @@ function iTutorialStart() {
function iTutorialEvaluateStep() { function iTutorialEvaluateStep() {
if (!ITutorial.isRunning) {console.log("Interactive Tutorial not running"); return;} if (!ITutorial.isRunning) {console.log("Interactive Tutorial not running"); return;}
//Disable and clear main menu // Disable and clear main menu
var terminalMainMenu = clearEventListeners("terminal-menu-link"); var terminalMainMenu = clearEventListeners("terminal-menu-link");
var statsMainMenu = clearEventListeners("stats-menu-link"); var statsMainMenu = clearEventListeners("stats-menu-link");
var activeScriptsMainMenu = clearEventListeners("active-scripts-menu-link"); var activeScriptsMainMenu = clearEventListeners("active-scripts-menu-link");
@ -116,7 +116,7 @@ function iTutorialEvaluateStep() {
cityMainMenu.removeAttribute("class"); cityMainMenu.removeAttribute("class");
tutorialMainMenu.removeAttribute("class"); tutorialMainMenu.removeAttribute("class");
//Interactive Tutorial Next button // Interactive Tutorial Next button
var nextBtn = document.getElementById("interactive-tutorial-next"); var nextBtn = document.getElementById("interactive-tutorial-next");
switch(ITutorial.currStep) { switch(ITutorial.currStep) {
@ -134,7 +134,7 @@ function iTutorialEvaluateStep() {
"the main navigation menu (left-hand side of the screen)"); "the main navigation menu (left-hand side of the screen)");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'Stats' menu and set its tutorial click handler // Flash 'Stats' menu and set its tutorial click handler
statsMainMenu.setAttribute("class", "flashing-button"); statsMainMenu.setAttribute("class", "flashing-button");
statsMainMenu.addEventListener("click", function() { statsMainMenu.addEventListener("click", function() {
Engine.loadCharacterContent(); Engine.loadCharacterContent();
@ -154,7 +154,7 @@ function iTutorialEvaluateStep() {
"main navigation menu."); "main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'Terminal' menu and set its tutorial click handler // Flash 'Terminal' menu and set its tutorial click handler
terminalMainMenu.setAttribute("class", "flashing-button"); terminalMainMenu.setAttribute("class", "flashing-button");
terminalMainMenu.addEventListener("click", function() { terminalMainMenu.addEventListener("click", function() {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -172,13 +172,13 @@ function iTutorialEvaluateStep() {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Let's try it out. Start by entering the 'help' command into the Terminal " + iTutorialSetText("Let's try it out. Start by entering the 'help' command into the Terminal " +
"(Don't forget to press Enter after typing the command)"); "(Don't forget to press Enter after typing the command)");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalLs: case iTutorialSteps.TerminalLs:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("The 'help' command displays a list of all available Terminal commands, how to use them, " + iTutorialSetText("The 'help' command displays a list of all available Terminal commands, how to use them, " +
"and a description of what they do. <br><br>Let's try another command. Enter the 'ls' command"); "and a description of what they do. <br><br>Let's try another command. Enter the 'ls' command");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalScan: case iTutorialSteps.TerminalScan:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -187,7 +187,7 @@ function iTutorialEvaluateStep() {
"We'll get to what this does later. <br><br>Using your home computer's terminal, you can connect " + "We'll get to what this does later. <br><br>Using your home computer's terminal, you can connect " +
"to other machines throughout the world. Let's do that now by first entering " + "to other machines throughout the world. Let's do that now by first entering " +
"the 'scan' command."); "the 'scan' command.");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalScanAnalyze1: case iTutorialSteps.TerminalScanAnalyze1:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -197,7 +197,7 @@ function iTutorialEvaluateStep() {
"That's great and all, but there's so many servers. Which one should you go to? " + "That's great and all, but there's so many servers. Which one should you go to? " +
"The 'scan-analyze' command gives some more detailed information about servers on the " + "The 'scan-analyze' command gives some more detailed information about servers on the " +
"network. Try it now"); "network. Try it now");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalScanAnalyze2: case iTutorialSteps.TerminalScanAnalyze2:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -205,7 +205,7 @@ function iTutorialEvaluateStep() {
"information about each server that you can connect to (servers that are a distance of " + "information about each server that you can connect to (servers that are a distance of " +
"one node away). <br><br> It is also possible to run 'scan-analyze' with " + "one node away). <br><br> It is also possible to run 'scan-analyze' with " +
"a higher depth. Let's try a depth of two with the following command: 'scan-analyze 2'.") "a higher depth. Let's try a depth of two with the following command: 'scan-analyze 2'.")
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalConnect: case iTutorialSteps.TerminalConnect:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -215,7 +215,7 @@ function iTutorialEvaluateStep() {
"the ip or the hostname, but dont use both.<br><br>" + "the ip or the hostname, but dont use both.<br><br>" +
"From the results of the 'scan-analyze' command, we can see that the 'foodnstuff' server is " + "From the results of the 'scan-analyze' command, we can see that the 'foodnstuff' server is " +
"only one node away. Let's connect so it now using: 'connect foodnstuff'"); "only one node away. Let's connect so it now using: 'connect foodnstuff'");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalAnalyze: case iTutorialSteps.TerminalAnalyze:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -224,7 +224,7 @@ function iTutorialEvaluateStep() {
"on servers and computers. Using your hacking abilities, you can hack servers " + "on servers and computers. Using your hacking abilities, you can hack servers " +
"to steal money and gain experience. <br><br> " + "to steal money and gain experience. <br><br> " +
"Before you try to hack a server, you should run diagnostics using the 'analyze' command"); "Before you try to hack a server, you should run diagnostics using the 'analyze' command");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalNuke: case iTutorialSteps.TerminalNuke:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -236,13 +236,13 @@ function iTutorialEvaluateStep() {
"open ports.<br><br> The 'analyze' results shows that there do not need to be any open ports " + "open ports.<br><br> The 'analyze' results shows that there do not need to be any open ports " +
"on this machine for the NUKE virus to work, so go ahead and run the virus using the " + "on this machine for the NUKE virus to work, so go ahead and run the virus using the " +
"'run NUKE.exe' command."); "'run NUKE.exe' command.");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalManualHack: case iTutorialSteps.TerminalManualHack:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("You now have root access! You can hack the server using the 'hack' command. " + iTutorialSetText("You now have root access! You can hack the server using the 'hack' command. " +
"Try doing that now."); "Try doing that now.");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalHackingMechanics: case iTutorialSteps.TerminalHackingMechanics:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -265,7 +265,7 @@ function iTutorialEvaluateStep() {
"command. Scripts must end with the '.script' extension. Let's make a script now by " + "command. Scripts must end with the '.script' extension. Let's make a script now by " +
"entering 'nano foodnstuff.script' after the hack command finishes running (Sidenote: Pressing ctrl + c" + "entering 'nano foodnstuff.script' after the hack command finishes running (Sidenote: Pressing ctrl + c" +
" will end a command like hack early)"); " will end a command like hack early)");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalTypeScript: case iTutorialSteps.TerminalTypeScript:
Engine.loadScriptEditorContent("foodnstuff.script", ""); Engine.loadScriptEditorContent("foodnstuff.script", "");
@ -281,7 +281,7 @@ function iTutorialEvaluateStep() {
"For anyone with basic programming experience, this code should be straightforward. " + "For anyone with basic programming experience, this code should be straightforward. " +
"This script will continuously hack the 'foodnstuff' server.<br><br>" + "This script will continuously hack the 'foodnstuff' server.<br><br>" +
"To save and close the script editor, press the button in the bottom left, or press ctrl + b."); "To save and close the script editor, press the button in the bottom left, or press ctrl + b.");
nextBtn.style.display = "none"; //next step triggered in saveAndCloseScriptEditor() (Script.js) nextBtn.style.display = "none"; // next step triggered in saveAndCloseScriptEditor() (Script.js)
break; break;
case iTutorialSteps.TerminalFree: case iTutorialSteps.TerminalFree:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -289,13 +289,13 @@ function iTutorialEvaluateStep() {
"run on any machine which you have root access to. Different servers have different " + "run on any machine which you have root access to. Different servers have different " +
"amounts of RAM. You can also purchase more RAM for your home server.<br><br>To check how much " + "amounts of RAM. You can also purchase more RAM for your home server.<br><br>To check how much " +
"RAM is available on this machine, enter the 'free' command."); "RAM is available on this machine, enter the 'free' command.");
nextBtn.style.display = "none"; //next step triggered by terminal commmand nextBtn.style.display = "none"; // next step triggered by terminal commmand
break; break;
case iTutorialSteps.TerminalRunScript: case iTutorialSteps.TerminalRunScript:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("We have 16GB of free RAM on this machine, which is enough to run our " + iTutorialSetText("We have 16GB of free RAM on this machine, which is enough to run our " +
"script. Let's run our script using 'run foodnstuff.script'."); "script. Let's run our script using 'run foodnstuff.script'.");
nextBtn.style.display = "none"; //next step triggered by terminal commmand nextBtn.style.display = "none"; // next step triggered by terminal commmand
break; break;
case iTutorialSteps.TerminalGoToActiveScriptsPage: case iTutorialSteps.TerminalGoToActiveScriptsPage:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -309,7 +309,7 @@ function iTutorialEvaluateStep() {
"'Active Scripts' link in the main navigation menu."); "'Active Scripts' link in the main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'Active Scripts' menu and set its tutorial click handler // Flash 'Active Scripts' menu and set its tutorial click handler
activeScriptsMainMenu.setAttribute("class", "flashing-button"); activeScriptsMainMenu.setAttribute("class", "flashing-button");
activeScriptsMainMenu.addEventListener("click", function() { activeScriptsMainMenu.addEventListener("click", function() {
Engine.loadActiveScriptsContent(); Engine.loadActiveScriptsContent();
@ -325,7 +325,7 @@ function iTutorialEvaluateStep() {
"link."); "link.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'Terminal' button and set its tutorial click handler // Flash 'Terminal' button and set its tutorial click handler
terminalMainMenu.setAttribute("class", "flashing-button"); terminalMainMenu.setAttribute("class", "flashing-button");
terminalMainMenu.addEventListener("click", function() { terminalMainMenu.addEventListener("click", function() {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -338,7 +338,7 @@ function iTutorialEvaluateStep() {
iTutorialSetText("One last thing about scripts, each active script contains logs that detail " + iTutorialSetText("One last thing about scripts, each active script contains logs that detail " +
"what it's doing. We can check these logs using the 'tail' command. Do that " + "what it's doing. We can check these logs using the 'tail' command. Do that " +
"now for the script we just ran by typing 'tail foodnstuff.script'"); "now for the script we just ran by typing 'tail foodnstuff.script'");
nextBtn.style.display = "none"; //next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalTailScript: case iTutorialSteps.TerminalTailScript:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -359,7 +359,7 @@ function iTutorialEvaluateStep() {
"the 'Hacknet Nodes' page through the main navigation menu now."); "the 'Hacknet Nodes' page through the main navigation menu now.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'Hacknet' menu and set its tutorial click handler // Flash 'Hacknet' menu and set its tutorial click handler
hacknetMainMenu.setAttribute("class", "flashing-button"); hacknetMainMenu.setAttribute("class", "flashing-button");
hacknetMainMenu.addEventListener("click", function() { hacknetMainMenu.addEventListener("click", function() {
Engine.loadHacknetNodesContent(); Engine.loadHacknetNodesContent();
@ -371,7 +371,7 @@ function iTutorialEvaluateStep() {
Engine.loadHacknetNodesContent(); Engine.loadHacknetNodesContent();
iTutorialSetText("From this page you can purchase new Hacknet Nodes and upgrade your " + iTutorialSetText("From this page you can purchase new Hacknet Nodes and upgrade your " +
"existing ones. Let's purchase a new one now."); "existing ones. Let's purchase a new one now.");
nextBtn.style.display = "none"; //Next step triggered by purchaseHacknet() (HacknetNode.js) nextBtn.style.display = "none"; // Next step triggered by purchaseHacknet() (HacknetNode.js)
break; break;
case iTutorialSteps.HacknetNodesGoToWorldPage: case iTutorialSteps.HacknetNodesGoToWorldPage:
Engine.loadHacknetNodesContent(); Engine.loadHacknetNodesContent();
@ -382,7 +382,7 @@ function iTutorialEvaluateStep() {
"Let's go to the 'City' page through the main navigation menu."); "Let's go to the 'City' page through the main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'City' menu and set its tutorial click handler // Flash 'City' menu and set its tutorial click handler
cityMainMenu.setAttribute("class", "flashing-button"); cityMainMenu.setAttribute("class", "flashing-button");
cityMainMenu.addEventListener("click", function() { cityMainMenu.addEventListener("click", function() {
Engine.loadLocationContent(); Engine.loadLocationContent();
@ -399,7 +399,7 @@ function iTutorialEvaluateStep() {
"Lastly, click on the 'Tutorial' link in the main navigation menu."); "Lastly, click on the 'Tutorial' link in the main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
//Flash 'Tutorial' menu and set its tutorial click handler // Flash 'Tutorial' menu and set its tutorial click handler
tutorialMainMenu.setAttribute("class", "flashing-button"); tutorialMainMenu.setAttribute("class", "flashing-button");
tutorialMainMenu.addEventListener("click", function() { tutorialMainMenu.addEventListener("click", function() {
Engine.loadTutorialContent(); Engine.loadTutorialContent();
@ -428,9 +428,9 @@ function iTutorialEvaluateStep() {
} }
} }
//Go to the next step and evaluate it // Go to the next step and evaluate it
function iTutorialNextStep() { function iTutorialNextStep() {
//Special behavior for certain steps // Special behavior for certain steps
if (ITutorial.currStep === iTutorialSteps.GoToCharacterPage) { if (ITutorial.currStep === iTutorialSteps.GoToCharacterPage) {
document.getElementById("stats-menu-link").removeAttribute("class"); document.getElementById("stats-menu-link").removeAttribute("class");
} }
@ -460,7 +460,7 @@ function iTutorialNextStep() {
iTutorialEvaluateStep(); iTutorialEvaluateStep();
} }
//Go to previous step and evaluate // Go to previous step and evaluate
function iTutorialPrevStep() { function iTutorialPrevStep() {
if (ITutorial.currStep > iTutorialSteps.Start) { if (ITutorial.currStep > iTutorialSteps.Start) {
ITutorial.currStep -= 1; ITutorial.currStep -= 1;
@ -469,7 +469,7 @@ function iTutorialPrevStep() {
} }
function iTutorialEnd() { function iTutorialEnd() {
//Re-enable auto save // Re-enable auto save
if (Settings.AutosaveInterval === 0) { if (Settings.AutosaveInterval === 0) {
Engine.Counters.autoSaveCounter = Infinity; Engine.Counters.autoSaveCounter = Infinity;
} else { } else {
@ -494,7 +494,7 @@ function iTutorialEnd() {
ITutorial.isRunning = false; ITutorial.isRunning = false;
document.getElementById("interactive-tutorial-container").style.display = "none"; document.getElementById("interactive-tutorial-container").style.display = "none";
//Create a popup with final introductory stuff // Create a popup with final introductory stuff
var popupId = "interactive-tutorial-ending-popup"; var popupId = "interactive-tutorial-ending-popup";
var txt = createElement("p", { var txt = createElement("p", {
innerHTML: innerHTML:

@ -1,8 +1,9 @@
/**
* Lore / world building literature files that can be found on servers.
* These files can be read by the player
*/
import { dialogBoxCreate } from "../utils/DialogBox"; import { dialogBoxCreate } from "../utils/DialogBox";
/* Literature.js
* Lore / world building literature that can be found on servers
*/
function Literature(title, filename, txt) { function Literature(title, filename, txt) {
this.title = title; this.title = title;
this.fn = filename; this.fn = filename;
@ -10,10 +11,9 @@ function Literature(title, filename, txt) {
} }
function showLiterature(fn) { function showLiterature(fn) {
var litObj = Literatures[fn]; const litObj = Literatures[fn];
if (litObj == null) {return;} if (litObj == null) { return; }
var txt = "<i>" + litObj.title + "</i><br><br>" + const txt = `<i>${litObj.title}</i><br><br>${litObj.txt}`;
litObj.txt;
dialogBoxCreate(txt); dialogBoxCreate(txt);
} }
@ -430,7 +430,10 @@ function initLiterature() {
fn = "the-secret-war.lit"; fn = "the-secret-war.lit";
txt = "" txt = ""
Literatures[fn] = new Literature(title, fn, txt); Literatures[fn] = new Literature(title, fn, txt);
} }
export {Literatures, initLiterature, showLiterature}; export {
Literatures,
initLiterature,
showLiterature
};

@ -15,7 +15,7 @@ import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
import jsplumb from "jsplumb"; import jsplumb from "jsplumb";
let inMission = false; //Flag to denote whether a mission is running let inMission = false; // Flag to denote whether a mission is running
let currMission = null; let currMission = null;
function setInMission(bool, mission) { function setInMission(bool, mission) {
inMission = bool; inMission = bool;
@ -26,26 +26,26 @@ function setInMission(bool, mission) {
} }
} }
//Keyboard shortcuts // Keyboard shortcuts
$(document).keydown(function(e) { $(document).keydown(function(e) {
if (inMission && currMission && currMission.selectedNode.length != 0) { if (inMission && currMission && currMission.selectedNode.length != 0) {
switch (e.keyCode) { switch (e.keyCode) {
case 65: //a for Attack case 65: // a for Attack
currMission.actionButtons[0].click(); currMission.actionButtons[0].click();
break; break;
case 83: //s for Scan case 83: // s for Scan
currMission.actionButtons[1].click(); currMission.actionButtons[1].click();
break; break;
case 87: //w for Weaken case 87: // w for Weaken
currMission.actionButtons[2].click(); currMission.actionButtons[2].click();
break; break;
case 70: //f for Fortify case 70: // f for Fortify
currMission.actionButtons[3].click(); currMission.actionButtons[3].click();
break; break;
case 82: //r for Overflow case 82: // r for Overflow
currMission.actionButtons[4].click(); currMission.actionButtons[4].click();
break; break;
case 68: //d for Detach connection case 68: // d for Detach connection
currMission.actionButtons[5].click(); currMission.actionButtons[5].click();
break; break;
default: default:
@ -55,20 +55,20 @@ $(document).keydown(function(e) {
}); });
let NodeTypes = { let NodeTypes = {
Core: "CPU Core Node", //All actions available Core: "CPU Core Node", // All actions available
Firewall: "Firewall Node", //No actions available Firewall: "Firewall Node", // No actions available
Database: "Database Node", //No actions available Database: "Database Node", // No actions available
Spam: "Spam Node", //No actions Available Spam: "Spam Node", // No actions Available
Transfer: "Transfer Node", //Can Weaken, Scan, Fortify and Overflow Transfer: "Transfer Node", // Can Weaken, Scan, Fortify and Overflow
Shield: "Shield Node" //Can Fortify Shield: "Shield Node" // Can Fortify
} }
let NodeActions = { let NodeActions = {
Attack: "Attacking", //Damaged based on attack stat + hacking level + opp def Attack: "Attacking", // Damaged based on attack stat + hacking level + opp def
Scan: "Scanning", //-Def for target, affected by attack and hacking level Scan: "Scanning", // -Def for target, affected by attack and hacking level
Weaken: "Weakening", //-Attack for target, affected by attack and hacking level Weaken: "Weakening", // -Attack for target, affected by attack and hacking level
Fortify: "Fortifying", //+Defense for Node, affected by hacking level Fortify: "Fortifying", // +Defense for Node, affected by hacking level
Overflow: "Overflowing", //+Attack but -Defense for Node, affected by hacking level Overflow: "Overflowing", // +Attack but -Defense for Node, affected by hacking level
} }
function Node(type, stats) { function Node(type, stats) {
@ -79,14 +79,15 @@ function Node(type, stats) {
this.maxhp = this.hp; this.maxhp = this.hp;
this.plyrCtrl = false; this.plyrCtrl = false;
this.enmyCtrl = false; this.enmyCtrl = false;
this.pos = [0, 0]; //x, y this.pos = [0, 0]; // x, y
this.el = null; //Holds the Node's DOM element this.el = null; // Holds the Node's DOM element
this.action = null; this.action = null;
this.targetedCount = 0; //Count of how many connections this node is the target of this.targetedCount = 0; // Count of how many connections this node is the target of
//Holds the JsPlumb Connection object for this Node, /**
//where this Node is the Source (since each Node * Holds the JsPlumb Connection object for this Node, where this Node is the Source (since each Node
//can only have 1 outgoing Connection) * can only have 1 outgoing Connection)
*/
this.conn = null; this.conn = null;
} }
@ -112,12 +113,12 @@ Node.prototype.setControlledByEnemy = function() {
} }
} }
//Sets this node to be the active node // Sets this node to be the active node
Node.prototype.select = function(actionButtons) { Node.prototype.select = function(actionButtons) {
if (this.enmyCtrl) {return;} if (this.enmyCtrl) {return;}
this.el.classList.add("hack-mission-player-node-active"); this.el.classList.add("hack-mission-player-node-active");
//Make all buttons inactive // Make all buttons inactive
for (var i = 0; i < actionButtons.length; ++i) { for (var i = 0; i < actionButtons.length; ++i) {
actionButtons[i].classList.remove("a-link-button"); actionButtons[i].classList.remove("a-link-button");
actionButtons[i].classList.add("a-link-button-inactive"); actionButtons[i].classList.add("a-link-button-inactive");
@ -125,7 +126,7 @@ Node.prototype.select = function(actionButtons) {
switch(this.type) { switch(this.type) {
case NodeTypes.Core: case NodeTypes.Core:
//All buttons active // All buttons active
for (var i = 0; i < actionButtons.length; ++i) { for (var i = 0; i < actionButtons.length; ++i) {
actionButtons[i].classList.remove("a-link-button-inactive"); actionButtons[i].classList.remove("a-link-button-inactive");
actionButtons[i].classList.add("a-link-button"); actionButtons[i].classList.add("a-link-button");
@ -170,31 +171,33 @@ Node.prototype.untarget = function() {
--this.targetedCount; --this.targetedCount;
} }
//Hacking mission instance /**
//Takes in the reputation of the Faction for which the mission is * Hacking mission instance
//being conducted * @param rep {number} How much reputation the player has for the faction
* @param fac {Faction} Faction for which this mission is being conducted
*/
function HackingMission(rep, fac) { function HackingMission(rep, fac) {
this.faction = fac; this.faction = fac;
this.started = false; this.started = false;
this.time = 180000; //5 minutes to start, milliseconds this.time = 180000; // 5 minutes to start, milliseconds
this.playerCores = []; this.playerCores = [];
this.playerNodes = []; //Non-core nodes this.playerNodes = []; // Non-core nodes
this.playerAtk = 0; this.playerAtk = 0;
this.playerDef = 0; this.playerDef = 0;
this.enemyCores = []; this.enemyCores = [];
this.enemyDatabases = []; this.enemyDatabases = [];
this.enemyNodes = []; //Non-core nodes this.enemyNodes = []; // Non-core nodes
this.enemyAtk = 0; this.enemyAtk = 0;
this.enemyDef = 0; this.enemyDef = 0;
this.miscNodes = []; this.miscNodes = [];
this.selectedNode = []; //Which of the player's nodes are currently selected this.selectedNode = []; // Which of the player's nodes are currently selected
this.actionButtons = []; //DOM buttons for actions this.actionButtons = []; // DOM buttons for actions
this.availablePositions = []; this.availablePositions = [];
for (var r = 0; r < 8; ++r) { for (var r = 0; r < 8; ++r) {
@ -216,10 +219,10 @@ function HackingMission(rep, fac) {
} }
HackingMission.prototype.init = function() { HackingMission.prototype.init = function() {
//Create Header DOM // Create Header DOM
this.createPageDom(); this.createPageDom();
//Create player starting nodes // Create player starting nodes
var home = Player.getHomeComputer() var home = Player.getHomeComputer()
for (var i = 0; i < home.cpuCores; ++i) { for (var i = 0; i < home.cpuCores; ++i) {
var stats = { var stats = {
@ -233,7 +236,7 @@ HackingMission.prototype.init = function() {
this.removeAvailablePosition(i, 0); this.removeAvailablePosition(i, 0);
} }
//Randomly generate enemy nodes (CPU and Firewall) based on difficulty // Randomly generate enemy nodes (CPU and Firewall) based on difficulty
var numNodes = Math.min(8, Math.max(1, Math.round(this.difficulty / 4))); var numNodes = Math.min(8, Math.max(1, Math.round(this.difficulty / 4)));
var numFirewalls = Math.min(20, var numFirewalls = Math.min(20,
getRandomInt(Math.round(this.difficulty/3), Math.round(this.difficulty/3) + 1)); getRandomInt(Math.round(this.difficulty/3), Math.round(this.difficulty/3) + 1));
@ -309,10 +312,10 @@ HackingMission.prototype.createPageDom = function() {
wikiGuideBtn.style.display = "inline-block"; wikiGuideBtn.style.display = "inline-block";
wikiGuideBtn.classList.add("hack-mission-header-element"); wikiGuideBtn.classList.add("hack-mission-header-element");
wikiGuideBtn.target = "_blank"; wikiGuideBtn.target = "_blank";
//TODO Add link to wiki page wikiGuideBtn.href = // TODO Add link to wiki page wikiGuideBtn.href =
//Start button will get replaced with forfeit when game is started // Start button will get replaced with forfeit when game is started
var startBtn = document.createElement("a"); var startBtn = document.createElement("a");
startBtn.innerHTML = "Start"; startBtn.innerHTML = "Start";
startBtn.setAttribute("id", "hack-mission-start-btn"); startBtn.setAttribute("id", "hack-mission-start-btn");
@ -339,15 +342,15 @@ HackingMission.prototype.createPageDom = function() {
timer.style.display = "inline-block"; timer.style.display = "inline-block";
timer.style.margin = "6px"; timer.style.margin = "6px";
//Create Action Buttons (Attack/Scan/Weaken/ etc...) // Create Action Buttons (Attack/Scan/Weaken/ etc...)
var actionsContainer = document.createElement("span"); var actionsContainer = document.createElement("span");
actionsContainer.style.display = "block"; actionsContainer.style.display = "block";
actionsContainer.classList.add("hack-mission-action-buttons-container"); actionsContainer.classList.add("hack-mission-action-buttons-container");
for (var i = 0; i < 6; ++i) { for (var i = 0; i < 6; ++i) {
this.actionButtons.push(document.createElement("a")); this.actionButtons.push(document.createElement("a"));
this.actionButtons[i].style.display = "inline-block"; this.actionButtons[i].style.display = "inline-block";
this.actionButtons[i].classList.add("a-link-button-inactive"); //Disabled at start this.actionButtons[i].classList.add("a-link-button-inactive"); // Disabled at start
this.actionButtons[i].classList.add("tooltip"); //Disabled at start this.actionButtons[i].classList.add("tooltip"); // Disabled at start
this.actionButtons[i].classList.add("hack-mission-header-element"); this.actionButtons[i].classList.add("hack-mission-header-element");
actionsContainer.appendChild(this.actionButtons[i]); actionsContainer.appendChild(this.actionButtons[i]);
} }
@ -388,7 +391,7 @@ HackingMission.prototype.createPageDom = function() {
"also be done by simply clicking the white connection line."; "also be done by simply clicking the white connection line.";
this.actionButtons[5].appendChild(dropconnTooltip); this.actionButtons[5].appendChild(dropconnTooltip);
//Player/enemy defense displays will be in action container // Player/enemy defense displays will be in action container
var playerStats = document.createElement("p"); var playerStats = document.createElement("p");
var enemyStats = document.createElement("p"); var enemyStats = document.createElement("p");
playerStats.style.display = "inline-block"; playerStats.style.display = "inline-block";
@ -402,7 +405,7 @@ HackingMission.prototype.createPageDom = function() {
actionsContainer.appendChild(playerStats); actionsContainer.appendChild(playerStats);
actionsContainer.appendChild(enemyStats); actionsContainer.appendChild(enemyStats);
//Set Action Button event listeners // Set Action Button event listeners
this.actionButtons[0].addEventListener("click", ()=>{ this.actionButtons[0].addEventListener("click", ()=>{
if (!(this.selectedNode.length > 0)) { if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node"); console.log("ERR: Pressing Action button without selected node");
@ -410,7 +413,7 @@ HackingMission.prototype.createPageDom = function() {
} }
if (this.selectedNode[0].type !== NodeTypes.Core) {return;} if (this.selectedNode[0].type !== NodeTypes.Core) {return;}
this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButtonsActive(this.selectedNode[0].type);
this.setActionButton(NodeActions.Attack, false); //Set attack button inactive this.setActionButton(NodeActions.Attack, false); // Set attack button inactive
this.selectedNode.forEach(function(node){ this.selectedNode.forEach(function(node){
node.action = NodeActions.Attack; node.action = NodeActions.Attack;
}); });
@ -421,10 +424,10 @@ HackingMission.prototype.createPageDom = function() {
console.log("ERR: Pressing Action button without selected node"); console.log("ERR: Pressing Action button without selected node");
return; return;
} }
var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
this.setActionButtonsActive(nodeType); this.setActionButtonsActive(nodeType);
this.setActionButton(NodeActions.Scan, false); //Set scan button inactive this.setActionButton(NodeActions.Scan, false); // Set scan button inactive
this.selectedNode.forEach(function(node){ this.selectedNode.forEach(function(node){
node.action = NodeActions.Scan; node.action = NodeActions.Scan;
}); });
@ -435,10 +438,10 @@ HackingMission.prototype.createPageDom = function() {
console.log("ERR: Pressing Action button without selected node"); console.log("ERR: Pressing Action button without selected node");
return; return;
} }
var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
this.setActionButtonsActive(nodeType); this.setActionButtonsActive(nodeType);
this.setActionButton(NodeActions.Weaken, false); //Set Weaken button inactive this.setActionButton(NodeActions.Weaken, false); // Set Weaken button inactive
this.selectedNode.forEach(function(node){ this.selectedNode.forEach(function(node){
node.action = NodeActions.Weaken; node.action = NodeActions.Weaken;
}); });
@ -450,7 +453,7 @@ HackingMission.prototype.createPageDom = function() {
return; return;
} }
this.setActionButtonsActive(this.selectedNode[0].type); this.setActionButtonsActive(this.selectedNode[0].type);
this.setActionButton(NodeActions.Fortify, false); //Set Fortify button inactive this.setActionButton(NodeActions.Fortify, false); // Set Fortify button inactive
this.selectedNode.forEach(function(node){ this.selectedNode.forEach(function(node){
node.action = NodeActions.Fortify; node.action = NodeActions.Fortify;
}); });
@ -464,7 +467,7 @@ HackingMission.prototype.createPageDom = function() {
var nodeType = this.selectedNode[0].type; var nodeType = this.selectedNode[0].type;
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;} if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
this.setActionButtonsActive(nodeType); this.setActionButtonsActive(nodeType);
this.setActionButton(NodeActions.Overflow, false); //Set Overflow button inactive this.setActionButton(NodeActions.Overflow, false); // Set Overflow button inactive
this.selectedNode.forEach(function(node){ this.selectedNode.forEach(function(node){
node.action = NodeActions.Overflow; node.action = NodeActions.Overflow;
}); });
@ -482,11 +485,7 @@ HackingMission.prototype.createPageDom = function() {
} }
node.action = NodeActions.Fortify; node.action = NodeActions.Fortify;
}); });
// if (this.selectedNode.conn) { });
// var endpoints = this.selectedNode.conn.endpoints;
// endpoints[0].detachFrom(endpoints[1]);
// }
})
var timeDisplay = document.createElement("p"); var timeDisplay = document.createElement("p");
@ -513,8 +512,10 @@ HackingMission.prototype.setActionButtonsActive = function(nodeType=null) {
this.actionButtons[i].classList.remove("a-link-button-inactive"); this.actionButtons[i].classList.remove("a-link-button-inactive");
} }
//For Transfer, FireWall and Shield Nodes, certain buttons should always be disabled /**
//0 = Attack, 1 = Scan, 2 = Weaken, 3 = Fortify, 4 = overflow, 5 = Drop conn * For Transfer, FireWall and Shield Nodes, certain buttons should always be disabled
* 0 = Attack, 1 = Scan, 2 = Weaken, 3 = Fortify, 4 = overflow, 5 = Drop conn
*/
if (nodeType) { if (nodeType) {
switch (nodeType) { switch (nodeType) {
case NodeTypes.Firewall: case NodeTypes.Firewall:
@ -540,7 +541,7 @@ HackingMission.prototype.setActionButtonsActive = function(nodeType=null) {
} }
} }
//True for active, false for inactive // True for active, false for inactive
HackingMission.prototype.setActionButton = function(i, active=true) { HackingMission.prototype.setActionButton = function(i, active=true) {
if (isString(i)) { if (isString(i)) {
switch (i) { switch (i) {
@ -657,7 +658,7 @@ HackingMission.prototype.setNodePosition = function(nodeObj, x, y) {
HackingMission.prototype.setNodeRandomPosition = function(nodeObj, xlimit=0) { HackingMission.prototype.setNodeRandomPosition = function(nodeObj, xlimit=0) {
var i = getRandomInt(0, this.availablePositions.length - 1); var i = getRandomInt(0, this.availablePositions.length - 1);
if (this.availablePositions[i][1] < xlimit) { if (this.availablePositions[i][1] < xlimit) {
//Recurse if not within limit // Recurse if not within limit
return this.setNodeRandomPosition(nodeObj, xlimit); return this.setNodeRandomPosition(nodeObj, xlimit);
} }
var pos = this.availablePositions.splice(i, 1); var pos = this.availablePositions.splice(i, 1);
@ -666,15 +667,15 @@ HackingMission.prototype.setNodeRandomPosition = function(nodeObj, xlimit=0) {
} }
HackingMission.prototype.createMap = function() { HackingMission.prototype.createMap = function() {
//Use a grid // Use a grid
var map = document.createElement("div"); var map = document.createElement("div");
map.classList.add("hack-mission-grid"); map.classList.add("hack-mission-grid");
map.setAttribute("id", "hacking-mission-map"); map.setAttribute("id", "hacking-mission-map");
document.getElementById("mission-container").appendChild(map); document.getElementById("mission-container").appendChild(map);
//Create random Nodes for every space in the map that // Create random Nodes for every space in the map that
//hasn't been filled yet. The stats of each Node will be based on // hasn't been filled yet. The stats of each Node will be based on
//the player/enemy attack // the player/enemy attack
var averageAttack = (this.playerAtk + this.enemyAtk) / 2; var averageAttack = (this.playerAtk + this.enemyAtk) / 2;
for (var x = 0; x < 8; ++x) { for (var x = 0; x < 8; ++x) {
for (var y = 0; y < 8; ++y) { for (var y = 0; y < 8; ++y) {
@ -682,7 +683,7 @@ HackingMission.prototype.createMap = function() {
var node, type = getRandomInt(0, 2); var node, type = getRandomInt(0, 2);
var randMult = addOffset(0.85 + (this.difficulty / 2), 15); var randMult = addOffset(0.85 + (this.difficulty / 2), 15);
switch (type) { switch (type) {
case 0: //Spam case 0: // Spam
var stats = { var stats = {
atk: 0, atk: 0,
def: averageAttack * 1.1 + getRandomInt(15, 45), def: averageAttack * 1.1 + getRandomInt(15, 45),
@ -690,7 +691,7 @@ HackingMission.prototype.createMap = function() {
} }
node = new Node(NodeTypes.Spam, stats); node = new Node(NodeTypes.Spam, stats);
break; break;
case 1: //Transfer case 1: // Transfer
var stats = { var stats = {
atk: 0, atk: 0,
def: averageAttack * 1.1 + getRandomInt(15, 45), def: averageAttack * 1.1 + getRandomInt(15, 45),
@ -698,7 +699,7 @@ HackingMission.prototype.createMap = function() {
} }
node = new Node(NodeTypes.Transfer, stats); node = new Node(NodeTypes.Transfer, stats);
break; break;
case 2: //Shield case 2: // Shield
default: default:
var stats = { var stats = {
atk: 0, atk: 0,
@ -715,14 +716,14 @@ HackingMission.prototype.createMap = function() {
} }
} }
//Create DOM elements in order // Create DOM elements in order
for (var r = 0; r < 8; ++r) { for (var r = 0; r < 8; ++r) {
for (var c = 0; c < 8; ++c) { for (var c = 0; c < 8; ++c) {
this.createNodeDomElement(this.map[r][c]); this.createNodeDomElement(this.map[r][c]);
} }
} }
//Configure all Player CPUS // Configure all Player CPUS
for (var i = 0; i < this.playerCores.length; ++i) { for (var i = 0; i < this.playerCores.length; ++i) {
console.log("Configuring Player Node: " + this.playerCores[i].el.id); console.log("Configuring Player Node: " + this.playerCores[i].el.id);
this.configurePlayerNodeElement(this.playerCores[i].el); this.configurePlayerNodeElement(this.playerCores[i].el);
@ -733,12 +734,12 @@ HackingMission.prototype.createNodeDomElement = function(nodeObj) {
var nodeDiv = document.createElement("a"), txtEl = document.createElement('p'); var nodeDiv = document.createElement("a"), txtEl = document.createElement('p');
nodeObj.el = nodeDiv; nodeObj.el = nodeDiv;
//Set the node element's id based on its coordinates // Set the node element's id based on its coordinates
var id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1]; var id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1];
nodeDiv.setAttribute("id", id); nodeDiv.setAttribute("id", id);
txtEl.setAttribute("id", id + "-txt"); txtEl.setAttribute("id", id + "-txt");
//Set node classes for owner // Set node classes for owner
nodeDiv.classList.add("hack-mission-node"); nodeDiv.classList.add("hack-mission-node");
if (nodeObj.plyrCtrl) { if (nodeObj.plyrCtrl) {
nodeDiv.classList.add("hack-mission-player-node"); nodeDiv.classList.add("hack-mission-player-node");
@ -746,7 +747,7 @@ HackingMission.prototype.createNodeDomElement = function(nodeObj) {
nodeDiv.classList.add("hack-mission-enemy-node"); nodeDiv.classList.add("hack-mission-enemy-node");
} }
//Set node classes based on type // Set node classes based on type
var txt; var txt;
switch (nodeObj.type) { switch (nodeObj.type) {
case NodeTypes.Core: case NodeTypes.Core:
@ -799,7 +800,7 @@ HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
var id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1]; var id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1];
var nodeDiv = document.getElementById(id), txtEl = document.getElementById(id + "-txt"); var nodeDiv = document.getElementById(id), txtEl = document.getElementById(id + "-txt");
//Set node classes based on type // Set node classes based on type
var txt; var txt;
switch (nodeObj.type) { switch (nodeObj.type) {
case NodeTypes.Core: case NodeTypes.Core:
@ -837,9 +838,11 @@ HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
txtEl.innerHTML = txt; txtEl.innerHTML = txt;
} }
//Gets a Node DOM element's corresponding Node object using its /**
//element id. Function accepts either the DOM element object or the ID as * Gets a Node DOM element's corresponding Node object using its
//an argument * element id. Function accepts either the DOM element object or the ID as
* an argument
*/
HackingMission.prototype.getNodeFromElement = function(el) { HackingMission.prototype.getNodeFromElement = function(el) {
var id; var id;
if (isString(el)) { if (isString(el)) {
@ -902,14 +905,16 @@ function clearAllSelectedNodes(hackMissionInst) {
} }
} }
//Configures a DOM element representing a player-owned node to /**
//be selectable and actionable * Configures a DOM element representing a player-owned node to
//Note: Does NOT change its css class. This is handled by Node.setControlledBy... * be selectable and actionable.
* Note: Does NOT change its css class. This is handled by Node.setControlledBy...
*/
HackingMission.prototype.configurePlayerNodeElement = function(el) { HackingMission.prototype.configurePlayerNodeElement = function(el) {
var nodeObj = this.getNodeFromElement(el); var nodeObj = this.getNodeFromElement(el);
if (nodeObj == null) {console.log("Error getting Node object");} if (nodeObj == null) {console.log("Error getting Node object");}
//Add event listener // Add event listener
var self = this; var self = this;
function selectNodeWrapper() { function selectNodeWrapper() {
selectNode(self, el); selectNode(self, el);
@ -927,10 +932,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) {
} }
} }
//Configures a DOM element representing an enemy-node by removing /**
//any event listeners * Configures a DOM element representing an enemy-node by removing
* any event listeners
*/
HackingMission.prototype.configureEnemyNodeElement = function(el) { HackingMission.prototype.configureEnemyNodeElement = function(el) {
//Deselect node if it was the selected node // Deselect node if it was the selected node
var nodeObj = this.getNodeFromElement(el); var nodeObj = this.getNodeFromElement(el);
for (var i = 0; i < this.selectedNode.length; ++i) { for (var i = 0; i < this.selectedNode.length; ++i) {
if (this.selectedNode[i] == nodeObj) { if (this.selectedNode[i] == nodeObj) {
@ -941,8 +948,10 @@ HackingMission.prototype.configureEnemyNodeElement = function(el) {
} }
} }
//Returns bool indicating whether a node is reachable by player /**
//by checking if any of the adjacent nodes are owned by the player * Returns bool indicating whether a node is reachable by player
* by checking if any of the adjacent nodes are owned by the player
*/
HackingMission.prototype.nodeReachable = function(node) { HackingMission.prototype.nodeReachable = function(node) {
var x = node.pos[0], y = node.pos[1]; var x = node.pos[0], y = node.pos[1];
if (x > 0 && this.map[x-1][y].plyrCtrl) {return true;} if (x > 0 && this.map[x-1][y].plyrCtrl) {return true;}
@ -985,7 +994,7 @@ HackingMission.prototype.initJsPlumb = function() {
this.jsplumbinstance = instance; this.jsplumbinstance = instance;
//All player cores are sources // All player cores are sources
for (var i = 0; i < this.playerCores.length; ++i) { for (var i = 0; i < this.playerCores.length; ++i) {
instance.makeSource(this.playerCores[i].el, { instance.makeSource(this.playerCores[i].el, {
deleteEndpointsOnEmpty:true, deleteEndpointsOnEmpty:true,
@ -995,7 +1004,7 @@ HackingMission.prototype.initJsPlumb = function() {
}); });
} }
//Everything else is a target // Everything else is a target
for (var i = 0; i < this.enemyCores.length; ++i) { for (var i = 0; i < this.enemyCores.length; ++i) {
instance.makeTarget(this.enemyCores[i].el, { instance.makeTarget(this.enemyCores[i].el, {
maxConnections:-1, maxConnections:-1,
@ -1025,7 +1034,7 @@ HackingMission.prototype.initJsPlumb = function() {
}); });
} }
//Clicking a connection drops it // Clicking a connection drops it
instance.bind("click", (conn, originalEvent) => { instance.bind("click", (conn, originalEvent) => {
// Cannot drop enemy's connections // Cannot drop enemy's connections
const sourceNode = this.getNodeFromElement(conn.source); const sourceNode = this.getNodeFromElement(conn.source);
@ -1035,15 +1044,15 @@ HackingMission.prototype.initJsPlumb = function() {
endpoints[0].detachFrom(endpoints[1]); endpoints[0].detachFrom(endpoints[1]);
}); });
//Connection events // Connection events
instance.bind("connection", (info) => { instance.bind("connection", (info) => {
var targetNode = this.getNodeFromElement(info.target); var targetNode = this.getNodeFromElement(info.target);
//Do not detach for enemy nodes // Do not detach for enemy nodes
var thisNode = this.getNodeFromElement(info.source); var thisNode = this.getNodeFromElement(info.source);
if (thisNode.enmyCtrl) {return;} if (thisNode.enmyCtrl) {return;}
//If the node is not reachable, drop the connection // If the node is not reachable, drop the connection
if (!this.nodeReachable(targetNode)) { if (!this.nodeReachable(targetNode)) {
info.sourceEndpoint.detachFrom(info.targetEndpoint); info.sourceEndpoint.detachFrom(info.targetEndpoint);
return; return;
@ -1055,7 +1064,7 @@ HackingMission.prototype.initJsPlumb = function() {
++targetNode.targetedCount; ++targetNode.targetedCount;
}); });
//Detach Connection events // Detach Connection events
instance.bind("connectionDetached", (info, originalEvent)=>{ instance.bind("connectionDetached", (info, originalEvent)=>{
var sourceNode = this.getNodeFromElement(info.source); var sourceNode = this.getNodeFromElement(info.source);
sourceNode.conn = null; sourceNode.conn = null;
@ -1065,7 +1074,7 @@ HackingMission.prototype.initJsPlumb = function() {
} }
//Drops all connections where the specified node is the source // Drops all connections where the specified node is the source
HackingMission.prototype.dropAllConnectionsFromNode = function(node) { HackingMission.prototype.dropAllConnectionsFromNode = function(node) {
var allConns = this.jsplumbinstance.getAllConnections(); var allConns = this.jsplumbinstance.getAllConnections();
for (var i = allConns.length-1; i >= 0; --i) { for (var i = allConns.length-1; i >= 0; --i) {
@ -1075,7 +1084,7 @@ HackingMission.prototype.dropAllConnectionsFromNode = function(node) {
} }
} }
//Drops all connections where the specified node is the target // Drops all connections where the specified node is the target
HackingMission.prototype.dropAllConnectionsToNode = function(node) { HackingMission.prototype.dropAllConnectionsToNode = function(node) {
var allConns = this.jsplumbinstance.getAllConnections(); var allConns = this.jsplumbinstance.getAllConnections();
for (var i = allConns.length-1; i >= 0; --i) { for (var i = allConns.length-1; i >= 0; --i) {
@ -1090,10 +1099,10 @@ var storedCycles = 0;
HackingMission.prototype.process = function(numCycles=1) { HackingMission.prototype.process = function(numCycles=1) {
if (!this.started) {return;} if (!this.started) {return;}
storedCycles += numCycles; storedCycles += numCycles;
if (storedCycles < 2) {return;} //Only process every 3 cycles minimum if (storedCycles < 2) {return;} // Only process every 3 cycles minimum
var res = false; var res = false;
//Process actions of all player nodes // Process actions of all player nodes
this.playerCores.forEach((node)=>{ this.playerCores.forEach((node)=>{
res |= this.processNode(node, storedCycles); res |= this.processNode(node, storedCycles);
}); });
@ -1106,7 +1115,7 @@ HackingMission.prototype.process = function(numCycles=1) {
} }
}); });
//Process actions of all enemy nodes // Process actions of all enemy nodes
this.enemyCores.forEach((node)=>{ this.enemyCores.forEach((node)=>{
this.enemyAISelectAction(node); this.enemyAISelectAction(node);
res |= this.processNode(node, storedCycles); res |= this.processNode(node, storedCycles);
@ -1121,7 +1130,7 @@ HackingMission.prototype.process = function(numCycles=1) {
} }
}); });
//The hp of enemy databases increases slowly // The hp of enemy databases increases slowly
this.enemyDatabases.forEach((node)=>{ this.enemyDatabases.forEach((node)=>{
node.maxhp += (0.1 * storedCycles); node.maxhp += (0.1 * storedCycles);
node.hp += (0.1 * storedCycles); node.hp += (0.1 * storedCycles);
@ -1132,19 +1141,19 @@ HackingMission.prototype.process = function(numCycles=1) {
this.calculateDefenses(); this.calculateDefenses();
} }
//Win if all enemy databases are conquered // Win if all enemy databases are conquered
if (this.enemyDatabases.length === 0) { if (this.enemyDatabases.length === 0) {
this.finishMission(true); this.finishMission(true);
return; return;
} }
//Lose if all your cores are gone // Lose if all your cores are gone
if (this.playerCores.length === 0) { if (this.playerCores.length === 0) {
this.finishMission(false); this.finishMission(false);
return; return;
} }
//Defense/hp of misc nodes increases slowly over time // Defense/hp of misc nodes increases slowly over time
this.miscNodes.forEach((node)=>{ this.miscNodes.forEach((node)=>{
node.def += (0.1 * storedCycles); node.def += (0.1 * storedCycles);
node.maxhp += (0.05 * storedCycles); node.maxhp += (0.05 * storedCycles);
@ -1153,7 +1162,7 @@ HackingMission.prototype.process = function(numCycles=1) {
this.updateNodeDomElement(node); this.updateNodeDomElement(node);
}); });
//Update timer and check if player lost // Update timer and check if player lost
this.time -= (storedCycles * Engine._idleSpeed); this.time -= (storedCycles * Engine._idleSpeed);
if (this.time <= 0) { if (this.time <= 0) {
this.finishMission(false); this.finishMission(false);
@ -1164,7 +1173,7 @@ HackingMission.prototype.process = function(numCycles=1) {
storedCycles = 0; storedCycles = 0;
} }
//Returns a bool representing whether defenses need to be re-calculated // Returns a bool representing whether defenses need to be re-calculated
HackingMission.prototype.processNode = function(nodeObj, numCycles=1) { HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
if (nodeObj.action == null) { if (nodeObj.action == null) {
return; return;
@ -1179,21 +1188,21 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
} }
if (targetNode == null) { if (targetNode == null) {
//Player is in the middle of dragging the connection, // Player is in the middle of dragging the connection,
//so the target node is null. Do nothing here // so the target node is null. Do nothing here
} else if (targetNode.plyrCtrl) { } else if (targetNode.plyrCtrl) {
def = this.playerDef; def = this.playerDef;
atk = this.enemyAtk; atk = this.enemyAtk;
} else if (targetNode.enmyCtrl) { } else if (targetNode.enmyCtrl) {
def = this.enemyDef; def = this.enemyDef;
atk = this.playerAtk; atk = this.playerAtk;
} else { //Misc Node } else { // Misc Node
def = targetNode.def; def = targetNode.def;
nodeObj.plyrCtrl ? atk = this.playerAtk : atk = this.enemyAtk; nodeObj.plyrCtrl ? atk = this.playerAtk : atk = this.enemyAtk;
} }
} }
//Calculations are per second, so divide everything by 5 // Calculations are per second, so divide everything by 5
var calcStats = false, plyr = nodeObj.plyrCtrl; var calcStats = false, plyr = nodeObj.plyrCtrl;
var enmyHacking = this.difficulty * CONSTANTS.HackingMissionDifficultyToHacking; var enmyHacking = this.difficulty * CONSTANTS.HackingMissionDifficultyToHacking;
switch(nodeObj.action) { switch(nodeObj.action) {
@ -1234,13 +1243,13 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
break; break;
} }
//Stats can't go below 0 // Stats can't go below 0
if (nodeObj.atk < 0) {nodeObj.atk = 0;} if (nodeObj.atk < 0) {nodeObj.atk = 0;}
if (nodeObj.def < 0) {nodeObj.def = 0;} if (nodeObj.def < 0) {nodeObj.def = 0;}
if (targetNode && targetNode.atk < 0) {targetNode.atk = 0;} if (targetNode && targetNode.atk < 0) {targetNode.atk = 0;}
if (targetNode && targetNode.def < 0) {targetNode.def = 0;} if (targetNode && targetNode.def < 0) {targetNode.def = 0;}
//Conquering a node // Conquering a node
if (targetNode && targetNode.hp <= 0) { if (targetNode && targetNode.hp <= 0) {
var conqueredByPlayer = nodeObj.plyrCtrl; var conqueredByPlayer = nodeObj.plyrCtrl;
targetNode.hp = targetNode.maxhp; targetNode.hp = targetNode.maxhp;
@ -1250,18 +1259,18 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
targetNode.deselect(this.actionButtons); targetNode.deselect(this.actionButtons);
} }
//The conquered node has its stats reduced // The conquered node has its stats reduced
targetNode.atk /= 2; targetNode.atk /= 2;
targetNode.def /= 3.5; targetNode.def /= 3.5;
//Flag for whether the target node was a misc node // Flag for whether the target node was a misc node
var isMiscNode = !targetNode.plyrCtrl && !targetNode.enmyCtrl; var isMiscNode = !targetNode.plyrCtrl && !targetNode.enmyCtrl;
//Remove all connections from Node // Remove all connections from Node
this.dropAllConnectionsToNode(targetNode); this.dropAllConnectionsToNode(targetNode);
this.dropAllConnectionsFromNode(targetNode); this.dropAllConnectionsFromNode(targetNode);
//Changes the css class and turn the node into a JsPlumb Source/Target // Changes the css class and turn the node into a JsPlumb Source/Target
if (conqueredByPlayer) { if (conqueredByPlayer) {
targetNode.setControlledByPlayer(); targetNode.setControlledByPlayer();
this.jsplumbinstance.unmakeTarget(targetNode.el); this.jsplumbinstance.unmakeTarget(targetNode.el);
@ -1273,7 +1282,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
}); });
} else { } else {
targetNode.setControlledByEnemy(); targetNode.setControlledByEnemy();
nodeObj.conn = null; //Clear connection nodeObj.conn = null; // Clear connection
this.jsplumbinstance.unmakeSource(targetNode.el); this.jsplumbinstance.unmakeSource(targetNode.el);
this.jsplumbinstance.makeTarget(targetNode.el, { this.jsplumbinstance.makeTarget(targetNode.el, {
maxConnections:-1, maxConnections:-1,
@ -1284,7 +1293,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
calcStats = true; calcStats = true;
//Helper function to swap nodes between the respective enemyNodes/playerNodes arrays // Helper function to swap nodes between the respective enemyNodes/playerNodes arrays
function swapNodes(orig, dest, targetNode) { function swapNodes(orig, dest, targetNode) {
for (var i = 0; i < orig.length; ++i) { for (var i = 0; i < orig.length; ++i) {
if (orig[i] == targetNode) { if (orig[i] == targetNode) {
@ -1324,7 +1333,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
case NodeTypes.Spam: case NodeTypes.Spam:
if (conqueredByPlayer) { if (conqueredByPlayer) {
swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode); swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
//Conquering spam node increases time limit // Conquering spam node increases time limit
this.time += CONSTANTS.HackingMissionSpamTimeIncrease; this.time += CONSTANTS.HackingMissionSpamTimeIncrease;
} else { } else {
swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode); swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
@ -1332,7 +1341,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
break; break;
case NodeTypes.Transfer: case NodeTypes.Transfer:
//Conquering a Transfer node increases the attack of all cores by some percentages // Conquering a Transfer node increases the attack of all cores by some percentages
if (conqueredByPlayer) { if (conqueredByPlayer) {
swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode); swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
this.playerCores.forEach(function(node) { this.playerCores.forEach(function(node) {
@ -1358,7 +1367,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
break; break;
} }
//If a misc node was conquered, the defense for all misc nodes increases by some fixed amount // If a misc node was conquered, the defense for all misc nodes increases by some fixed amount
if (isMiscNode) { //&& conqueredByPlayer) { if (isMiscNode) { //&& conqueredByPlayer) {
this.miscNodes.forEach((node)=>{ this.miscNodes.forEach((node)=>{
if (node.targetedCount === 0) { if (node.targetedCount === 0) {
@ -1368,23 +1377,25 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
} }
} }
//Update node DOMs // Update node DOMs
this.updateNodeDomElement(nodeObj); this.updateNodeDomElement(nodeObj);
if (targetNode) {this.updateNodeDomElement(targetNode);} if (targetNode) {this.updateNodeDomElement(targetNode);}
return calcStats; return calcStats;
} }
//Enemy "AI" for CPU Core and Transfer Nodes // Enemy "AI" for CPU Core and Transfer Nodes
HackingMission.prototype.enemyAISelectAction = function(nodeObj) { HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
if (nodeObj == null) {return;} if (nodeObj == null) {return;}
switch(nodeObj.type) { switch(nodeObj.type) {
case NodeTypes.Core: case NodeTypes.Core:
//Select a single RANDOM target from miscNodes and player's Nodes /**
//If it is reachable, it will target it. If not, no target will * Select a single RANDOM target from miscNodes and player's Nodes
//be selected for now, and the next time process() gets called this will repeat * If it is reachable, it will target it. If not, no target will
* be selected for now, and the next time process() gets called this will repeat
*/
if (nodeObj.conn == null) { if (nodeObj.conn == null) {
if (this.miscNodes.length === 0) { if (this.miscNodes.length === 0) {
//Randomly pick a player node and attack it if its reachable // Randomly pick a player node and attack it if its reachable
var rand = getRandomInt(0, this.playerNodes.length-1); var rand = getRandomInt(0, this.playerNodes.length-1);
var node; var node;
if (this.playerNodes.length === 0) { if (this.playerNodes.length === 0) {
@ -1393,23 +1404,23 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
node = this.playerNodes[rand]; node = this.playerNodes[rand];
} }
if (this.nodeReachableByEnemy(node)) { if (this.nodeReachableByEnemy(node)) {
//Create connection // Create connection
nodeObj.conn = this.jsplumbinstance.connect({ nodeObj.conn = this.jsplumbinstance.connect({
source:nodeObj.el, source:nodeObj.el,
target:node.el target:node.el
}); });
++node.targetedCount; ++node.targetedCount;
} else { } else {
//Randomly pick a player core and attack it if its reachable // Randomly pick a player core and attack it if its reachable
rand = getRandomInt(0, this.playerCores.length-1); rand = getRandomInt(0, this.playerCores.length-1);
if (this.playerCores.length === 0) { if (this.playerCores.length === 0) {
return; //No Misc Nodes, no player Nodes, no Player cores. Player lost return; // No Misc Nodes, no player Nodes, no Player cores. Player lost
} else { } else {
node = this.playerCores[rand]; node = this.playerCores[rand];
} }
if (this.nodeReachableByEnemy(node)) { if (this.nodeReachableByEnemy(node)) {
//Create connection // Create connection
nodeObj.conn = this.jsplumbinstance.connect({ nodeObj.conn = this.jsplumbinstance.connect({
source:nodeObj.el, source:nodeObj.el,
target:node.el target:node.el
@ -1418,7 +1429,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
} }
} }
} else { } else {
//Randomly pick a misc node and attack it if its reachable // Randomly pick a misc node and attack it if its reachable
var rand = getRandomInt(0, this.miscNodes.length-1); var rand = getRandomInt(0, this.miscNodes.length-1);
var node = this.miscNodes[rand]; var node = this.miscNodes[rand];
if (this.nodeReachableByEnemy(node)) { if (this.nodeReachableByEnemy(node)) {
@ -1430,10 +1441,10 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
} }
} }
//If no connection was made, set the Core to Fortify // If no connection was made, set the Core to Fortify
nodeObj.action = NodeActions.Fortify; nodeObj.action = NodeActions.Fortify;
} else { } else {
//If this node has a selected target // If this node has a selected target
var targetNode; var targetNode;
if (nodeObj.conn.target) { if (nodeObj.conn.target) {
targetNode = this.getNodeFromElement(nodeObj.conn.target); targetNode = this.getNodeFromElement(nodeObj.conn.target);
@ -1458,7 +1469,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
} }
break; break;
case NodeTypes.Transfer: case NodeTypes.Transfer:
//Switch between fortifying and overflowing as necessary // Switch between fortifying and overflowing as necessary
if (nodeObj.def < 125) { if (nodeObj.def < 125) {
nodeObj.action = NodeActions.Fortify; nodeObj.action = NodeActions.Fortify;
} else { } else {
@ -1474,11 +1485,11 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
} }
} }
var hackEffWeightSelf = 130; //Weight for Node actions on self var hackEffWeightSelf = 130; // Weight for Node actions on self
var hackEffWeightTarget = 25; //Weight for Node Actions against Target var hackEffWeightTarget = 25; // Weight for Node Actions against Target
var hackEffWeightAttack = 80; //Weight for Attack action var hackEffWeightAttack = 80; // Weight for Attack action
//Returns damage per cycle based on stats // Returns damage per cycle based on stats
HackingMission.prototype.calculateAttackDamage = function(atk, def, hacking = 0) { HackingMission.prototype.calculateAttackDamage = function(atk, def, hacking = 0) {
return Math.max(0.55 * (atk + (hacking / hackEffWeightAttack) - def), 1); return Math.max(0.55 * (atk + (hacking / hackEffWeightAttack) - def), 1);
} }
@ -1499,11 +1510,11 @@ HackingMission.prototype.calculateOverflowEffect = function(hacking=0) {
return 0.95 * hacking / hackEffWeightSelf; return 0.95 * hacking / hackEffWeightSelf;
} }
//Updates timer display // Updates timer display
HackingMission.prototype.updateTimer = function() { HackingMission.prototype.updateTimer = function() {
var timer = document.getElementById("hacking-mission-timer"); var timer = document.getElementById("hacking-mission-timer");
//Convert time remaining to a string of the form mm:ss // Convert time remaining to a string of the form mm:ss
var seconds = Math.round(this.time / 1000); var seconds = Math.round(this.time / 1000);
var minutes = Math.trunc(seconds / 60); var minutes = Math.trunc(seconds / 60);
seconds %= 60; seconds %= 60;
@ -1511,7 +1522,7 @@ HackingMission.prototype.updateTimer = function() {
timer.innerText = "Time left: " + str; timer.innerText = "Time left: " + str;
} }
//The 'win' argument is a bool for whether or not the player won // The 'win' argument is a bool for whether or not the player won
HackingMission.prototype.finishMission = function(win) { HackingMission.prototype.finishMission = function(win) {
inMission = false; inMission = false;
currMission = null; currMission = null;
@ -1530,13 +1541,13 @@ HackingMission.prototype.finishMission = function(win) {
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation."); dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
} }
//Clear mission container // Clear mission container
var container = document.getElementById("mission-container"); var container = document.getElementById("mission-container");
while(container.firstChild) { while(container.firstChild) {
container.removeChild(container.firstChild); container.removeChild(container.firstChild);
} }
//Return to Faction page // Return to Faction page
document.getElementById("mainmenu-container").style.visibility = "visible"; document.getElementById("mainmenu-container").style.visibility = "visible";
document.getElementById("character-overview-wrapper").style.visibility = "visible"; document.getElementById("character-overview-wrapper").style.visibility = "visible";
Engine.loadFactionContent(); Engine.loadFactionContent();

@ -134,13 +134,13 @@ import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup"; import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElementById } from "../utils/uiHelpers/removeElementById"; import { removeElementById } from "../utils/uiHelpers/removeElementById";
let hasCorporationSF = false; //Source-File 3 let hasCorporationSF = false; // Source-File 3
let hasSingularitySF = false; //Source-File 4 let hasSingularitySF = false; // Source-File 4
let hasAISF = false; //Source-File 5 let hasAISF = false; // Source-File 5
let hasBladeburnerSF = false; //Source-File 6 let hasBladeburnerSF = false; // Source-File 6
let hasBladeburner2079SF = false; //Source-File 7 let hasBladeburner2079SF = false; // Source-File 7
let hasWallStreetSF = false; //Source-File 8 let hasWallStreetSF = false; // Source-File 8
let hasBn11SF = false; //Source-File 11 let hasBn11SF = false; // Source-File 11
let singularitySFLvl = 1; let singularitySFLvl = 1;
let wallStreetSFLvl = 1; let wallStreetSFLvl = 1;
@ -216,7 +216,7 @@ var possibleLogs = {
setTerritoryWarfare: true, setTerritoryWarfare: true,
} }
//Used to check and set flags for every Source File, despite the name of the function // Used to check and set flags for every Source File, despite the name of the function
function initSingularitySFFlags() { function initSingularitySFFlags() {
for (var i = 0; i < Player.sourceFiles.length; ++i) { for (var i = 0; i < Player.sourceFiles.length; ++i) {
if (Player.sourceFiles[i].n === 3) {hasCorporationSF = true;} if (Player.sourceFiles[i].n === 3) {hasCorporationSF = true;}
@ -455,10 +455,10 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "hack() error. Invalid IP or hostname passed in: " + ip + ". Stopping..."); throw makeRuntimeRejectMsg(workerScript, "hack() error. Invalid IP or hostname passed in: " + ip + ". Stopping...");
} }
//Calculate the hacking time // Calculate the hacking time
var hackingTime = calculateHackingTime(server); //This is in seconds var hackingTime = calculateHackingTime(server); // This is in seconds
//No root access or skill level too low // No root access or skill level too low
const canHack = netscriptCanHack(server, Player); const canHack = netscriptCanHack(server, Player);
if (!canHack.res) { if (!canHack.res) {
workerScript.scriptRef.log(`ERROR: ${canHack.msg}`); workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
@ -475,18 +475,17 @@ function NetscriptFunctions(workerScript) {
var rand = Math.random(); var rand = Math.random();
var expGainedOnSuccess = calculateHackingExpGain(server) * threads; var expGainedOnSuccess = calculateHackingExpGain(server) * threads;
var expGainedOnFailure = (expGainedOnSuccess / 4); var expGainedOnFailure = (expGainedOnSuccess / 4);
if (rand < hackChance) { //Success! if (rand < hackChance) { // Success!
const percentHacked = calculatePercentMoneyHacked(server); const percentHacked = calculatePercentMoneyHacked(server);
let maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax)); let maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax));
if (isNaN(maxThreadNeeded)) { if (isNaN(maxThreadNeeded)) {
//Server has a 'max money' of 0 (probably). // Server has a 'max money' of 0 (probably). We'll set this to an arbitrarily large value
//We'll set this to an arbitrarily large value
maxThreadNeeded = 1e6; maxThreadNeeded = 1e6;
} }
let moneyGained = Math.floor(server.moneyAvailable * percentHacked) * threads; let moneyGained = Math.floor(server.moneyAvailable * percentHacked) * threads;
//Over-the-top safety checks // Over-the-top safety checks
if (moneyGained <= 0) { if (moneyGained <= 0) {
moneyGained = 0; moneyGained = 0;
expGainedOnSuccess = expGainedOnFailure; expGainedOnSuccess = expGainedOnFailure;
@ -508,7 +507,7 @@ function NetscriptFunctions(workerScript) {
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded)); server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
return Promise.resolve(moneyGained); return Promise.resolve(moneyGained);
} else { } else {
//Player only gains 25% exp for failure? // Player only gains 25% exp for failure?
Player.gainHackingExp(expGainedOnFailure); Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += expGainedOnFailure; workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.hack == null) { if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.hack == null) {
@ -586,7 +585,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "Cannot grow(). Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "Cannot grow(). Invalid IP or hostname passed in: " + ip);
} }
//No root access or skill level too low // No root access or skill level too low
const canHack = netscriptCanGrow(server); const canHack = netscriptCanGrow(server);
if (!canHack.res) { if (!canHack.res) {
workerScript.scriptRef.log(`ERROR: ${canHack.msg}`); workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
@ -600,7 +599,7 @@ function NetscriptFunctions(workerScript) {
return netscriptDelay(growTime * 1000, workerScript).then(function() { return netscriptDelay(growTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);} if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable; const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable;
server.moneyAvailable += (1 * threads); //It can be grown even if it has no money server.moneyAvailable += (1 * threads); // It can be grown even if it has no money
var growthPercentage = processSingleServerGrowth(server, 450 * threads, Player); var growthPercentage = processSingleServerGrowth(server, 450 * threads, Player);
const moneyAfter = server.moneyAvailable; const moneyAfter = server.moneyAvailable;
workerScript.scriptRef.recordGrow(server.ip, threads); workerScript.scriptRef.recordGrow(server.ip, threads);
@ -648,7 +647,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "Cannot weaken(). Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "Cannot weaken(). Invalid IP or hostname passed in: " + ip);
} }
//No root access or skill level too low // No root access or skill level too low
const canHack = netscriptCanWeaken(server); const canHack = netscriptCanWeaken(server);
if (!canHack.res) { if (!canHack.res) {
workerScript.scriptRef.log(`ERROR: ${canHack.msg}`); workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
@ -1075,7 +1074,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments"); throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
} }
if (scriptname && scriptname.constructor === Array) { if (scriptname && scriptname.constructor === Array) {
//Recursively call scp on all elements of array // Recursively call scp on all elements of array
var res = false; var res = false;
scriptname.forEach(function(script) { scriptname.forEach(function(script) {
if (NetscriptFunctions(workerScript).scp(script, ip1, ip2)) { if (NetscriptFunctions(workerScript).scp(script, ip1, ip2)) {
@ -1121,7 +1120,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments"); throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
} }
//Scp for lit files // Scp for lit files
if (scriptname.endsWith(".lit")) { if (scriptname.endsWith(".lit")) {
var found = false; var found = false;
for (var i = 0; i < currServ.messages.length; ++i) { for (var i = 0; i < currServ.messages.length; ++i) {
@ -1141,7 +1140,7 @@ function NetscriptFunctions(workerScript) {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) { if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) {
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname); workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
} }
return true; //Already exists return true; // Already exists
} }
} }
destServer.messages.push(scriptname); destServer.messages.push(scriptname);
@ -1151,7 +1150,7 @@ function NetscriptFunctions(workerScript) {
return true; return true;
} }
//Scp for text files // Scp for text files
if (scriptname.endsWith(".txt")) { if (scriptname.endsWith(".txt")) {
var found = false, txtFile; var found = false, txtFile;
for (var i = 0; i < currServ.textFiles.length; ++i) { for (var i = 0; i < currServ.textFiles.length; ++i) {
@ -1169,7 +1168,7 @@ function NetscriptFunctions(workerScript) {
for (var i = 0; i < destServer.textFiles.length; ++i) { for (var i = 0; i < destServer.textFiles.length; ++i) {
if (destServer.textFiles[i].fn === scriptname) { if (destServer.textFiles[i].fn === scriptname) {
//Overwrite // Overwrite
destServer.textFiles[i].text = txtFile.text; destServer.textFiles[i].text = txtFile.text;
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) { if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) {
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname); workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
@ -1185,7 +1184,7 @@ function NetscriptFunctions(workerScript) {
return true; return true;
} }
//Scp for script files // Scp for script files
var sourceScript = null; var sourceScript = null;
for (var i = 0; i < currServ.scripts.length; ++i) { for (var i = 0; i < currServ.scripts.length; ++i) {
if (scriptname == currServ.scripts[i].filename) { if (scriptname == currServ.scripts[i].filename) {
@ -1198,7 +1197,7 @@ function NetscriptFunctions(workerScript) {
return false; return false;
} }
//Overwrite script if it already exists // Overwrite script if it already exists
for (var i = 0; i < destServer.scripts.length; ++i) { for (var i = 0; i < destServer.scripts.length; ++i) {
if (scriptname == destServer.scripts[i].filename) { if (scriptname == destServer.scripts[i].filename) {
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) { if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) {
@ -1213,7 +1212,7 @@ function NetscriptFunctions(workerScript) {
} }
} }
//Create new script if it does not already exist // Create new script if it does not already exist
var newScript = new Script(); var newScript = new Script();
newScript.filename = scriptname; newScript.filename = scriptname;
newScript.code = sourceScript.code; newScript.code = sourceScript.code;
@ -1239,7 +1238,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ls() failed. Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "ls() failed. Invalid IP or hostname passed in: " + ip);
} }
//Get the grep filter, if one exists // Get the grep filter, if one exists
var filter = false; var filter = false;
if (arguments.length >= 2) { if (arguments.length >= 2) {
filter = grep.toString(); filter = grep.toString();
@ -1303,7 +1302,7 @@ function NetscriptFunctions(workerScript) {
} }
} }
//Sort the files alphabetically then print each // Sort the files alphabetically then print each
allFiles.sort(); allFiles.sort();
return allFiles; return allFiles;
}, },
@ -1708,7 +1707,7 @@ function NetscriptFunctions(workerScript) {
var gains = stock.price * shares - CONSTANTS.StockMarketCommission; var gains = stock.price * shares - CONSTANTS.StockMarketCommission;
Player.gainMoney(gains); Player.gainMoney(gains);
//Calculate net profit and add to script stats // Calculate net profit and add to script stats
var netProfit = ((stock.price - stock.playerAvgPx) * shares) - CONSTANTS.StockMarketCommission; var netProfit = ((stock.price - stock.playerAvgPx) * shares) - CONSTANTS.StockMarketCommission;
if (isNaN(netProfit)) {netProfit = 0;} if (isNaN(netProfit)) {netProfit = 0;}
workerScript.scriptRef.onlineMoneyMade += netProfit; workerScript.scriptRef.onlineMoneyMade += netProfit;
@ -1908,7 +1907,7 @@ function NetscriptFunctions(workerScript) {
if (stock == null) { if (stock == null) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Invalid stock symbol passed into getStockVolatility()"); throw makeRuntimeRejectMsg(workerScript, "ERROR: Invalid stock symbol passed into getStockVolatility()");
} }
return stock.mv / 100; //Convert from percentage to decimal return stock.mv / 100; // Convert from percentage to decimal
}, },
getStockForecast : function(symbol) { getStockForecast : function(symbol) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
@ -1924,7 +1923,7 @@ function NetscriptFunctions(workerScript) {
} }
var forecast = 50; var forecast = 50;
stock.b ? forecast += stock.otlkMag : forecast -= stock.otlkMag; stock.b ? forecast += stock.otlkMag : forecast -= stock.otlkMag;
return forecast / 100; //Convert from percentage to decimal return forecast / 100; // Convert from percentage to decimal
}, },
purchase4SMarketData : function() { purchase4SMarketData : function() {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
@ -2087,25 +2086,25 @@ function NetscriptFunctions(workerScript) {
var ip = server.ip; var ip = server.ip;
//Can't delete server you're currently connected to // Can't delete server you're currently connected to
if (server.isConnectedTo) { if (server.isConnectedTo) {
workerScript.scriptRef.log("ERROR: deleteServer() failed because you are currently connected to the server you are trying to delete"); workerScript.scriptRef.log("ERROR: deleteServer() failed because you are currently connected to the server you are trying to delete");
return false; return false;
} }
//A server cannot delete itself // A server cannot delete itself
if (ip === workerScript.serverIp) { if (ip === workerScript.serverIp) {
workerScript.scriptRef.log("ERROR: Cannot call deleteServer() on self. deleteServer() failed"); workerScript.scriptRef.log("ERROR: Cannot call deleteServer() on self. deleteServer() failed");
return false; return false;
} }
//Delete all scripts running on server // Delete all scripts running on server
if (server.runningScripts.length > 0) { if (server.runningScripts.length > 0) {
workerScript.scriptRef.log("ERROR: Cannot delete server " + server.hostname + " because it still has scripts running."); workerScript.scriptRef.log("ERROR: Cannot delete server " + server.hostname + " because it still has scripts running.");
return false; return false;
} }
//Delete from player's purchasedServers array // Delete from player's purchasedServers array
var found = false; var found = false;
for (var i = 0; i < Player.purchasedServers.length; ++i) { for (var i = 0; i < Player.purchasedServers.length; ++i) {
if (ip == Player.purchasedServers[i]) { if (ip == Player.purchasedServers[i]) {
@ -2121,10 +2120,10 @@ function NetscriptFunctions(workerScript) {
return false; return false;
} }
//Delete from all servers // Delete from all servers
delete AllServers[ip]; delete AllServers[ip];
//Delete from home computer // Delete from home computer
found = false; found = false;
var homeComputer = Player.getHomeComputer(); var homeComputer = Player.getHomeComputer();
for (var i = 0; i < homeComputer.serversOnNetwork.length; ++i) { for (var i = 0; i < homeComputer.serversOnNetwork.length; ++i) {
@ -2136,7 +2135,7 @@ function NetscriptFunctions(workerScript) {
return true; return true;
} }
} }
//Wasn't found on home computer // Wasn't found on home computer
workerScript.scriptRef.log("ERROR: Could not find server " + server.hostname + workerScript.scriptRef.log("ERROR: Could not find server " + server.hostname +
"as a purchased server. This is likely a bug please contact game dev"); "as a purchased server. This is likely a bug please contact game dev");
return false; return false;
@ -2165,8 +2164,8 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("write", CONSTANTS.ScriptReadWriteRamCost); return updateStaticRam("write", CONSTANTS.ScriptReadWriteRamCost);
} }
updateDynamicRam("write", CONSTANTS.ScriptReadWriteRamCost); updateDynamicRam("write", CONSTANTS.ScriptReadWriteRamCost);
if (!isNaN(port)) { //Write to port if (!isNaN(port)) { // Write to port
//Port 1-10 // Port 1-10
port = Math.round(port); port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) { if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to write to invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid."); throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to write to invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid.");
@ -2176,17 +2175,17 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer"); throw makeRuntimeRejectMsg(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer");
} }
return port.write(data); return port.write(data);
} else if (isString(port)) { //Write to script or text file } else if (isString(port)) { // Write to script or text file
var fn = port; var fn = port;
var server = workerScript.getServer(); var server = workerScript.getServer();
if (server == null) { if (server == null) {
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in write(). This is a bug please contact game dev"); throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in write(). This is a bug please contact game dev");
} }
if (isScriptFilename(fn)) { if (isScriptFilename(fn)) {
//Write to script // Write to script
let script = workerScript.getScriptOnServer(fn); let script = workerScript.getScriptOnServer(fn);
if (script == null) { if (script == null) {
//Create a new script // Create a new script
script = new Script(fn, data, server.ip); script = new Script(fn, data, server.ip);
server.scripts.push(script); server.scripts.push(script);
return true; return true;
@ -2194,7 +2193,7 @@ function NetscriptFunctions(workerScript) {
mode === "w" ? script.code = data : script.code += data; mode === "w" ? script.code = data : script.code += data;
script.updateRamUsage(); script.updateRamUsage();
} else { } else {
//Write to text file // Write to text file
let txtFile = getTextFile(fn, server); let txtFile = getTextFile(fn, server);
if (txtFile == null) { if (txtFile == null) {
txtFile = createTextFile(fn, data, server); txtFile = createTextFile(fn, data, server);
@ -2235,8 +2234,8 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("read", CONSTANTS.ScriptReadWriteRamCost); return updateStaticRam("read", CONSTANTS.ScriptReadWriteRamCost);
} }
updateDynamicRam("read", CONSTANTS.ScriptReadWriteRamCost); updateDynamicRam("read", CONSTANTS.ScriptReadWriteRamCost);
if (!isNaN(port)) { //Read from port if (!isNaN(port)) { // Read from port
//Port 1-10 // Port 1-10
port = Math.round(port); port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) { if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to read from invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid."); throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to read from invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid.");
@ -2246,21 +2245,21 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Could not find port: " + port + ". This is a bug contact the game developer"); throw makeRuntimeRejectMsg(workerScript, "ERROR: Could not find port: " + port + ". This is a bug contact the game developer");
} }
return port.read(); return port.read();
} else if (isString(port)) { //Read from script or text file } else if (isString(port)) { // Read from script or text file
let fn = port; let fn = port;
let server = getServer(workerScript.serverIp); let server = getServer(workerScript.serverIp);
if (server == null) { if (server == null) {
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in read(). This is a bug please contact game dev"); throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in read(). This is a bug please contact game dev");
} }
if (isScriptFilename(fn)) { if (isScriptFilename(fn)) {
//Read from script // Read from script
let script = workerScript.getScriptOnServer(fn); let script = workerScript.getScriptOnServer(fn);
if (script == null) { if (script == null) {
return ""; return "";
} }
return script.code; return script.code;
} else { } else {
//Read from text file // Read from text file
let txtFile = getTextFile(fn, server); let txtFile = getTextFile(fn, server);
if (txtFile !== null) { if (txtFile !== null) {
return txtFile.text; return txtFile.text;
@ -2295,7 +2294,7 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("clear", CONSTANTS.ScriptReadWriteRamCost); return updateStaticRam("clear", CONSTANTS.ScriptReadWriteRamCost);
} }
updateDynamicRam("clear", CONSTANTS.ScriptReadWriteRamCost); updateDynamicRam("clear", CONSTANTS.ScriptReadWriteRamCost);
if (!isNaN(port)) { //Clear port if (!isNaN(port)) { // Clear port
port = Math.round(port); port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) { if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to clear invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid"); throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to clear invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid");
@ -2305,7 +2304,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Could not find port: " + port + ". This is a bug contact the game developer"); throw makeRuntimeRejectMsg(workerScript, "ERROR: Could not find port: " + port + ". This is a bug contact the game developer");
} }
return port.clear(); return port.clear();
} else if (isString(port)) { //Clear text file } else if (isString(port)) { // Clear text file
var fn = port; var fn = port;
var server = getServer(workerScript.serverIp); var server = getServer(workerScript.serverIp);
if (server == null) { if (server == null) {
@ -2423,7 +2422,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("getHackTime() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("getHackTime() failed. Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getHackTime() failed. Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "getHackTime() failed. Invalid IP or hostname passed in: " + ip);
} }
return calculateHackingTime(server, hack, int); //Returns seconds return calculateHackingTime(server, hack, int); // Returns seconds
}, },
getGrowTime : function(ip, hack, int) { getGrowTime : function(ip, hack, int) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
@ -2435,7 +2434,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("getGrowTime() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("getGrowTime() failed. Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getGrowTime() failed. Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "getGrowTime() failed. Invalid IP or hostname passed in: " + ip);
} }
return calculateGrowTime(server, hack, int); //Returns seconds return calculateGrowTime(server, hack, int); // Returns seconds
}, },
getWeakenTime : function(ip, hack, int) { getWeakenTime : function(ip, hack, int) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
@ -2447,7 +2446,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("getWeakenTime() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("getWeakenTime() failed. Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getWeakenTime() failed. Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "getWeakenTime() failed. Invalid IP or hostname passed in: " + ip);
} }
return calculateWeakenTime(server, hack, int); //Returns seconds return calculateWeakenTime(server, hack, int); // Returns seconds
}, },
getScriptIncome : function(scriptname, ip) { getScriptIncome : function(scriptname, ip) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
@ -2455,13 +2454,13 @@ function NetscriptFunctions(workerScript) {
} }
updateDynamicRam("getScriptIncome", CONSTANTS.ScriptGetScriptRamCost); updateDynamicRam("getScriptIncome", CONSTANTS.ScriptGetScriptRamCost);
if (arguments.length === 0) { if (arguments.length === 0) {
//Get total script income // Get total script income
var res = []; var res = [];
res.push(updateActiveScriptsItems()); res.push(updateActiveScriptsItems());
res.push(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000)); res.push(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
return res; return res;
} else { } else {
//Get income for a particular script // Get income for a particular script
var server = getServer(ip); var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.scriptRef.log("getScriptIncome() failed. Invalid IP or hostnamed passed in: " + ip); workerScript.scriptRef.log("getScriptIncome() failed. Invalid IP or hostnamed passed in: " + ip);
@ -2491,7 +2490,7 @@ function NetscriptFunctions(workerScript) {
} }
return total; return total;
} else { } else {
//Get income for a particular script // Get income for a particular script
var server = getServer(ip); var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.scriptRef.log("getScriptExpGain() failed. Invalid IP or hostnamed passed in: " + ip); workerScript.scriptRef.log("getScriptExpGain() failed. Invalid IP or hostnamed passed in: " + ip);
@ -3206,7 +3205,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: Invalid job passed into applyToCompany: " + field + ". applyToCompany() failed"); workerScript.scriptRef.log("ERROR: Invalid job passed into applyToCompany: " + field + ". applyToCompany() failed");
return false; return false;
} }
//The Player object's applyForJob function can return string with special error messages // The Player object's applyForJob function can return string with special error messages
if (isString(res)) { if (isString(res)) {
workerScript.scriptRef.log(res); workerScript.scriptRef.log(res);
return false; return false;
@ -3298,7 +3297,7 @@ function NetscriptFunctions(workerScript) {
return false; return false;
} }
} }
//Make a copy of Player.factionInvitations // Make a copy of Player.factionInvitations
return Player.factionInvitations.slice(); return Player.factionInvitations.slice();
}, },
joinFaction : function(name) { joinFaction : function(name) {
@ -3327,7 +3326,7 @@ function NetscriptFunctions(workerScript) {
var fac = Factions[name]; var fac = Factions[name];
joinFaction(fac); joinFaction(fac);
//Update Faction Invitation list to account for joined + banned factions // Update Faction Invitation list to account for joined + banned factions
for (var i = 0; i < Player.factionInvitations.length; ++i) { for (var i = 0; i < Player.factionInvitations.length; ++i) {
if (Player.factionInvitations[i] == name || Factions[Player.factionInvitations[i]].isBanned) { if (Player.factionInvitations[i] == name || Factions[Player.factionInvitations[i]].isBanned) {
Player.factionInvitations.splice(i, 1); Player.factionInvitations.splice(i, 1);
@ -3383,7 +3382,7 @@ function NetscriptFunctions(workerScript) {
} }
var fac = Factions[name]; var fac = Factions[name];
//Arrays listing factions that allow each time of work // Arrays listing factions that allow each time of work
var hackAvailable = ["Illuminati", "Daedalus", "The Covenant", "ECorp", "MegaCorp", var hackAvailable = ["Illuminati", "Daedalus", "The Covenant", "ECorp", "MegaCorp",
"Bachman & Associates", "Blade Industries", "NWO", "Clarke Incorporated", "Bachman & Associates", "Blade Industries", "NWO", "Clarke Incorporated",
"OmniTek Incorporated", "Four Sigma", "KuaiGong International", "OmniTek Incorporated", "Four Sigma", "KuaiGong International",
@ -4695,7 +4694,7 @@ function NetscriptFunctions(workerScript) {
updateDynamicRam("joinBladeburnerDivision", CONSTANTS.ScriptBladeburnerApiBaseRamCost); updateDynamicRam("joinBladeburnerDivision", CONSTANTS.ScriptBladeburnerApiBaseRamCost);
if ((Player.bitNodeN === 7 || hasBladeburner2079SF)) { if ((Player.bitNodeN === 7 || hasBladeburner2079SF)) {
if (Player.bladeburner instanceof Bladeburner) { if (Player.bladeburner instanceof Bladeburner) {
return true; //Already member return true; // Already member
} else if (Player.strength >= 100 && Player.defense >= 100 && } else if (Player.strength >= 100 && Player.defense >= 100 &&
Player.dexterity >= 100 && Player.agility >= 100) { Player.dexterity >= 100 && Player.agility >= 100) {
Player.bladeburner = new Bladeburner({new:true}); Player.bladeburner = new Bladeburner({new:true});
@ -5158,8 +5157,8 @@ function NetscriptFunctions(workerScript) {
return Player.sleeves[sleeveNumber].tryBuyAugmentation(Player, aug); return Player.sleeves[sleeveNumber].tryBuyAugmentation(Player, aug);
} }
} // End sleeve } // End sleeve
} //End return } // End return
} //End NetscriptFunction() } // End NetscriptFunction()
export {NetscriptFunctions, initSingularitySFFlags, hasSingularitySF, hasBn11SF, export {NetscriptFunctions, initSingularitySFFlags, hasSingularitySF, hasBn11SF,
hasWallStreetSF, wallStreetSFLvl, hasCorporationSF, hasAISF, hasBladeburnerSF}; hasWallStreetSF, wallStreetSFLvl, hasCorporationSF, hasAISF, hasBladeburnerSF};

@ -10,7 +10,7 @@ export let Player = new PlayerObject();
export function loadPlayer(saveString) { export function loadPlayer(saveString) {
Player = JSON.parse(saveString, Reviver); Player = JSON.parse(saveString, Reviver);
//Parse Decimal.js objects // Parse Decimal.js objects
Player.money = new Decimal(Player.money); Player.money = new Decimal(Player.money);
if (Player.corporation instanceof Corporation) { if (Player.corporation instanceof Corporation) {

@ -64,7 +64,7 @@ import Decimal from "decimal.js";
const BitNode8StartingMoney = 250e6; const BitNode8StartingMoney = 250e6;
//Prestige by purchasing augmentation // Prestige by purchasing augmentation
function prestigeAugmentation() { function prestigeAugmentation() {
// Set Navigation to Terminal screen, for any logic that depends on it // Set Navigation to Terminal screen, for any logic that depends on it
routing.navigateTo(Page.Terminal); routing.navigateTo(Page.Terminal);
@ -81,17 +81,17 @@ function prestigeAugmentation() {
$("#terminal tr:not(:last)").remove(); $("#terminal tr:not(:last)").remove();
postNetburnerText(); postNetburnerText();
//Delete all Worker Scripts objects // Delete all Worker Scripts objects
prestigeWorkerScripts(); prestigeWorkerScripts();
var homeComp = Player.getHomeComputer(); var homeComp = Player.getHomeComputer();
//Delete all servers except home computer // Delete all servers except home computer
prestigeAllServers(); prestigeAllServers();
//Delete Special Server IPs // Delete Special Server IPs
prestigeSpecialServerIps(); //Must be done before initForeignServers() prestigeSpecialServerIps(); // Must be done before initForeignServers()
//Reset home computer (only the programs) and add to AllServers // Reset home computer (only the programs) and add to AllServers
AddToAllServers(homeComp); AddToAllServers(homeComp);
prestigeHomeComputer(homeComp); prestigeHomeComputer(homeComp);
@ -106,39 +106,39 @@ function prestigeAugmentation() {
homeComp.programs.push(Programs.BruteSSHProgram.name); homeComp.programs.push(Programs.BruteSSHProgram.name);
} }
//Re-create foreign servers // Re-create foreign servers
initForeignServers(Player.getHomeComputer()); initForeignServers(Player.getHomeComputer());
//Gain favor for Companies // Gain favor for Companies
for (var member in Companies) { for (var member in Companies) {
if (Companies.hasOwnProperty(member)) { if (Companies.hasOwnProperty(member)) {
Companies[member].gainFavor(); Companies[member].gainFavor();
} }
} }
//Gain favor for factions // Gain favor for factions
for (var member in Factions) { for (var member in Factions) {
if (Factions.hasOwnProperty(member)) { if (Factions.hasOwnProperty(member)) {
Factions[member].gainFavor(); Factions[member].gainFavor();
} }
} }
//Stop a Terminal action if there is onerror // Stop a Terminal action if there is onerror
if (Engine._actionInProgress) { if (Engine._actionInProgress) {
Engine._actionInProgress = false; Engine._actionInProgress = false;
Terminal.finishAction(true); Terminal.finishAction(true);
} }
//Re-initialize things - This will update any changes // Re-initialize things - This will update any changes
initFactions(); //Factions must be initialized before augmentations initFactions(); // Factions must be initialized before augmentations
initAugmentations(); //Calls reapplyAllAugmentations() and resets Player multipliers initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
initCompanies(); initCompanies();
//Messages // Messages
initMessages(); initMessages();
//Gang, in BitNode 2 // Gang, in BitNode 2
if (Player.bitNodeN == 2 && Player.inGang()) { if (Player.bitNodeN == 2 && Player.inGang()) {
var faction = Factions[Player.gang.facName]; var faction = Factions[Player.gang.facName];
if (faction instanceof Faction) { if (faction instanceof Faction) {
@ -146,19 +146,19 @@ function prestigeAugmentation() {
} }
} }
//Cancel Bladeburner action // Cancel Bladeburner action
if (Player.bladeburner instanceof Bladeburner) { if (Player.bladeburner instanceof Bladeburner) {
Player.bladeburner.prestige(); Player.bladeburner.prestige();
} }
//BitNode 8: Ghost of Wall Street // BitNode 8: Ghost of Wall Street
if (Player.bitNodeN === 8) {Player.money = new Decimal(BitNode8StartingMoney);} if (Player.bitNodeN === 8) {Player.money = new Decimal(BitNode8StartingMoney);}
if (Player.bitNodeN === 8 || hasWallStreetSF) { if (Player.bitNodeN === 8 || hasWallStreetSF) {
Player.hasWseAccount = true; Player.hasWseAccount = true;
Player.hasTixApiAccess = true; Player.hasTixApiAccess = true;
} }
//Reset Stock market // Reset Stock market
if (Player.hasWseAccount) { if (Player.hasWseAccount) {
initStockMarket(); initStockMarket();
initSymbolToStockMap(); initSymbolToStockMap();
@ -169,13 +169,13 @@ function prestigeAugmentation() {
stockMarketList.removeChild(stockMarketList.firstChild); stockMarketList.removeChild(stockMarketList.firstChild);
} }
var watchlist = document.getElementById("stock-market-watchlist-filter"); var watchlist = document.getElementById("stock-market-watchlist-filter");
watchlist.value = ""; //Reset watchlist filter watchlist.value = ""; // Reset watchlist filter
// Refresh Main Menu (the 'World' menu, specifically) // Refresh Main Menu (the 'World' menu, specifically)
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
//Red Pill // Red Pill
if (augmentationExists(AugmentationNames.TheRedPill) && if (augmentationExists(AugmentationNames.TheRedPill) &&
Augmentations[AugmentationNames.TheRedPill].owned) { Augmentations[AugmentationNames.TheRedPill].owned) {
var WorldDaemon = AllServers[SpecialServerIps[SpecialServerNames.WorldDaemon]]; var WorldDaemon = AllServers[SpecialServerIps[SpecialServerNames.WorldDaemon]];
@ -188,27 +188,27 @@ function prestigeAugmentation() {
} }
//Prestige by destroying Bit Node and gaining a Source File // Prestige by destroying Bit Node and gaining a Source File
function prestigeSourceFile() { function prestigeSourceFile() {
initBitNodeMultipliers(Player); initBitNodeMultipliers(Player);
updateSourceFileFlags(Player); updateSourceFileFlags(Player);
Player.prestigeSourceFile(); Player.prestigeSourceFile();
prestigeWorkerScripts(); //Delete all Worker Scripts objects prestigeWorkerScripts(); // Delete all Worker Scripts objects
var homeComp = Player.getHomeComputer(); var homeComp = Player.getHomeComputer();
//Delete all servers except home computer // Delete all servers except home computer
prestigeAllServers(); //Must be done before initForeignServers() prestigeAllServers(); // Must be done before initForeignServers()
//Delete Special Server IPs // Delete Special Server IPs
prestigeSpecialServerIps(); prestigeSpecialServerIps();
//Reset home computer (only the programs) and add to AllServers // Reset home computer (only the programs) and add to AllServers
AddToAllServers(homeComp); AddToAllServers(homeComp);
prestigeHomeComputer(homeComp); prestigeHomeComputer(homeComp);
//Re-create foreign servers // Re-create foreign servers
initForeignServers(Player.getHomeComputer()); initForeignServers(Player.getHomeComputer());
if (SourceFileFlags[9] >= 2) { if (SourceFileFlags[9] >= 2) {
@ -253,11 +253,11 @@ function prestigeSourceFile() {
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
initCompanies(); initCompanies();
//Clear terminal // Clear terminal
$("#terminal tr:not(:last)").remove(); $("#terminal tr:not(:last)").remove();
postNetburnerText(); postNetburnerText();
//Messages // Messages
initMessages(); initMessages();
var mainMenu = document.getElementById("mainmenu-container"); var mainMenu = document.getElementById("mainmenu-container");
@ -265,17 +265,17 @@ function prestigeSourceFile() {
Terminal.resetTerminalInput(); Terminal.resetTerminalInput();
Engine.loadTerminalContent(); Engine.loadTerminalContent();
//Reinitialize Bit Node flags // Reinitialize Bit Node flags
initSingularitySFFlags(); initSingularitySFFlags();
//BitNode 3: Corporatocracy // BitNode 3: Corporatocracy
if (Player.bitNodeN === 3) { if (Player.bitNodeN === 3) {
homeComp.messages.push("corporation-management-handbook.lit"); homeComp.messages.push("corporation-management-handbook.lit");
dialogBoxCreate("You received a copy of the Corporation Management Handbook on your home computer. " + dialogBoxCreate("You received a copy of the Corporation Management Handbook on your home computer. " +
"Read it if you need help getting started with Corporations!"); "Read it if you need help getting started with Corporations!");
} }
//BitNode 6: Bladeburner // BitNode 6: Bladeburner
if (Player.bitNodeN === 6) { if (Player.bitNodeN === 6) {
var cinematicText = ["In the middle of the 21st century, OmniTek Incorporated advanced robot evolution " + var cinematicText = ["In the middle of the 21st century, OmniTek Incorporated advanced robot evolution " +
"with their Synthoids (synthetic androids), a being virtually identical to a human.", "with their Synthoids (synthetic androids), a being virtually identical to a human.",
@ -319,7 +319,7 @@ function prestigeSourceFile() {
} }
//BitNode 8: Ghost of Wall Street // BitNode 8: Ghost of Wall Street
if (Player.bitNodeN === 8) {Player.money = new Decimal(BitNode8StartingMoney);} if (Player.bitNodeN === 8) {Player.money = new Decimal(BitNode8StartingMoney);}
if (Player.bitNodeN === 8 || hasWallStreetSF) { if (Player.bitNodeN === 8 || hasWallStreetSF) {
Player.hasWseAccount = true; Player.hasWseAccount = true;
@ -363,7 +363,7 @@ function prestigeSourceFile() {
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
//Gain int exp // Gain int exp
Player.gainIntelligenceExp(5); Player.gainIntelligenceExp(5);
} }

@ -1,3 +1,6 @@
/**
* Implementation for what happens when you destroy a BitNode
*/
import { BitNodes } from "./BitNode/BitNode"; import { BitNodes } from "./BitNode/BitNode";
import { Engine } from "./engine"; import { Engine } from "./engine";
import { Player } from "./Player"; import { Player } from "./Player";
@ -18,10 +21,9 @@ import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement"; import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
/* RedPill.js
* Implements what happens when you have Red Pill augmentation and then hack the world daemon */
//Returns promise
// Returns promise
function writeRedPillLine(line) { function writeRedPillLine(line) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var container = document.getElementById("red-pill-content"); var container = document.getElementById("red-pill-content");
@ -100,8 +102,6 @@ function hackWorldDaemon(currentNodeNumber, flume=false) {
}); });
} }
//The bitNode name passed in will have a hyphen between number (e.g. BitNode-1)
//This needs to be removed
function giveSourceFile(bitNodeNumber) { function giveSourceFile(bitNodeNumber) {
var sourceFileKey = "SourceFile"+ bitNodeNumber.toString(); var sourceFileKey = "SourceFile"+ bitNodeNumber.toString();
var sourceFile = SourceFiles[sourceFileKey]; var sourceFile = SourceFiles[sourceFileKey];
@ -110,7 +110,7 @@ function giveSourceFile(bitNodeNumber) {
return; return;
} }
//Check if player already has this source file // Check if player already has this source file
var alreadyOwned = false; var alreadyOwned = false;
var ownedSourceFile = null; var ownedSourceFile = null;
for (var i = 0; i < Player.sourceFiles.length; ++i) { for (var i = 0; i < Player.sourceFiles.length; ++i) {
@ -133,7 +133,7 @@ function giveSourceFile(bitNodeNumber) {
} else { } else {
var playerSrcFile = new PlayerOwnedSourceFile(bitNodeNumber, 1); var playerSrcFile = new PlayerOwnedSourceFile(bitNodeNumber, 1);
Player.sourceFiles.push(playerSrcFile); Player.sourceFiles.push(playerSrcFile);
if (bitNodeNumber === 5) { //Artificial Intelligence if (bitNodeNumber === 5) { // Artificial Intelligence
Player.intelligence = 1; Player.intelligence = 1;
} }
dialogBoxCreate("You received a Source-File for destroying a Bit Node!<br><br>" + dialogBoxCreate("You received a Source-File for destroying a Bit Node!<br><br>" +
@ -142,11 +142,11 @@ function giveSourceFile(bitNodeNumber) {
} }
function loadBitVerse(destroyedBitNodeNum, flume=false) { function loadBitVerse(destroyedBitNodeNum, flume=false) {
//Clear the screen // Clear the screen
var container = document.getElementById("red-pill-content"); var container = document.getElementById("red-pill-content");
removeChildrenFromElement(container); removeChildrenFromElement(container);
//Create the Bit Verse // Create the Bit Verse
var bitVerseImage = document.createElement("pre"); var bitVerseImage = document.createElement("pre");
var bitNodes = []; var bitNodes = [];
for (var i = 1; i <= 12; ++i) { for (var i = 1; i <= 12; ++i) {
@ -211,7 +211,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
container.appendChild(bitVerseImage); container.appendChild(bitVerseImage);
//Bit node event listeners // Bit node event listeners
for (var i = 1; i <= 12; ++i) { for (var i = 1; i <= 12; ++i) {
(function(i) { (function(i) {
var elemId = "bitnode-" + i.toString(); var elemId = "bitnode-" + i.toString();
@ -233,10 +233,10 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
dialogBoxCreate("Not yet implemented! Coming soon!") dialogBoxCreate("Not yet implemented! Coming soon!")
}); });
} }
}(i)); //Immediate invocation closure }(i)); // Immediate invocation closure
} }
//Create lore text // Create lore text
return writeRedPillLine("Many decades ago, a humanoid extraterrestial species which we call the Enders descended on the Earth...violently").then(function() { return writeRedPillLine("Many decades ago, a humanoid extraterrestial species which we call the Enders descended on the Earth...violently").then(function() {
return writeRedPillLine("Our species fought back, but it was futile. The Enders had technology far beyond our own..."); return writeRedPillLine("Our species fought back, but it was futile. The Enders had technology far beyond our own...");
}).then(function() { }).then(function() {
@ -285,7 +285,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
} }
//Returns string with DOM element for Bit Node // Returns string with DOM element for Bit Node
function createBitNode(n) { function createBitNode(n) {
var bitNodeStr = "BitNode" + n.toString(); var bitNodeStr = "BitNode" + n.toString();
var bitNode = BitNodes[bitNodeStr]; var bitNode = BitNodes[bitNodeStr];
@ -304,19 +304,19 @@ function createBitNodeYesNoEventListeners(newBitNode, destroyedBitNode, flume=fa
if (!flume) { if (!flume) {
giveSourceFile(destroyedBitNode); giveSourceFile(destroyedBitNode);
} else { } else {
//If player used flume, subtract 5 int exp. The prestigeSourceFile() // If player used flume, subtract 5 int exp. The prestigeSourceFile()
//function below grants 5 int exp, so this allows sets net gain to 0 // function below grants 5 int exp, so this allows sets net gain to 0
Player.gainIntelligenceExp(-5); Player.gainIntelligenceExp(-5);
} }
redPillFlag = false; redPillFlag = false;
var container = document.getElementById("red-pill-content"); var container = document.getElementById("red-pill-content");
removeChildrenFromElement(container); removeChildrenFromElement(container);
//Set new Bit Node // Set new Bit Node
Player.bitNodeN = newBitNode; Player.bitNodeN = newBitNode;
console.log("Entering Bit Node " + Player.bitNodeN); console.log("Entering Bit Node " + Player.bitNodeN);
//Reenable terminal // Reenable terminal
$("#hack-progress-bar").attr('id', "old-hack-progress-bar"); $("#hack-progress-bar").attr('id', "old-hack-progress-bar");
$("#hack-progress").attr('id', "old-hack-progress"); $("#hack-progress").attr('id', "old-hack-progress");
document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>'; document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';

@ -72,7 +72,7 @@ function BitburnerSaveObject() {
BitburnerSaveObject.prototype.getSaveString = function() { BitburnerSaveObject.prototype.getSaveString = function() {
this.PlayerSave = JSON.stringify(Player); this.PlayerSave = JSON.stringify(Player);
//Delete all logs from all running scripts // Delete all logs from all running scripts
var TempAllServers = JSON.parse(JSON.stringify(AllServers), Reviver); var TempAllServers = JSON.parse(JSON.stringify(AllServers), Reviver);
for (var ip in TempAllServers) { for (var ip in TempAllServers) {
var server = TempAllServers[ip]; var server = TempAllServers[ip];
@ -106,7 +106,7 @@ BitburnerSaveObject.prototype.getSaveString = function() {
BitburnerSaveObject.prototype.saveGame = function(db) { BitburnerSaveObject.prototype.saveGame = function(db) {
var saveString = this.getSaveString(); var saveString = this.getSaveString();
//We'll save to both localstorage and indexedDb // We'll save to both localstorage and indexedDb
var objectStore = db.transaction(["savestring"], "readwrite").objectStore("savestring"); var objectStore = db.transaction(["savestring"], "readwrite").objectStore("savestring");
var request = objectStore.put(saveString, "save"); var request = objectStore.put(saveString, "save");
@ -115,12 +115,11 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
} }
request.onsuccess = function(e) { request.onsuccess = function(e) {
//console.log("Saved game to IndexedDB!"); // TODO anything here?
} }
try { try {
window.localStorage.setItem("bitburnerSave", saveString); window.localStorage.setItem("bitburnerSave", saveString);
//console.log("Saved game to LocalStorage!");
} catch(e) { } catch(e) {
if (e.code == 22) { if (e.code == 22) {
createStatusText("Save failed for localStorage! Check console(F12)"); createStatusText("Save failed for localStorage! Check console(F12)");
@ -260,7 +259,7 @@ function loadGame(saveString) {
evaluateVersionCompatibility(ver); evaluateVersionCompatibility(ver);
if (window.location.href.toLowerCase().includes("bitburner-beta")) { if (window.location.href.toLowerCase().includes("bitburner-beta")) {
//Beta branch, always show changes // Beta branch, always show changes
createBetaUpdateText(); createBetaUpdateText();
} else if (ver != CONSTANTS.Version) { } else if (ver != CONSTANTS.Version) {
createNewUpdateText(); createNewUpdateText();
@ -296,8 +295,8 @@ function loadImportedGame(saveObj, saveString) {
var tempAllGangs = null; var tempAllGangs = null;
let tempCorporationResearchTrees = null; let tempCorporationResearchTrees = null;
//Check to see if the imported save file can be parsed. If any // Check to see if the imported save file can be parsed. If any
//errors are caught it will fail // errors are caught it will fail
try { try {
var decodedSaveString = decodeURIComponent(escape(atob(saveString))); var decodedSaveString = decodeURIComponent(escape(atob(saveString)));
tempSaveObj = new BitburnerSaveObject(); tempSaveObj = new BitburnerSaveObject();
@ -305,7 +304,7 @@ function loadImportedGame(saveObj, saveString) {
tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver); tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver);
//Parse Decimal.js objects // Parse Decimal.js objects
tempPlayer.money = new Decimal(tempPlayer.money); tempPlayer.money = new Decimal(tempPlayer.money);
tempAllServers = JSON.parse(tempSaveObj.AllServersSave, Reviver); tempAllServers = JSON.parse(tempSaveObj.AllServersSave, Reviver);
@ -374,7 +373,7 @@ function loadImportedGame(saveObj, saveString) {
return false; return false;
} }
//Since the save file is valid, load everything for real // Since the save file is valid, load everything for real
saveString = decodeURIComponent(escape(atob(saveString))); saveString = decodeURIComponent(escape(atob(saveString)));
saveObj = JSON.parse(saveString, Reviver); saveObj = JSON.parse(saveString, Reviver);
@ -472,18 +471,18 @@ function loadImportedGame(saveObj, saveString) {
createPopup(popupId, [txt, gotitBtn]); createPopup(popupId, [txt, gotitBtn]);
gameOptionsBoxClose(); gameOptionsBoxClose();
//Re-start game // Re-start game
console.log("Importing game"); console.log("Importing game");
Engine.setDisplayElements(); //Sets variables for important DOM elements Engine.setDisplayElements(); // Sets variables for important DOM elements
Engine.init(); //Initialize buttons, work, etc. Engine.init(); // Initialize buttons, work, etc.
//Calculate the number of cycles have elapsed while offline // Calculate the number of cycles have elapsed while offline
Engine._lastUpdate = new Date().getTime(); Engine._lastUpdate = new Date().getTime();
var lastUpdate = Player.lastUpdate; var lastUpdate = Player.lastUpdate;
var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed); var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed);
/* Process offline progress */ // Process offline progress
var offlineProductionFromScripts = loadAllRunningScripts(); //This also takes care of offline production for those scripts var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
if (Player.isWorking) { if (Player.isWorking) {
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds"); console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
if (Player.workType == CONSTANTS.WorkTypeFaction) { if (Player.workType == CONSTANTS.WorkTypeFaction) {
@ -501,16 +500,16 @@ function loadImportedGame(saveObj, saveString) {
} }
} }
//Hacknet Nodes offline progress // Hacknet Nodes offline progress
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline); var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
const hacknetProdInfo = hasHacknetServers() ? const hacknetProdInfo = hasHacknetServers() ?
`${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` : `${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` :
`${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`; `${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`;
//Passive faction rep gain offline // Passive faction rep gain offline
processPassiveFactionRepGain(numCyclesOffline); processPassiveFactionRepGain(numCyclesOffline);
//Update total playtime // Update total playtime
var time = numCyclesOffline * Engine._idleSpeed; var time = numCyclesOffline * Engine._idleSpeed;
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;} if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;} if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;}
@ -519,14 +518,14 @@ function loadImportedGame(saveObj, saveString) {
Player.playtimeSinceLastAug += time; Player.playtimeSinceLastAug += time;
Player.playtimeSinceLastBitnode += time; Player.playtimeSinceLastBitnode += time;
//Re-apply augmentations // Re-apply augmentations
Player.reapplyAllAugmentations(); Player.reapplyAllAugmentations();
//Clear terminal // Clear terminal
$("#terminal tr:not(:last)").remove(); $("#terminal tr:not(:last)").remove();
Player.lastUpdate = Engine._lastUpdate; Player.lastUpdate = Engine._lastUpdate;
Engine.start(); //Run main game loop and Scripts loop Engine.start(); // Run main game loop and Scripts loop
const timeOfflineString = convertTimeMsToTimeElapsedString(time); const timeOfflineString = convertTimeMsToTimeElapsedString(time);
dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` + dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` +
"generated <span class='money-gold'>" + "generated <span class='money-gold'>" +
@ -582,12 +581,12 @@ BitburnerSaveObject.prototype.importGame = function() {
} }
BitburnerSaveObject.prototype.deleteGame = function(db) { BitburnerSaveObject.prototype.deleteGame = function(db) {
//Delete from local storage // Delete from local storage
if (window.localStorage.getItem("bitburnerSave")) { if (window.localStorage.getItem("bitburnerSave")) {
window.localStorage.removeItem("bitburnerSave"); window.localStorage.removeItem("bitburnerSave");
} }
//Delete from indexedDB // Delete from indexedDB
var request = db.transaction(["savestring"], "readwrite").objectStore("savestring").delete("save"); var request = db.transaction(["savestring"], "readwrite").objectStore("savestring").delete("save");
request.onsuccess = function(e) { request.onsuccess = function(e) {
console.log("Successfully deleted save from indexedDb"); console.log("Successfully deleted save from indexedDb");
@ -624,8 +623,6 @@ BitburnerSaveObject.fromJSON = function(value) {
Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject; Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject;
//Import game
function openImportFileHandler(evt) { function openImportFileHandler(evt) {
var file = evt.target.files[0]; var file = evt.target.files[0];
if (!file) { if (!file) {

@ -1,8 +1,7 @@
import { Player } from "./Player"; import { Player } from "./Player";
import { BitNodes } from "./BitNode/BitNode"; import { BitNodes } from "./BitNode/BitNode";
/* SourceFile.js */ // Each SourceFile corresponds to a BitNode with the same number
//Each SourceFile corresponds to a BitNode with the same number
function SourceFile(number, info="") { function SourceFile(number, info="") {
var bitnodeKey = "BitNode" + number; var bitnodeKey = "BitNode" + number;
var bitnode = BitNodes[bitnodeKey]; var bitnode = BitNodes[bitnodeKey];
@ -80,7 +79,7 @@ function initSourceFiles() {
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)"); "In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
} }
//Takes in a PlayerOwnedSourceFile as the "srcFile" argument // Takes in a PlayerOwnedSourceFile as the "srcFile" argument
function applySourceFile(srcFile) { function applySourceFile(srcFile) {
var srcFileKey = "SourceFile" + srcFile.n; var srcFileKey = "SourceFile" + srcFile.n;
var sourceFileObject = SourceFiles[srcFileKey]; var sourceFileObject = SourceFiles[srcFileKey];

@ -112,13 +112,13 @@ function isNumber(str) {
// Defines key commands in terminal // Defines key commands in terminal
$(document).keydown(function(event) { $(document).keydown(function(event) {
//Terminal // Terminal
if (routing.isOn(Page.Terminal)) { if (routing.isOn(Page.Terminal)) {
var terminalInput = document.getElementById("terminal-input-text-box"); var terminalInput = document.getElementById("terminal-input-text-box");
if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();} if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();}
if (event.keyCode === KEY.ENTER) { if (event.keyCode === KEY.ENTER) {
event.preventDefault(); //Prevent newline from being entered in Script Editor event.preventDefault(); // Prevent newline from being entered in Script Editor
const command = terminalInput.value; const command = terminalInput.value;
const dir = Terminal.currDir; const dir = Terminal.currDir;
post( post(
@ -129,35 +129,35 @@ $(document).keydown(function(event) {
); );
if (command.length > 0) { if (command.length > 0) {
Terminal.resetTerminalInput(); //Clear input first Terminal.resetTerminalInput(); // Clear input first
Terminal.executeCommands(command); Terminal.executeCommands(command);
} }
} }
if (event.keyCode === KEY.C && event.ctrlKey) { if (event.keyCode === KEY.C && event.ctrlKey) {
if (Engine._actionInProgress) { if (Engine._actionInProgress) {
//Cancel action // Cancel action
post("Cancelling..."); post("Cancelling...");
Engine._actionInProgress = false; Engine._actionInProgress = false;
Terminal.finishAction(true); Terminal.finishAction(true);
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) { } else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
//Dont prevent default so it still copies // Dont prevent default so it still copies
Terminal.resetTerminalInput(); //Clear Terminal Terminal.resetTerminalInput(); // Clear Terminal
} }
} }
if (event.keyCode === KEY.L && event.ctrlKey) { if (event.keyCode === KEY.L && event.ctrlKey) {
event.preventDefault(); event.preventDefault();
Terminal.executeCommand("clear"); //Clear screen Terminal.executeCommand("clear"); // Clear screen
} }
//Ctrl p same as up arrow // Ctrl p same as up arrow
//Ctrl n same as down arrow // Ctrl n same as down arrow
if (event.keyCode === KEY.UPARROW || if (event.keyCode === KEY.UPARROW ||
(FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.P && event.ctrlKey)) { (FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.P && event.ctrlKey)) {
if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();} if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();}
//Cycle through past commands // Cycle through past commands
if (terminalInput == null) {return;} if (terminalInput == null) {return;}
var i = Terminal.commandHistoryIndex; var i = Terminal.commandHistoryIndex;
var len = Terminal.commandHistory.length; var len = Terminal.commandHistory.length;
@ -178,7 +178,7 @@ $(document).keydown(function(event) {
if (event.keyCode === KEY.DOWNARROW || if (event.keyCode === KEY.DOWNARROW ||
(FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.M && event.ctrlKey)) { (FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.M && event.ctrlKey)) {
if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();} if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();}
//Cycle through past commands // Cycle through past commands
if (terminalInput == null) {return;} if (terminalInput == null) {return;}
var i = Terminal.commandHistoryIndex; var i = Terminal.commandHistoryIndex;
var len = Terminal.commandHistory.length; var len = Terminal.commandHistory.length;
@ -188,7 +188,7 @@ $(document).keydown(function(event) {
Terminal.commandHistoryIndex = len; Terminal.commandHistoryIndex = len;
} }
//Latest command, put nothing // Latest command, put nothing
if (i == len || i == len-1) { if (i == len || i == len-1) {
Terminal.commandHistoryIndex = len; Terminal.commandHistoryIndex = len;
terminalInput.value = ""; terminalInput.value = "";
@ -202,7 +202,7 @@ $(document).keydown(function(event) {
if (event.keyCode === KEY.TAB) { if (event.keyCode === KEY.TAB) {
event.preventDefault(); event.preventDefault();
//Autocomplete // Autocomplete
if (terminalInput == null) {return;} if (terminalInput == null) {return;}
var input = terminalInput.value; var input = terminalInput.value;
if (input == "") {return;} if (input == "") {return;}
@ -240,7 +240,7 @@ $(document).keydown(function(event) {
terminalInput.focus(); terminalInput.focus();
} }
//Extra Bash Emulation Hotkeys, must be enabled through .fconf // Extra Bash Emulation Hotkeys, must be enabled through .fconf
if (FconfSettings.ENABLE_BASH_HOTKEYS) { if (FconfSettings.ENABLE_BASH_HOTKEYS) {
if (event.keyCode === KEY.A && event.ctrlKey) { if (event.keyCode === KEY.A && event.ctrlKey) {
event.preventDefault(); event.preventDefault();
@ -278,17 +278,16 @@ $(document).keydown(function(event) {
event.preventDefault(); event.preventDefault();
} }
//TODO AFTER THIS: // TODO AFTER THIS:
// alt + d deletes word after cursor
//alt + d deletes word after cursor // ^w deletes word before cursor
//^w deletes word before cursor // ^k clears line after cursor
//^k clears line after cursor // ^u clears line before cursor
//^u clears line before cursor
} }
} }
}); });
//Keep terminal in focus // Keep terminal in focus
let terminalCtrlPressed = false, shiftKeyPressed = false; let terminalCtrlPressed = false, shiftKeyPressed = false;
$(document).ready(function() { $(document).ready(function() {
if (routing.isOn(Page.Terminal)) { if (routing.isOn(Page.Terminal)) {
@ -303,7 +302,7 @@ $(document).keydown(function(e) {
} else if (e.shiftKey) { } else if (e.shiftKey) {
shiftKeyPressed = true; shiftKeyPressed = true;
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) { } else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
//Don't focus // Don't focus
} else { } else {
var inputTextBox = document.getElementById("terminal-input-text-box"); var inputTextBox = document.getElementById("terminal-input-text-box");
if (inputTextBox != null) {inputTextBox.focus();} if (inputTextBox != null) {inputTextBox.focus();}
@ -349,7 +348,7 @@ let Terminal = {
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` + `<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
'<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>'; '<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
//Auto re-size the line element as it wraps // Auto re-size the line element as it wraps
autosize(document.getElementById("terminal-input-text-box")); autosize(document.getElementById("terminal-input-text-box"));
} else { } else {
document.getElementById("terminal-input-td").innerHTML = document.getElementById("terminal-input-td").innerHTML =
@ -377,7 +376,7 @@ let Terminal = {
terminalInput.value = inputText.substr(0, start-1) + inputText.substr(start); terminalInput.value = inputText.substr(0, start-1) + inputText.substr(start);
} }
break; break;
case "deletewordbefore": //Delete rest of word before the cursor case "deletewordbefore": // Delete rest of word before the cursor
for (var delStart = start-1; delStart > 0; --delStart) { for (var delStart = start-1; delStart > 0; --delStart) {
if (inputText.charAt(delStart) === " ") { if (inputText.charAt(delStart) === " ") {
terminalInput.value = inputText.substr(0, delStart) + inputText.substr(start); terminalInput.value = inputText.substr(0, delStart) + inputText.substr(start);
@ -385,7 +384,7 @@ let Terminal = {
} }
} }
break; break;
case "deletewordafter": //Delete rest of word after the cursor case "deletewordafter": // Delete rest of word after the cursor
for (var delStart = start+1; delStart <= text.length+1; ++delStart) { for (var delStart = start+1; delStart <= text.length+1; ++delStart) {
if (inputText.charAt(delStart) === " ") { if (inputText.charAt(delStart) === " ") {
terminalInput.value = inputText.substr(0, start) + inputText.substr(delStart); terminalInput.value = inputText.substr(0, start) + inputText.substr(delStart);
@ -393,9 +392,9 @@ let Terminal = {
} }
} }
break; break;
case "clearafter": //Deletes everything after cursor case "clearafter": // Deletes everything after cursor
break; break;
case "clearbefore:": //Deleetes everything before cursor case "clearbefore:": // Deleetes everything before cursor
break; break;
} }
} catch(e) { } catch(e) {
@ -456,7 +455,7 @@ let Terminal = {
startHack: function() { startHack: function() {
Terminal.hackFlag = true; Terminal.hackFlag = true;
//Hacking through Terminal should be faster than hacking through a script // Hacking through Terminal should be faster than hacking through a script
Terminal.actionTime = calculateHackingTime(Player.getCurrentServer()) / 4; Terminal.actionTime = calculateHackingTime(Player.getCurrentServer()) / 4;
Terminal.startAction(); Terminal.startAction();
}, },
@ -474,7 +473,7 @@ let Terminal = {
hackProgressPost("Time left:"); hackProgressPost("Time left:");
hackProgressBarPost("["); hackProgressBarPost("[");
//Disable terminal // Disable terminal
document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>'; document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>';
$('input[class=terminal-input]').prop('disabled', true); $('input[class=terminal-input]').prop('disabled', true);
}, },
@ -487,17 +486,17 @@ let Terminal = {
} }
}, },
//Complete the hack/analyze command // Complete the hack/analyze command
finishHack: function(cancelled = false) { finishHack: function(cancelled = false) {
if (cancelled == false) { if (cancelled == false) {
var server = Player.getCurrentServer(); var server = Player.getCurrentServer();
//Calculate whether hack was successful // Calculate whether hack was successful
var hackChance = calculateHackingChance(server); var hackChance = calculateHackingChance(server);
var rand = Math.random(); var rand = Math.random();
var expGainedOnSuccess = calculateHackingExpGain(server); var expGainedOnSuccess = calculateHackingExpGain(server);
var expGainedOnFailure = (expGainedOnSuccess / 4); var expGainedOnFailure = (expGainedOnSuccess / 4);
if (rand < hackChance) { //Success! if (rand < hackChance) { // Success!
if (SpecialServerIps[SpecialServerNames.WorldDaemon] && if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) { SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
if (Player.bitNodeN == null) { if (Player.bitNodeN == null) {
@ -510,7 +509,7 @@ let Terminal = {
var moneyGained = calculatePercentMoneyHacked(server); var moneyGained = calculatePercentMoneyHacked(server);
moneyGained = Math.floor(server.moneyAvailable * moneyGained); moneyGained = Math.floor(server.moneyAvailable * moneyGained);
if (moneyGained <= 0) {moneyGained = 0;} //Safety check if (moneyGained <= 0) {moneyGained = 0;} // Safety check
server.moneyAvailable -= moneyGained; server.moneyAvailable -= moneyGained;
Player.gainMoney(moneyGained); Player.gainMoney(moneyGained);
@ -521,14 +520,14 @@ let Terminal = {
server.fortify(CONSTANTS.ServerFortifyAmount); server.fortify(CONSTANTS.ServerFortifyAmount);
post("Hack successful! Gained " + numeralWrapper.format(moneyGained, '($0,0.00)') + " and " + numeralWrapper.format(expGainedOnSuccess, '0.0000') + " hacking EXP"); post("Hack successful! Gained " + numeralWrapper.format(moneyGained, '($0,0.00)') + " and " + numeralWrapper.format(expGainedOnSuccess, '0.0000') + " hacking EXP");
} else { //Failure } else { // Failure
//Player only gains 25% exp for failure? TODO Can change this later to balance // Player only gains 25% exp for failure? TODO Can change this later to balance
Player.gainHackingExp(expGainedOnFailure) Player.gainHackingExp(expGainedOnFailure)
post("Failed to hack " + server.hostname + ". Gained " + numeralWrapper.format(expGainedOnFailure, '0.0000') + " hacking EXP"); post("Failed to hack " + server.hostname + ". Gained " + numeralWrapper.format(expGainedOnFailure, '0.0000') + " hacking EXP");
} }
} }
//Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal // Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
$("#hack-progress-bar").attr('id', "old-hack-progress-bar"); $("#hack-progress-bar").attr('id', "old-hack-progress-bar");
$("#hack-progress").attr('id', "old-hack-progress"); $("#hack-progress").attr('id', "old-hack-progress");
Terminal.resetTerminalInput(); Terminal.resetTerminalInput();
@ -596,7 +595,7 @@ let Terminal = {
executeCommands : function(commands) { executeCommands : function(commands) {
// Sanitize input // Sanitize input
commands = commands.trim(); commands = commands.trim();
commands = commands.replace(/\s\s+/g, ' '); //Replace all extra whitespace in command with a single space commands = commands.replace(/\s\s+/g, ' '); // Replace all extra whitespace in command with a single space
// Handle Terminal History - multiple commands should be saved as one // Handle Terminal History - multiple commands should be saved as one
if (Terminal.commandHistory[Terminal.commandHistory.length-1] != commands) { if (Terminal.commandHistory[Terminal.commandHistory.length-1] != commands) {
@ -644,7 +643,7 @@ let Terminal = {
if (endQuote === command.length-1) { if (endQuote === command.length-1) {
start = i = endQuote+1; start = i = endQuote+1;
} else { } else {
start = i = endQuote+2; //Skip the space start = i = endQuote+2; // Skip the space
} }
continue; continue;
} }
@ -663,7 +662,7 @@ let Terminal = {
if (endQuote === command.length-1) { if (endQuote === command.length-1) {
start = i = endQuote+1; start = i = endQuote+1;
} else { } else {
start = i = endQuote+2; //Skip the space start = i = endQuote+2; // Skip the space
} }
continue; continue;
} }
@ -705,15 +704,15 @@ let Terminal = {
}, },
executeCommand : function(command) { executeCommand : function(command) {
//Process any aliases // Process any aliases
command = substituteAliases(command); command = substituteAliases(command);
//Allow usage of ./ // Allow usage of ./
if (command.startsWith("./")) { if (command.startsWith("./")) {
command = "run " + command.slice(2); command = "run " + command.slice(2);
} }
//Only split the first space // Only split the first space
var commandArray = Terminal.parseCommandArguments(command); var commandArray = Terminal.parseCommandArguments(command);
if (commandArray.length == 0) { return; } if (commandArray.length == 0) { return; }
@ -815,7 +814,7 @@ let Terminal = {
case iTutorialSteps.ActiveScriptsToTerminal: case iTutorialSteps.ActiveScriptsToTerminal:
if (commandArray.length == 2 && if (commandArray.length == 2 &&
commandArray[0] == "tail" && commandArray[1] == "foodnstuff.script") { commandArray[0] == "tail" && commandArray[1] == "foodnstuff.script") {
//Check that the script exists on this machine // Check that the script exists on this machine
var runningScript = findRunningScript("foodnstuff.script", [], Player.getCurrentServer()); var runningScript = findRunningScript("foodnstuff.script", [], Player.getCurrentServer());
if (runningScript == null) { if (runningScript == null) {
post("Error: No such script exists"); post("Error: No such script exists");
@ -941,7 +940,7 @@ let Terminal = {
postError("Incorrect number of arguments. Usage: check [script] [arg1] [arg2]..."); postError("Incorrect number of arguments. Usage: check [script] [arg1] [arg2]...");
} else { } else {
const scriptName = Terminal.getFilepath(commandArray[1]); const scriptName = Terminal.getFilepath(commandArray[1]);
//Can only tail script files // Can only tail script files
if (!isScriptFilename(scriptName)) { if (!isScriptFilename(scriptName)) {
postError("tail can only be called on .script files (filename must end with .script)"); postError("tail can only be called on .script files (filename must end with .script)");
return; return;
@ -977,7 +976,7 @@ let Terminal = {
postNetburnerText(); postNetburnerText();
break; break;
case "connect": { case "connect": {
//Disconnect from current server in terminal and connect to new one // Disconnect from current server in terminal and connect to new one
if (commandArray.length !== 2) { if (commandArray.length !== 2) {
postError("Incorrect usage of connect command. Usage: connect [ip/hostname]"); postError("Incorrect usage of connect command. Usage: connect [ip/hostname]");
return; return;
@ -1003,7 +1002,7 @@ let Terminal = {
} }
const fn = commandArray[1]; const fn = commandArray[1];
if (fn === "*" || fn === "*.script" || fn === "*.txt") { if (fn === "*" || fn === "*.script" || fn === "*.txt") {
//Download all scripts as a zip // Download all scripts as a zip
var zip = new JSZip(); var zip = new JSZip();
if (fn === "*" || fn === "*.script") { if (fn === "*" || fn === "*.script") {
for (var i = 0; i < s.scripts.length; ++i) { for (var i = 0; i < s.scripts.length; ++i) {
@ -1081,8 +1080,8 @@ let Terminal = {
postError("Incorrect usage of hack command. Usage: hack"); postError("Incorrect usage of hack command. Usage: hack");
return; return;
} }
//Hack the current PC (usually for money) // Hack the current PC (usually for money)
//You can't hack your home pc or servers you purchased // You can't hack your home pc or servers you purchased
if (s.purchasedByPlayer) { if (s.purchasedByPlayer) {
postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers"); postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers");
} else if (s.hasAdminRights == false ) { } else if (s.hasAdminRights == false ) {
@ -1262,7 +1261,7 @@ let Terminal = {
return; return;
} }
//Check programs // Check programs
let delTarget = Terminal.getFilepath(commandArray[1]); let delTarget = Terminal.getFilepath(commandArray[1]);
const status = s.removeFile(delTarget); const status = s.removeFile(delTarget);
@ -1272,19 +1271,19 @@ let Terminal = {
break; break;
} }
case "run": case "run":
//Run a program or a script // Run a program or a script
if (commandArray.length < 2) { if (commandArray.length < 2) {
postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]..."); postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
} else { } else {
var executableName = commandArray[1]; var executableName = commandArray[1];
//Secret Music player! // Secret Music player!
if (executableName === "musicplayer") { if (executableName === "musicplayer") {
post('<iframe src="https://open.spotify.com/embed/user/danielyxie/playlist/1ORnnL6YNvXOracUaUV2kh" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>', false); post('<iframe src="https://open.spotify.com/embed/user/danielyxie/playlist/1ORnnL6YNvXOracUaUV2kh" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>', false);
return; return;
} }
//Check if its a script or just a program/executable // Check if its a script or just a program/executable
if (isScriptFilename(executableName)) { if (isScriptFilename(executableName)) {
Terminal.runScript(commandArray); Terminal.runScript(commandArray);
} else if (executableName.endsWith(".cct")) { } else if (executableName.endsWith(".cct")) {
@ -1434,20 +1433,20 @@ let Terminal = {
post("Script Threads RAM Usage"); post("Script Threads RAM Usage");
let currRunningScripts = s.runningScripts; let currRunningScripts = s.runningScripts;
//Iterate through scripts on current server // Iterate through scripts on current server
for (let i = 0; i < currRunningScripts.length; i++) { for (let i = 0; i < currRunningScripts.length; i++) {
let script = currRunningScripts[i]; let script = currRunningScripts[i];
//Calculate name padding // Calculate name padding
let numSpacesScript = 32 - script.filename.length; //26 -> width of name column let numSpacesScript = 32 - script.filename.length; // 26 -> width of name column
if (numSpacesScript < 0) {numSpacesScript = 0;} if (numSpacesScript < 0) {numSpacesScript = 0;}
let spacesScript = Array(numSpacesScript+1).join(" "); let spacesScript = Array(numSpacesScript+1).join(" ");
//Calculate thread padding // Calculate thread padding
let numSpacesThread = 16 - (script.threads + "").length; //16 -> width of thread column let numSpacesThread = 16 - (script.threads + "").length; // 16 -> width of thread column
let spacesThread = Array(numSpacesThread+1).join(" "); let spacesThread = Array(numSpacesThread+1).join(" ");
//Calculate and transform RAM usage // Calculate and transform RAM usage
let ramUsage = numeralWrapper.format(script.getRamUsage() * script.threads, '0.00') + " GB"; let ramUsage = numeralWrapper.format(script.getRamUsage() * script.threads, '0.00') + " GB";
var entry = [script.filename, spacesScript, script.threads, spacesThread, ramUsage]; var entry = [script.filename, spacesScript, script.threads, spacesThread, ramUsage];
@ -1515,7 +1514,7 @@ let Terminal = {
post("Connected to " + serv.hostname); post("Connected to " + serv.hostname);
Terminal.currDir = "/"; Terminal.currDir = "/";
if (Player.getCurrentServer().hostname == "darkweb") { if (Player.getCurrentServer().hostname == "darkweb") {
checkIfConnectedToDarkweb(); //Posts a 'help' message if connecting to dark web checkIfConnectedToDarkweb(); // Posts a 'help' message if connecting to dark web
} }
Terminal.resetTerminalInput(); Terminal.resetTerminalInput();
}, },
@ -1606,7 +1605,7 @@ let Terminal = {
prefix = null; prefix = null;
} }
//Display all programs and scripts // Display all programs and scripts
let allFiles = []; let allFiles = [];
let folders = []; let folders = [];
@ -1742,18 +1741,18 @@ let Terminal = {
const currServ = Player.getCurrentServer(); const currServ = Player.getCurrentServer();
post("Hostname IP Root Access"); post("Hostname IP Root Access");
for (let i = 0; i < currServ.serversOnNetwork.length; i++) { for (let i = 0; i < currServ.serversOnNetwork.length; i++) {
//Add hostname // Add hostname
let entry = getServerOnNetwork(currServ, i); let entry = getServerOnNetwork(currServ, i);
if (entry == null) { continue; } if (entry == null) { continue; }
entry = entry.hostname; entry = entry.hostname;
//Calculate padding and add IP // Calculate padding and add IP
let numSpaces = 21 - entry.length; let numSpaces = 21 - entry.length;
let spaces = Array(numSpaces+1).join(" "); let spaces = Array(numSpaces+1).join(" ");
entry += spaces; entry += spaces;
entry += getServerOnNetwork(currServ, i).ip; entry += getServerOnNetwork(currServ, i).ip;
//Calculate padding and add root access info // Calculate padding and add root access info
let hasRoot; let hasRoot;
if (getServerOnNetwork(currServ, i).hasAdminRights) { if (getServerOnNetwork(currServ, i).hasAdminRights) {
hasRoot = 'Y'; hasRoot = 'Y';
@ -1769,7 +1768,7 @@ let Terminal = {
}, },
executeScanAnalyzeCommand: function(depth=1, all=false) { executeScanAnalyzeCommand: function(depth=1, all=false) {
//TODO Using array as stack for now, can make more efficient // TODO Using array as stack for now, can make more efficient
post("~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~"); post("~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~");
post(" "); post(" ");
@ -1800,7 +1799,7 @@ let Terminal = {
stack.push(getServerOnNetwork(s, i)); stack.push(getServerOnNetwork(s, i));
depthQueue.push(d+1); depthQueue.push(d+1);
} }
if (d == 0) {continue;} //Don't print current server if (d == 0) {continue;} // Don't print current server
var titleDashes = Array((d-1) * 4 + 1).join("-"); var titleDashes = Array((d-1) * 4 + 1).join("-");
if (Player.hasProgram(Programs.AutoLink.name)) { if (Player.hasProgram(Programs.AutoLink.name)) {
post("<strong>" + titleDashes + "> <a class='scan-analyze-link'>" + s.hostname + "</a></strong>", false); post("<strong>" + titleDashes + "> <a class='scan-analyze-link'>" + s.hostname + "</a></strong>", false);
@ -1809,7 +1808,6 @@ let Terminal = {
} }
var dashes = titleDashes + "--"; var dashes = titleDashes + "--";
//var dashes = Array(d * 2 + 1).join("-");
var c = "NO"; var c = "NO";
if (s.hasAdminRights) {c = "YES";} if (s.hasAdminRights) {c = "YES";}
post(`${dashes}Root Access: ${c}${!isHacknet ? ", Required hacking skill: " + s.requiredHackingSkill : ""}`); post(`${dashes}Root Access: ${c}${!isHacknet ? ", Required hacking skill: " + s.requiredHackingSkill : ""}`);
@ -1826,7 +1824,7 @@ let Terminal = {
if (Terminal.analyzeFlag || Terminal.hackFlag) {return;} if (Terminal.analyzeFlag || Terminal.hackFlag) {return;}
Terminal.connectToServer(hostname); Terminal.connectToServer(hostname);
} }
}());//Immediate invocation }());// Immediate invocation
} }
}, },
@ -1850,7 +1848,7 @@ let Terminal = {
const ip = destServer.ip; const ip = destServer.ip;
const currServ = Player.getCurrentServer(); const currServ = Player.getCurrentServer();
//Scp for lit files // Scp for lit files
if (scriptname.endsWith(".lit")) { if (scriptname.endsWith(".lit")) {
var found = false; var found = false;
for (var i = 0; i < currServ.messages.length; ++i) { for (var i = 0; i < currServ.messages.length; ++i) {
@ -1865,14 +1863,14 @@ let Terminal = {
for (var i = 0; i < destServer.messages.length; ++i) { for (var i = 0; i < destServer.messages.length; ++i) {
if (destServer.messages[i] === scriptname) { if (destServer.messages[i] === scriptname) {
post(scriptname + " copied over to " + destServer.hostname); post(scriptname + " copied over to " + destServer.hostname);
return; //Already exists return; // Already exists
} }
} }
destServer.messages.push(scriptname); destServer.messages.push(scriptname);
return post(scriptname + " copied over to " + destServer.hostname); return post(scriptname + " copied over to " + destServer.hostname);
} }
//Scp for txt files // Scp for txt files
if (scriptname.endsWith(".txt")) { if (scriptname.endsWith(".txt")) {
var found = false, txtFile; var found = false, txtFile;
for (var i = 0; i < currServ.textFiles.length; ++i) { for (var i = 0; i < currServ.textFiles.length; ++i) {
@ -1928,8 +1926,8 @@ let Terminal = {
} }
}, },
//First called when the "run [program]" command is called. Checks to see if you // First called when the "run [program]" command is called. Checks to see if you
//have the executable and, if you do, calls the executeProgram() function // have the executable and, if you do, calls the executeProgram() function
runProgram: function(commandArray) { runProgram: function(commandArray) {
if (commandArray.length < 2) { return; } if (commandArray.length < 2) { return; }
@ -1944,7 +1942,7 @@ let Terminal = {
post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)"); post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)");
}, },
//Contains the implementations of all possible programs // Contains the implementations of all possible programs
executeProgram: function(commandArray) { executeProgram: function(commandArray) {
if (commandArray.length < 2) { return; } if (commandArray.length < 2) { return; }
@ -2238,16 +2236,16 @@ let Terminal = {
} }
//Check if this script is already running // Check if this script is already running
if (findRunningScript(scriptName, args, server) != null) { if (findRunningScript(scriptName, args, server) != null) {
post("ERROR: This script is already running. Cannot run multiple instances"); post("ERROR: This script is already running. Cannot run multiple instances");
return; return;
} }
//Check if the script exists and if it does run it // Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; i++) { for (var i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename === scriptName) { if (server.scripts[i].filename === scriptName) {
//Check for admin rights and that there is enough RAM availble to run // Check for admin rights and that there is enough RAM availble to run
var script = server.scripts[i]; var script = server.scripts[i];
var ramUsage = script.ramUsage * numThreads; var ramUsage = script.ramUsage * numThreads;
var ramAvailable = server.maxRam - server.ramUsed; var ramAvailable = server.maxRam - server.ramUsed;
@ -2260,7 +2258,7 @@ let Terminal = {
numThreads + " threads. Script requires " + ramUsage + "GB of RAM"); numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
return; return;
} else { } else {
//Able to run script // Able to run script
post("Running script with " + numThreads + " thread(s) and args: " + arrayToString(args) + "."); post("Running script with " + numThreads + " thread(s) and args: " + arrayToString(args) + ".");
post("May take a few seconds to start up the process..."); post("May take a few seconds to start up the process...");
var runningScriptObj = new RunningScript(script, args); var runningScriptObj = new RunningScript(script, args);

@ -155,7 +155,8 @@ import "../css/grid.min.css";
import "../css/dev-menu.css"; import "../css/dev-menu.css";
/* Shortcuts to navigate through the game /**
* Shortcuts to navigate through the game
* Alt-t - Terminal * Alt-t - Terminal
* Alt-c - Character * Alt-c - Character
* Alt-e - Script editor * Alt-e - Script editor
@ -209,7 +210,7 @@ $(document).keydown(function(e) {
e.preventDefault(); e.preventDefault();
Engine.loadCreateProgramContent(); Engine.loadCreateProgramContent();
} else if (e.keyCode === KEY.F && e.altKey) { } else if (e.keyCode === KEY.F && e.altKey) {
//Overriden by Fconf // Overriden by Fconf
if (routing.isOn(Page.Terminal) && FconfSettings.ENABLE_BASH_HOTKEYS) { if (routing.isOn(Page.Terminal) && FconfSettings.ENABLE_BASH_HOTKEYS) {
return; return;
} }
@ -234,24 +235,25 @@ const Engine = {
version: "", version: "",
Debug: true, Debug: true,
//Clickable objects // Clickable objects
Clickables: { Clickables: {
//Main menu buttons // Main menu buttons
saveMainMenuButton: null, saveMainMenuButton: null,
deleteMainMenuButton: null, deleteMainMenuButton: null,
}, },
//Display objects // Display objects
// TODO-Refactor this into its own component
Display: { Display: {
//Progress bar // Progress bar
progress: null, progress: null,
//Display for status text (such as "Saved" or "Loaded") // Display for status text (such as "Saved" or "Loaded")
statusText: null, statusText: null,
hacking_skill: null, hacking_skill: null,
//Main menu content // Main menu content
terminalContent: null, terminalContent: null,
characterContent: null, characterContent: null,
scriptEditorContent: null, scriptEditorContent: null,
@ -271,15 +273,14 @@ const Engine = {
cinematicTextContent: null, cinematicTextContent: null,
missionContent: null, missionContent: null,
//Character info // Character info
characterInfo: null, characterInfo: null,
}, },
//Time variables (milliseconds unix epoch time) // Time variables (milliseconds unix epoch time)
_lastUpdate: new Date().getTime(), _lastUpdate: new Date().getTime(),
_idleSpeed: 200, //Speed (in ms) at which the main loop is updated _idleSpeed: 200, // Speed (in ms) at which the main loop is updated
/* Load content when a main menu button is clicked */
loadTerminalContent: function() { loadTerminalContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
Engine.Display.terminalContent.style.display = "block"; Engine.Display.terminalContent.style.display = "block";
@ -425,7 +426,6 @@ const Engine = {
loadWorkInProgressContent: function() { loadWorkInProgressContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
var mainMenu = document.getElementById("mainmenu-container"); var mainMenu = document.getElementById("mainmenu-container");
//mainMenu.style.visibility = "hidden";
mainMenu.style.visibility = "hidden"; mainMenu.style.visibility = "hidden";
Engine.Display.workInProgressContent.style.display = "block"; Engine.Display.workInProgressContent.style.display = "block";
routing.navigateTo(Page.WorkInProgress); routing.navigateTo(Page.WorkInProgress);
@ -602,15 +602,16 @@ const Engine = {
} }
}, },
/* Display character info */ /// Display character info
updateCharacterInfo: function() { updateCharacterInfo: function() {
displayCharacterInfo(Engine.Display.characterInfo, Player); displayCharacterInfo(Engine.Display.characterInfo, Player);
}, },
// TODO Refactor this into Faction implementation
displayFactionsInfo: function() { displayFactionsInfo: function() {
removeChildrenFromElement(Engine.Display.factionsContent); removeChildrenFromElement(Engine.Display.factionsContent);
//Factions // Factions
Engine.Display.factionsContent.appendChild(createElement("h1", { Engine.Display.factionsContent.appendChild(createElement("h1", {
innerText:"Factions" innerText:"Factions"
})); }));
@ -620,7 +621,7 @@ const Engine = {
var factionsList = createElement("ul"); var factionsList = createElement("ul");
Engine.Display.factionsContent.appendChild(createElement("br")); Engine.Display.factionsContent.appendChild(createElement("br"));
//Add a button for each faction you are a member of // Add a button for each faction you are a member of
for (var i = 0; i < Player.factions.length; ++i) { for (var i = 0; i < Player.factions.length; ++i) {
(function () { (function () {
var factionName = Player.factions[i]; var factionName = Player.factions[i];
@ -635,12 +636,12 @@ const Engine = {
} }
})); }));
factionsList.appendChild(createElement("br")); factionsList.appendChild(createElement("br"));
}()); //Immediate invocation }()); // Immediate invocation
} }
Engine.Display.factionsContent.appendChild(factionsList); Engine.Display.factionsContent.appendChild(factionsList);
Engine.Display.factionsContent.appendChild(createElement("br")); Engine.Display.factionsContent.appendChild(createElement("br"));
//Invited Factions // Invited Factions
Engine.Display.factionsContent.appendChild(createElement("h1", { Engine.Display.factionsContent.appendChild(createElement("h1", {
innerText:"Outstanding Faction Invitations" innerText:"Outstanding Faction Invitations"
})); }));
@ -652,7 +653,7 @@ const Engine = {
})); }));
var invitationsList = createElement("ul"); var invitationsList = createElement("ul");
//Add a button to accept for each faction you have invitiations for // Add a button to accept for each faction you have invitiations for
for (var i = 0; i < Player.factionInvitations.length; ++i) { for (var i = 0; i < Player.factionInvitations.length; ++i) {
(function () { (function () {
var factionName = Player.factionInvitations[i]; var factionName = Player.factionInvitations[i];
@ -685,18 +686,18 @@ const Engine = {
Engine.Display.factionsContent.appendChild(invitationsList); Engine.Display.factionsContent.appendChild(invitationsList);
}, },
/* Main Event Loop */ // Main Game Loop
idleTimer: function() { idleTimer: function() {
//Get time difference // Get time difference
var _thisUpdate = new Date().getTime(); var _thisUpdate = new Date().getTime();
var diff = _thisUpdate - Engine._lastUpdate; var diff = _thisUpdate - Engine._lastUpdate;
var offset = diff % Engine._idleSpeed; var offset = diff % Engine._idleSpeed;
//Divide this by cycle time to determine how many cycles have elapsed since last update // Divide this by cycle time to determine how many cycles have elapsed since last update
diff = Math.floor(diff / Engine._idleSpeed); diff = Math.floor(diff / Engine._idleSpeed);
if (diff > 0) { if (diff > 0) {
//Update the game engine by the calculated number of cycles // Update the game engine by the calculated number of cycles
Engine._lastUpdate = _thisUpdate - offset; Engine._lastUpdate = _thisUpdate - offset;
Player.lastUpdate = _thisUpdate - offset; Player.lastUpdate = _thisUpdate - offset;
Engine.updateGame(diff); Engine.updateGame(diff);
@ -714,7 +715,7 @@ const Engine = {
Player.playtimeSinceLastAug += time; Player.playtimeSinceLastAug += time;
Player.playtimeSinceLastBitnode += time; Player.playtimeSinceLastBitnode += time;
//Start Manual hack // Start Manual hack
if (Terminal.actionStarted === true) { if (Terminal.actionStarted === true) {
Engine._totalActionTime = Terminal.actionTime; Engine._totalActionTime = Terminal.actionTime;
Engine._actionTimeLeft = Terminal.actionTime; Engine._actionTimeLeft = Terminal.actionTime;
@ -725,7 +726,7 @@ const Engine = {
Terminal.actionStarted = false; Terminal.actionStarted = false;
} }
//Working // Working
if (Player.isWorking) { if (Player.isWorking) {
if (Player.workType == CONSTANTS.WorkTypeFaction) { if (Player.workType == CONSTANTS.WorkTypeFaction) {
Player.workForFaction(numCycles); Player.workForFaction(numCycles);
@ -747,20 +748,19 @@ const Engine = {
processStockPrices(numCycles); processStockPrices(numCycles);
} }
//Gang, if applicable // Gang, if applicable
if (Player.bitNodeN == 2 && Player.inGang()) { if (Player.bitNodeN == 2 && Player.inGang()) {
Player.gang.process(numCycles, Player); Player.gang.process(numCycles, Player);
} }
//Mission // Mission
if (inMission && currMission) { if (inMission && currMission) {
currMission.process(numCycles); currMission.process(numCycles);
} }
//Corporation // Corporation
if (Player.corporation instanceof Corporation) { if (Player.corporation instanceof Corporation) {
//Stores cycles in a "buffer". Processed separately using Engine Counters // Stores cycles in a "buffer". Processed separately using Engine Counters
//This is to avoid constant DOM redraws when Corporation is catching up
Player.corporation.storeCycles(numCycles); Player.corporation.storeCycles(numCycles);
} }
@ -782,38 +782,41 @@ const Engine = {
} }
} }
//Counters // Counters
Engine.decrementAllCounters(numCycles); Engine.decrementAllCounters(numCycles);
Engine.checkCounters(); Engine.checkCounters();
//Manual hacks // Manual hacks
if (Engine._actionInProgress == true) { if (Engine._actionInProgress == true) {
Engine.updateHackProgress(numCycles); Engine.updateHackProgress(numCycles);
} }
//Update the running time of all active scripts // Update the running time of all active scripts
updateOnlineScriptTimes(numCycles); updateOnlineScriptTimes(numCycles);
//Hacknet Nodes // Hacknet Nodes
processHacknetEarnings(numCycles); processHacknetEarnings(numCycles);
}, },
//Counters for the main event loop. Represent the number of game cycles are required /**
//for something to happen. * Counters for the main event loop. Represent the number of game cycles that
* are required for something to happen. These counters are in game cycles,
* which is once every 200ms
*/
Counters: { Counters: {
autoSaveCounter: 300, //Autosave every minute autoSaveCounter: 300,
updateSkillLevelsCounter: 10, //Only update skill levels every 2 seconds. Might improve performance updateSkillLevelsCounter: 10,
updateDisplays: 3, updateDisplays: 3,
updateDisplaysMed: 9, updateDisplaysMed: 9,
updateDisplaysLong: 15, updateDisplaysLong: 15,
updateActiveScriptsDisplay: 5, updateActiveScriptsDisplay: 5,
createProgramNotifications: 10, //Checks whether any programs can be created and notifies createProgramNotifications: 10,
checkFactionInvitations: 100, //Check whether you qualify for any faction invitations checkFactionInvitations: 100,
passiveFactionGrowth: 600, passiveFactionGrowth: 600,
messages: 150, messages: 150,
sCr: 1500, sCr: 1500,
mechanicProcess: 5, //Processes certain mechanics (Corporation, Bladeburner) mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
contractGeneration: 3000 //Generate Coding Contracts contractGeneration: 3000, // Generate Coding Contracts
}, },
decrementAllCounters: function(numCycles = 1) { decrementAllCounters: function(numCycles = 1) {
@ -824,8 +827,10 @@ const Engine = {
} }
}, },
//Checks if any counters are 0 and if they are, executes whatever /**
//is necessary and then resets the counter * Checks if any counters are 0. If they are, executes whatever
* is necessary and then resets the counter
*/
checkCounters: function() { checkCounters: function() {
if (Engine.Counters.autoSaveCounter <= 0) { if (Engine.Counters.autoSaveCounter <= 0) {
if (Settings.AutosaveInterval == null) { if (Settings.AutosaveInterval == null) {
@ -845,7 +850,7 @@ const Engine = {
} }
if (Engine.Counters.updateActiveScriptsDisplay <= 0) { if (Engine.Counters.updateActiveScriptsDisplay <= 0) {
//Always update, but make the interval longer if the page isn't active // Always update, but make the interval longer if the page isn't active
updateActiveScriptsItems(); updateActiveScriptsItems();
if (routing.isOn(Page.ActiveScripts)) { if (routing.isOn(Page.ActiveScripts)) {
Engine.Counters.updateActiveScriptsDisplay = 5; Engine.Counters.updateActiveScriptsDisplay = 5;
@ -925,7 +930,7 @@ const Engine = {
if (Engine.Counters.messages <= 0) { if (Engine.Counters.messages <= 0) {
checkForMessagesToSend(); checkForMessagesToSend();
if (Augmentations[AugmentationNames.TheRedPill].owned) { if (Augmentations[AugmentationNames.TheRedPill].owned) {
Engine.Counters.messages = 4500; //15 minutes for Red pill message Engine.Counters.messages = 4500; // 15 minutes for Red pill message
} else { } else {
Engine.Counters.messages = 150; Engine.Counters.messages = 150;
} }
@ -962,7 +967,8 @@ const Engine = {
} }
}, },
/* Calculates the hack progress for a manual (non-scripted) hack and updates the progress bar/time accordingly */ // Calculates the hack progress for a manual (non-scripted) hack and updates the progress bar/time accordingly
// TODO Refactor this into Terminal module
_totalActionTime: 0, _totalActionTime: 0,
_actionTimeLeft: 0, _actionTimeLeft: 0,
_actionTimeStr: "Time left: ", _actionTimeStr: "Time left: ",
@ -971,34 +977,36 @@ const Engine = {
_actionInProgress: false, _actionInProgress: false,
updateHackProgress: function(numCycles = 1) { updateHackProgress: function(numCycles = 1) {
var timeElapsedMilli = numCycles * Engine._idleSpeed; var timeElapsedMilli = numCycles * Engine._idleSpeed;
Engine._actionTimeLeft -= (timeElapsedMilli/ 1000); //Substract idle speed (ms) Engine._actionTimeLeft -= (timeElapsedMilli/ 1000); // Substract idle speed (ms)
Engine._actionTimeLeft = Math.max(Engine._actionTimeLeft, 0); Engine._actionTimeLeft = Math.max(Engine._actionTimeLeft, 0);
//Calculate percent filled // Calculate percent filled
var percent = Math.round((1 - Engine._actionTimeLeft / Engine._totalActionTime) * 100); var percent = Math.round((1 - Engine._actionTimeLeft / Engine._totalActionTime) * 100);
//Update progress bar // Update progress bar
while (Engine._actionProgressBarCount * 2 <= percent) { while (Engine._actionProgressBarCount * 2 <= percent) {
Engine._actionProgressStr = replaceAt(Engine._actionProgressStr, Engine._actionProgressBarCount, "|"); Engine._actionProgressStr = replaceAt(Engine._actionProgressStr, Engine._actionProgressBarCount, "|");
Engine._actionProgressBarCount += 1; Engine._actionProgressBarCount += 1;
} }
//Update hack time remaining // Update hack time remaining
Engine._actionTimeStr = "Time left: " + Math.max(0, Math.round(Engine._actionTimeLeft)).toString() + "s"; Engine._actionTimeStr = "Time left: " + Math.max(0, Math.round(Engine._actionTimeLeft)).toString() + "s";
document.getElementById("hack-progress").innerHTML = Engine._actionTimeStr; document.getElementById("hack-progress").innerHTML = Engine._actionTimeStr;
//Dynamically update progress bar // Dynamically update progress bar
document.getElementById("hack-progress-bar").innerHTML = Engine._actionProgressStr.replace( / /g, "&nbsp;" ); document.getElementById("hack-progress-bar").innerHTML = Engine._actionProgressStr.replace( / /g, "&nbsp;" );
//Once percent is 100, the hack is completed // Once percent is 100, the hack is completed
if (percent >= 100) { if (percent >= 100) {
Engine._actionInProgress = false; Engine._actionInProgress = false;
Terminal.finishAction(); Terminal.finishAction();
} }
}, },
//Used when initializing a game /**
//elems should be an array of all DOM elements under the header * Collapses a main menu header. Used when initializing the game.
* @param elems {HTMLElement[]} Elements under header
*/
closeMainMenuHeader: function(elems) { closeMainMenuHeader: function(elems) {
for (var i = 0; i < elems.length; ++i) { for (var i = 0; i < elems.length; ++i) {
elems[i].style.maxHeight = null; elems[i].style.maxHeight = null;
@ -1007,8 +1015,10 @@ const Engine = {
} }
}, },
//Used when initializing the game /**
//elems should be an array of all DOM elements under the header * Expands a main menu header. Used when initializing the game.
* @param elems {HTMLElement[]} Elements under header
*/
openMainMenuHeader: function(elems) { openMainMenuHeader: function(elems) {
for (var i = 0; i < elems.length; ++i) { for (var i = 0; i < elems.length; ++i) {
elems[i].style.maxHeight = elems[i].scrollHeight + "px"; elems[i].style.maxHeight = elems[i].scrollHeight + "px";
@ -1016,10 +1026,12 @@ const Engine = {
} }
}, },
//Used in game when clicking on a main menu header (NOT FOR INITIALIZATION) /**
//open is a boolean specifying whether its being opened or closed * Used in game when clicking on a main menu header (NOT used for initialization)
//elems is an array of DOM elements for main menu tabs (li) * @param open {boolean} Whether header is being opened or closed
//links is an array of DOM elements for main menu links (a) * @param elems {HTMLElement[]} li Elements under header
* @param links {HTMLElement[]} a elements under header
*/
toggleMainMenuHeader: function(open, elems, links) { toggleMainMenuHeader: function(open, elems, links) {
for (var i = 0; i < elems.length; ++i) { for (var i = 0; i < elems.length; ++i) {
if (open) { if (open) {
@ -1045,35 +1057,34 @@ const Engine = {
}, },
load: function(saveString) { load: function(saveString) {
//Initialize main menu accordion panels to all start as "open" // Initialize main menu accordion panels to all start as "open"
var terminal = document.getElementById("terminal-tab"); const terminal = document.getElementById("terminal-tab");
var createScript = document.getElementById("create-script-tab"); const createScript = document.getElementById("create-script-tab");
var activeScripts = document.getElementById("active-scripts-tab"); const activeScripts = document.getElementById("active-scripts-tab");
var createProgram = document.getElementById("create-program-tab"); const createProgram = document.getElementById("create-program-tab");
var stats = document.getElementById("stats-tab"); const stats = document.getElementById("stats-tab");
var factions = document.getElementById("factions-tab"); const factions = document.getElementById("factions-tab");
var augmentations = document.getElementById("augmentations-tab"); const augmentations = document.getElementById("augmentations-tab");
var hacknetnodes = document.getElementById("hacknet-nodes-tab"); const hacknetnodes = document.getElementById("hacknet-nodes-tab");
var city = document.getElementById("city-tab"); const city = document.getElementById("city-tab");
var travel = document.getElementById("travel-tab"); const travel = document.getElementById("travel-tab");
var job = document.getElementById("job-tab"); const job = document.getElementById("job-tab");
var stockmarket = document.getElementById("stock-market-tab"); const stockmarket = document.getElementById("stock-market-tab");
var bladeburner = document.getElementById("bladeburner-tab"); const bladeburner = document.getElementById("bladeburner-tab");
var corp = document.getElementById("corporation-tab"); const corp = document.getElementById("corporation-tab");
var gang = document.getElementById("gang-tab"); const gang = document.getElementById("gang-tab");
var tutorial = document.getElementById("tutorial-tab"); const tutorial = document.getElementById("tutorial-tab");
var options = document.getElementById("options-tab"); const options = document.getElementById("options-tab");
var dev = document.getElementById("dev-tab"); const dev = document.getElementById("dev-tab");
//Load game from save or create new game // Load game from save or create new game
if (loadGame(saveString)) { if (loadGame(saveString)) {
console.log("Loaded game from save");
initBitNodes(); initBitNodes();
initBitNodeMultipliers(Player); initBitNodeMultipliers(Player);
initSourceFiles(); initSourceFiles();
Engine.setDisplayElements(); //Sets variables for important DOM elements Engine.setDisplayElements(); // Sets variables for important DOM elements
Engine.init(); //Initialize buttons, work, etc. Engine.init(); // Initialize buttons, work, etc.
initAugmentations(); //Also calls Player.reapplyAllAugmentations() initAugmentations(); // Also calls Player.reapplyAllAugmentations()
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
initStockSymbols(); initStockSymbols();
if (Player.hasWseAccount) { if (Player.hasWseAccount) {
@ -1083,13 +1094,13 @@ const Engine = {
initSingularitySFFlags(); initSingularitySFFlags();
updateSourceFileFlags(Player); updateSourceFileFlags(Player);
//Calculate the number of cycles have elapsed while offline // Calculate the number of cycles have elapsed while offline
Engine._lastUpdate = new Date().getTime(); Engine._lastUpdate = new Date().getTime();
var lastUpdate = Player.lastUpdate; var lastUpdate = Player.lastUpdate;
var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed); var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed);
/* Process offline progress */ // Process offline progress
var offlineProductionFromScripts = loadAllRunningScripts(); //This also takes care of offline production for those scripts var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
if (Player.isWorking) { if (Player.isWorking) {
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds"); console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
if (Player.workType == CONSTANTS.WorkTypeFaction) { if (Player.workType == CONSTANTS.WorkTypeFaction) {
@ -1107,13 +1118,13 @@ const Engine = {
} }
} }
//Hacknet Nodes offline progress // Hacknet Nodes offline progress
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline); var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
const hacknetProdInfo = hasHacknetServers() ? const hacknetProdInfo = hasHacknetServers() ?
`${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` : `${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` :
`${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`; `${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`;
//Passive faction rep gain offline // Passive faction rep gain offline
processPassiveFactionRepGain(numCyclesOffline); processPassiveFactionRepGain(numCyclesOffline);
// Stock Market offline progress // Stock Market offline progress
@ -1150,7 +1161,7 @@ const Engine = {
} }
} }
//Update total playtime // Update total playtime
var time = numCyclesOffline * Engine._idleSpeed; var time = numCyclesOffline * Engine._idleSpeed;
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;} if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;} if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;}
@ -1160,14 +1171,14 @@ const Engine = {
Player.playtimeSinceLastBitnode += time; Player.playtimeSinceLastBitnode += time;
Player.lastUpdate = Engine._lastUpdate; Player.lastUpdate = Engine._lastUpdate;
Engine.start(); //Run main game loop and Scripts loop Engine.start(); // Run main game loop and Scripts loop
removeLoadingScreen(); removeLoadingScreen();
const timeOfflineString = convertTimeMsToTimeElapsedString(time); const timeOfflineString = convertTimeMsToTimeElapsedString(time);
dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` + dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` +
"generated <span class='money-gold'>" + "generated <span class='money-gold'>" +
numeralWrapper.formatMoney(offlineProductionFromScripts) + "</span> " + numeralWrapper.formatMoney(offlineProductionFromScripts) + "</span> " +
"and your Hacknet Nodes generated <span class='money-gold'>" + hacknetProdInfo + "</span>"); "and your Hacknet Nodes generated <span class='money-gold'>" + hacknetProdInfo + "</span>");
//Close main menu accordions for loaded game // Close main menu accordions for loaded game
var visibleMenuTabs = [terminal, createScript, activeScripts, stats, var visibleMenuTabs = [terminal, createScript, activeScripts, stats,
hacknetnodes, city, tutorial, options, dev]; hacknetnodes, city, tutorial, options, dev];
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);} if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
@ -1191,14 +1202,14 @@ const Engine = {
Engine.closeMainMenuHeader(visibleMenuTabs); Engine.closeMainMenuHeader(visibleMenuTabs);
} else { } else {
//No save found, start new game // No save found, start new game
console.log("Initializing new game"); console.log("Initializing new game");
initBitNodes(); initBitNodes();
initBitNodeMultipliers(Player); initBitNodeMultipliers(Player);
initSourceFiles(); initSourceFiles();
initSpecialServerIps(); initSpecialServerIps();
Engine.setDisplayElements(); //Sets variables for important DOM elements Engine.setDisplayElements(); // Sets variables for important DOM elements
Engine.start(); //Run main game loop and Scripts loop Engine.start(); // Run main game loop and Scripts loop
Player.init(); Player.init();
initForeignServers(Player.getHomeComputer()); initForeignServers(Player.getHomeComputer());
initCompanies(); initCompanies();
@ -1209,18 +1220,17 @@ const Engine = {
initLiterature(); initLiterature();
initSingularitySFFlags(); initSingularitySFFlags();
//Open main menu accordions for new game // Open main menu accordions for new game
//Main menu accordions const hackingHdr = document.getElementById("hacking-menu-header");
var hackingHdr = document.getElementById("hacking-menu-header");
hackingHdr.classList.toggle("opened"); hackingHdr.classList.toggle("opened");
var characterHdr = document.getElementById("character-menu-header"); const characterHdr = document.getElementById("character-menu-header");
characterHdr.classList.toggle("opened"); characterHdr.classList.toggle("opened");
var worldHdr = document.getElementById("world-menu-header"); const worldHdr = document.getElementById("world-menu-header");
worldHdr.classList.toggle("opened"); worldHdr.classList.toggle("opened");
var helpHdr = document.getElementById("help-menu-header"); const helpHdr = document.getElementById("help-menu-header");
helpHdr.classList.toggle("opened"); helpHdr.classList.toggle("opened");
//Hide tabs that wont be revealed until later // Hide tabs that wont be revealed until later
factions.style.display = "none"; factions.style.display = "none";
augmentations.style.display = "none"; augmentations.style.display = "none";
job.style.display = "none"; job.style.display = "none";
@ -1238,18 +1248,18 @@ const Engine = {
tutorial, options] tutorial, options]
); );
//Start interactive tutorial // Start interactive tutorial
iTutorialStart(); iTutorialStart();
removeLoadingScreen(); removeLoadingScreen();
} }
//Initialize labels on game settings // Initialize labels on game settings
setSettingsLabels(); setSettingsLabels();
scriptEditorInit(); scriptEditorInit();
Terminal.resetTerminalInput(); Terminal.resetTerminalInput();
}, },
setDisplayElements: function() { setDisplayElements: function() {
//Content elements // Content elements
Engine.Display.terminalContent = document.getElementById("terminal-container"); Engine.Display.terminalContent = document.getElementById("terminal-container");
routing.navigateTo(Page.Terminal); routing.navigateTo(Page.Terminal);
@ -1294,22 +1304,22 @@ const Engine = {
Engine.Display.missionContent = document.getElementById("mission-container"); Engine.Display.missionContent = document.getElementById("mission-container");
Engine.Display.missionContent.style.display = "none"; Engine.Display.missionContent.style.display = "none";
//Character info // Character info
Engine.Display.characterInfo = document.getElementById("character-content"); Engine.Display.characterInfo = document.getElementById("character-content");
//Location page (page that shows up when you visit a specific location in World) // Location page (page that shows up when you visit a specific location in World)
Engine.Display.locationContent = document.getElementById("location-container"); Engine.Display.locationContent = document.getElementById("location-container");
Engine.Display.locationContent.style.display = "none"; Engine.Display.locationContent.style.display = "none";
//Work In Progress // Work In Progress
Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container"); Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container");
Engine.Display.workInProgressContent.style.display = "none"; Engine.Display.workInProgressContent.style.display = "none";
//Red Pill / Hack World Daemon // Red Pill / Hack World Daemon
Engine.Display.redPillContent = document.getElementById("red-pill-container"); Engine.Display.redPillContent = document.getElementById("red-pill-container");
Engine.Display.redPillContent.style.display = "none"; Engine.Display.redPillContent.style.display = "none";
//Cinematic Text // Cinematic Text
Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container"); Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container");
Engine.Display.cinematicTextContent.style.display = "none"; Engine.Display.cinematicTextContent.style.display = "none";
@ -1323,9 +1333,9 @@ const Engine = {
} }
}, },
/* Initialization */ // Initialization
init: function() { init: function() {
//Import game link // Import game link
document.getElementById("import-game-link").onclick = function() { document.getElementById("import-game-link").onclick = function() {
saveObject.importGame(); saveObject.importGame();
}; };
@ -1434,10 +1444,10 @@ const Engine = {
return false; return false;
}); });
//Active scripts list // Active scripts list
Engine.ActiveScriptsList = document.getElementById("active-scripts-list"); Engine.ActiveScriptsList = document.getElementById("active-scripts-list");
//Save, Delete, Import/Export buttons // Save, Delete, Import/Export buttons
Engine.Clickables.saveMainMenuButton = document.getElementById("save-game-link"); Engine.Clickables.saveMainMenuButton = document.getElementById("save-game-link");
Engine.Clickables.saveMainMenuButton.addEventListener("click", function() { Engine.Clickables.saveMainMenuButton.addEventListener("click", function() {
saveObject.saveGame(indexedDb); saveObject.saveGame(indexedDb);
@ -1455,7 +1465,7 @@ const Engine = {
return false; return false;
}); });
//Character Overview buttons // Character Overview buttons
document.getElementById("character-overview-save-button").addEventListener("click", function() { document.getElementById("character-overview-save-button").addEventListener("click", function() {
saveObject.saveGame(indexedDb); saveObject.saveGame(indexedDb);
return false; return false;
@ -1466,13 +1476,13 @@ const Engine = {
return false; return false;
}); });
//Create Program buttons // Create Program buttons
initCreateProgramButtons(); initCreateProgramButtons();
//Message at the top of terminal // Message at the top of terminal
postNetburnerText(); postNetburnerText();
//Player was working cancel button // Player was working cancel button
if (Player.isWorking) { if (Player.isWorking) {
var cancelButton = document.getElementById("work-in-progress-cancel-button"); var cancelButton = document.getElementById("work-in-progress-cancel-button");
cancelButton.addEventListener("click", function() { cancelButton.addEventListener("click", function() {
@ -1494,10 +1504,10 @@ const Engine = {
Engine.loadWorkInProgressContent(); Engine.loadWorkInProgressContent();
} }
//character overview screen // Character overview screen
document.getElementById("character-overview-container").style.display = "block"; document.getElementById("character-overview-container").style.display = "block";
//Remove classes from links (they might be set from tutorial) // Remove classes from links (they might be set from tutorial)
document.getElementById("terminal-menu-link").removeAttribute("class"); document.getElementById("terminal-menu-link").removeAttribute("class");
document.getElementById("stats-menu-link").removeAttribute("class"); document.getElementById("stats-menu-link").removeAttribute("class");
document.getElementById("create-script-menu-link").removeAttribute("class"); document.getElementById("create-script-menu-link").removeAttribute("class");
@ -1543,7 +1553,7 @@ const Engine = {
} }
}); });
//DEBUG Delete active Scripts on home // DEBUG Delete active Scripts on home
document.getElementById("debug-delete-scripts-link").addEventListener("click", function() { document.getElementById("debug-delete-scripts-link").addEventListener("click", function() {
console.log("Deleting running scripts on home computer"); console.log("Deleting running scripts on home computer");
Player.getHomeComputer().runningScripts = []; Player.getHomeComputer().runningScripts = [];
@ -1552,7 +1562,7 @@ const Engine = {
return false; return false;
}); });
//DEBUG Soft Reset // DEBUG Soft Reset
document.getElementById("debug-soft-reset").addEventListener("click", function() { document.getElementById("debug-soft-reset").addEventListener("click", function() {
dialogBoxCreate("Soft Reset!"); dialogBoxCreate("Soft Reset!");
prestigeAugmentation(); prestigeAugmentation();
@ -1562,10 +1572,10 @@ const Engine = {
}, },
start: function() { start: function() {
//Run main loop // Run main loop
Engine.idleTimer(); Engine.idleTimer();
//Scripts // Script-processing loop
runScriptsLoop(); runScriptsLoop();
} }
}; };
@ -1573,18 +1583,20 @@ const Engine = {
var indexedDb, indexedDbRequest; var indexedDb, indexedDbRequest;
window.onload = function() { window.onload = function() {
if (!window.indexedDB) { if (!window.indexedDB) {
return Engine.load(null); //Will try to load from localstorage return Engine.load(null); // Will try to load from localstorage
} }
//DB is called bitburnerSave /**
//Object store is called savestring * DB is called bitburnerSave
//key for the Object store is called save * Object store is called savestring
* key for the Object store is called save
*/
indexedDbRequest = window.indexedDB.open("bitburnerSave", 1); indexedDbRequest = window.indexedDB.open("bitburnerSave", 1);
indexedDbRequest.onerror = function(e) { indexedDbRequest.onerror = function(e) {
console.log("Error opening indexedDB: "); console.log("Error opening indexedDB: ");
console.log(e); console.log(e);
return Engine.load(null); //Try to load from localstorage return Engine.load(null); // Try to load from localstorage
}; };
indexedDbRequest.onsuccess = function(e) { indexedDbRequest.onsuccess = function(e) {
@ -1595,11 +1607,11 @@ window.onload = function() {
var request = objectStore.get("save"); var request = objectStore.get("save");
request.onerror = function(e) { request.onerror = function(e) {
console.log("Error in Database request to get savestring: " + e); console.log("Error in Database request to get savestring: " + e);
return Engine.load(null); //Try to load from localstorage return Engine.load(null); // Try to load from localstorage
} }
request.onsuccess = function(e) { request.onsuccess = function(e) {
Engine.load(request.result); //Is this right? Engine.load(request.result);
} }
}; };