mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 14:28:36 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7417fb6ef8 | ||
|
|
98a04e4932 | ||
|
|
8d33c5b571 | ||
|
|
221b81d802 | ||
|
|
df89cc5002 | ||
|
|
3b6b37f8a6 | ||
|
|
cf2acb8844 |
@@ -75,7 +75,7 @@
|
||||
margin: 4px;
|
||||
padding: 2px;
|
||||
resize: none;
|
||||
width: 50%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
#script-editor-status {
|
||||
|
||||
2
dist/engine.bundle.js
vendored
2
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/engine.css
vendored
2
dist/engine.css
vendored
@@ -893,7 +893,7 @@ button {
|
||||
margin: 4px;
|
||||
padding: 2px;
|
||||
resize: none;
|
||||
width: 50%; }
|
||||
width: 60%; }
|
||||
|
||||
#script-editor-status {
|
||||
float: left;
|
||||
|
||||
114
dist/vendor.bundle.js
vendored
114
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -3,6 +3,31 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.46.2 - 4/14/2019
|
||||
-------------------
|
||||
* Source-File 2 now allows you to form gangs in other BitNodes when your karma reaches a very large negative value
|
||||
** (Karma is a hidden stat and is lowered by committing crimes)
|
||||
* Gang changes:
|
||||
** Bug Fix: Gangs can no longer clash with themselve
|
||||
** Bug Fix: Winning against another gang should properly reduce their power
|
||||
|
||||
* Bug Fix: Terminal 'wget' command now works properly
|
||||
* Bug Fix: Hacknet Server Hash upgrades now properly reset upon installing Augs/switching BitNodes
|
||||
* Bug Fix: Fixed button for creating Corporations
|
||||
|
||||
v0.46.1 - 4/12/2019
|
||||
-------------------
|
||||
* Added a very rudimentary directory system to the Terminal
|
||||
* Details here: https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#filesystem-directories
|
||||
|
||||
* Added numHashes(), hashCost(), and spendHashes() functions to the Netscript Hacknet Node API
|
||||
* 'Generate Coding Contract' hash upgrade is now more expensive
|
||||
* 'Generate Coding Contract' hash upgrade now generates the contract randomly on the server, rather than on home computer
|
||||
* The cost of selling hashes for money no longer increases each time
|
||||
* Selling hashes for money now costs 4 hashes (in exchange for $1m)
|
||||
* Bug Fix: Hacknet Node earnings should work properly when game is inactive/offline
|
||||
* Bug Fix: Duplicate Sleeve augmentations are now properly reset when switching to a new BitNode
|
||||
|
||||
v0.46.0 - 4/3/2019
|
||||
------------------
|
||||
* Added BitNode-9: Hacktocracy
|
||||
|
||||
@@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# The short X.Y version.
|
||||
version = '0.46'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.46.0'
|
||||
release = '0.46.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -8,6 +8,7 @@ recruitMember() Netscript Function
|
||||
Attempt to recruit a new gang member.
|
||||
|
||||
Possible reasons for failure:
|
||||
|
||||
* Cannot currently recruit a new member
|
||||
* There already exists a member with the specified name
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ hashCost() Netscript Function
|
||||
|
||||
.. warning:: This page contains spoilers for the game
|
||||
|
||||
.. js:function:: hashCost(upgName, upgTarget)
|
||||
.. js:function:: hashCost(upgName)
|
||||
|
||||
:param string upgName: Name of upgrade to get the cost of. Must be an exact match
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
<div id="script-editor-filename-wrapper">
|
||||
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
|
||||
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/>
|
||||
<input id="script-editor-filename" type="text" maxlength="100" tabindex="1"/>
|
||||
</div>
|
||||
|
||||
<div id="ace-editor"></div>
|
||||
@@ -221,8 +221,6 @@
|
||||
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
||||
<div id="faction-container" class="generic-menupage-container"></div>
|
||||
|
||||
<div id="faction-augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
<!-- Augmentations -->
|
||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
|
||||
@@ -114,5 +114,5 @@
|
||||
"watch": "webpack --watch --mode production",
|
||||
"watch:dev": "webpack --watch --mode development"
|
||||
},
|
||||
"version": "0.45.0"
|
||||
"version": "0.46.2"
|
||||
}
|
||||
|
||||
@@ -1,35 +1,38 @@
|
||||
import {workerScripts,
|
||||
killWorkerScript} from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { getServer } from "./Server/ServerHelpers";
|
||||
import {numeralWrapper} from "./ui/numeralFormat";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement";
|
||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||
import {createElement} from "../utils/uiHelpers/createElement";
|
||||
import {createProgressBarText} from "../utils/helpers/createProgressBarText";
|
||||
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
|
||||
import {getElementById} from "../utils/uiHelpers/getElementById";
|
||||
import {logBoxCreate} from "../utils/LogBox";
|
||||
import {formatNumber,
|
||||
convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import {removeElement} from "../utils/uiHelpers/removeElement";
|
||||
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
||||
import {Page, routing} from "./ui/navigationTracking";
|
||||
// TODO - Convert this to React
|
||||
import { workerScripts, killWorkerScript } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { getServer } from "./Server/ServerHelpers";
|
||||
|
||||
/* {
|
||||
* serverName: {
|
||||
* header: Server Header Element
|
||||
* panel: Server Panel List (ul) element
|
||||
* scripts: {
|
||||
* script id: Ref to Script information
|
||||
* }
|
||||
* }
|
||||
* ...
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { logBoxCreate } from "../utils/LogBox";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { createProgressBarText } from "../utils/helpers/createProgressBarText";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { getElementById } from "../utils/uiHelpers/getElementById";
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { removeElement } from "../utils/uiHelpers/removeElement";
|
||||
|
||||
|
||||
/**
|
||||
* {
|
||||
* serverName: {
|
||||
* header: Server Header Element
|
||||
* panel: Server Panel List (ul) element
|
||||
* scripts: {
|
||||
* script id: Ref to Script information
|
||||
* }
|
||||
* }
|
||||
* ...
|
||||
*/
|
||||
let ActiveScriptsUI = {};
|
||||
let ActiveScriptsTasks = []; //Sequentially schedule the creation/deletion of UI elements
|
||||
const ActiveScriptsUI = {};
|
||||
const ActiveScriptsTasks = []; // Sequentially schedule the creation/deletion of UI elements
|
||||
|
||||
const getHeaderHtml = (server) => {
|
||||
// TODO: calculate the longest hostname length rather than hard coding it
|
||||
@@ -48,7 +51,7 @@ const updateHeaderHtml = (server) => {
|
||||
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);
|
||||
if (accordion.header.dataset.ramPercentage !== ramPercentage) {
|
||||
accordion.header.dataset.ramPercentage = ramPercentage;
|
||||
@@ -81,16 +84,18 @@ function createActiveScriptsServerPanel(server) {
|
||||
header: hdr,
|
||||
panel: panel,
|
||||
panelList: panelScriptList,
|
||||
scripts: {}, //Holds references to li 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
|
||||
scripts: {}, // Holds references to li 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
|
||||
};
|
||||
|
||||
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) {
|
||||
let hostname = server.hostname;
|
||||
if (ActiveScriptsUI[hostname] == null) {
|
||||
@@ -98,9 +103,9 @@ function deleteActiveScriptsServerPanel(server) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Make sure it's empty
|
||||
// Make sure it's empty
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -112,7 +117,7 @@ function deleteActiveScriptsServerPanel(server) {
|
||||
function addActiveScriptsItem(workerscript) {
|
||||
var server = getServer(workerscript.serverIp);
|
||||
if (server == null) {
|
||||
console.log("ERROR: Invalid server IP for workerscript in addActiveScriptsItem()");
|
||||
console.warn("Invalid server IP for workerscript in addActiveScriptsItem()");
|
||||
return;
|
||||
}
|
||||
let hostname = server.hostname;
|
||||
@@ -122,7 +127,7 @@ function addActiveScriptsItem(workerscript) {
|
||||
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];
|
||||
for (var i = 0; i < workerscript.args.length; ++i) {
|
||||
itemNameArray.push(String(workerscript.args[i]));
|
||||
@@ -139,8 +144,10 @@ function addActiveScriptsItem(workerscript) {
|
||||
panel.classList.remove("accordion-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", {
|
||||
innerHTML: "Threads: " + workerscript.scriptRef.threads + "<br>" +
|
||||
"Args: " + arrayToString(workerscript.args)
|
||||
@@ -173,7 +180,7 @@ function addActiveScriptsItem(workerscript) {
|
||||
}
|
||||
}));
|
||||
|
||||
//Append element to list
|
||||
// Append element to list
|
||||
ActiveScriptsUI[hostname]["panelList"].appendChild(li);
|
||||
ActiveScriptsUI[hostname].scripts[itemName] = li;
|
||||
ActiveScriptsUI[hostname].scriptHdrs[itemName] = hdr;
|
||||
@@ -218,11 +225,13 @@ function deleteActiveScriptsItem(workerscript) {
|
||||
}.bind(null, workerscript));
|
||||
}
|
||||
|
||||
//Update the ActiveScriptsItems array
|
||||
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...
|
||||
let numTasks = Math.min(maxTasks, ActiveScriptsTasks.length);
|
||||
/**
|
||||
* Run tasks that need to be done sequentially (adding items, creating/deleting server panels)
|
||||
* 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) {
|
||||
let task = ActiveScriptsTasks.shift();
|
||||
try {
|
||||
@@ -233,8 +242,8 @@ function updateActiveScriptsItems(maxTasks=150) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!routing.isOn(Page.ActiveScripts)) {return;}
|
||||
var total = 0;
|
||||
if (!routing.isOn(Page.ActiveScripts)) { return; }
|
||||
let total = 0;
|
||||
for (var i = 0; i < workerScripts.length; ++i) {
|
||||
try {
|
||||
total += updateActiveScriptsItemContent(workerScripts[i]);
|
||||
@@ -246,10 +255,10 @@ function updateActiveScriptsItems(maxTasks=150) {
|
||||
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-avg").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
//Updates the content of the given item in the Active Scripts list
|
||||
function updateActiveScriptsItemContent(workerscript) {
|
||||
var server = getServer(workerscript.serverIp);
|
||||
if (server == null) {
|
||||
@@ -258,7 +267,7 @@ function updateActiveScriptsItemContent(workerscript) {
|
||||
}
|
||||
let hostname = server.hostname;
|
||||
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);
|
||||
@@ -270,11 +279,11 @@ function updateActiveScriptsItemContent(workerscript) {
|
||||
var itemName = itemNameArray.join("-");
|
||||
|
||||
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];
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
@@ -293,7 +302,7 @@ function updateActiveScriptsText(workerscript, item, itemName) {
|
||||
updateHeaderHtml(server);
|
||||
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].scriptHdrs[itemName].classList.contains("active") === false) {return onlineMps;}
|
||||
|
||||
@@ -302,7 +311,7 @@ function updateActiveScriptsText(workerscript, item, itemName) {
|
||||
var onlineTime = "Online Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.onlineRunningTime * 1e3);
|
||||
var offlineTime = "Offline Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.offlineRunningTime * 1e3);
|
||||
|
||||
//Online
|
||||
// Online
|
||||
var onlineTotalMoneyMade = "Total online production: " + numeralWrapper.formatMoney(workerscript.scriptRef.onlineMoneyMade);
|
||||
var onlineTotalExpEarned = (Array(26).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.onlineExpGained) + " hacking exp").replace( / /g, " ");
|
||||
|
||||
@@ -310,7 +319,7 @@ function updateActiveScriptsText(workerscript, item, itemName) {
|
||||
var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime;
|
||||
var onlineEpsText = (Array(25).join(" ") + numeralWrapper.formatBigNumber(onlineEps) + " hacking exp / second").replace( / /g, " ");
|
||||
|
||||
//Offline
|
||||
// Offline
|
||||
var offlineTotalMoneyMade = "Total offline production: " + numeralWrapper.formatMoney(workerscript.scriptRef.offlineMoneyMade);
|
||||
var offlineTotalExpEarned = (Array(27).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.offlineExpGained) + " hacking exp").replace( / /g, " ");
|
||||
|
||||
|
||||
14
src/Alias.ts
14
src/Alias.ts
@@ -1,5 +1,5 @@
|
||||
import { IMap } from "./types";
|
||||
import { post } from "./ui/postToTerminal";
|
||||
import { IMap } from "./types";
|
||||
import { post } from "./ui/postToTerminal";
|
||||
|
||||
export let Aliases: IMap<string> = {};
|
||||
export let GlobalAliases: IMap<string> = {};
|
||||
@@ -20,7 +20,7 @@ export function loadGlobalAliases(saveString: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
//Print all aliases to terminal
|
||||
// Prints all aliases to terminal
|
||||
export function printAliases(): void {
|
||||
for (var name in Aliases) {
|
||||
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) {
|
||||
var re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
|
||||
var matches = dec.match(re);
|
||||
@@ -90,8 +90,10 @@ export function removeAlias(name: string): boolean {
|
||||
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 {
|
||||
const commandArray = origCommand.split(" ");
|
||||
if (commandArray.length > 0){
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviv
|
||||
|
||||
interface IConstructorParams {
|
||||
info: string;
|
||||
isSpecial?: boolean;
|
||||
moneyCost: number;
|
||||
name: string;
|
||||
prereqs?: string[];
|
||||
@@ -62,6 +63,9 @@ export class Augmentation {
|
||||
// Description of what this Aug is and what it does
|
||||
info: string = "";
|
||||
|
||||
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
|
||||
isSpecial: boolean = false;
|
||||
|
||||
// Augmentation level - for repeatable Augs like NeuroFlux Governor
|
||||
level: number = 0;
|
||||
|
||||
@@ -90,6 +94,10 @@ export class Augmentation {
|
||||
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
this.startingCost = this.baseCost;
|
||||
|
||||
if (params.isSpecial) {
|
||||
this.isSpecial = true;
|
||||
}
|
||||
|
||||
this.level = 0;
|
||||
|
||||
// Set multipliers
|
||||
|
||||
@@ -1677,19 +1677,6 @@ function initAugmentations() {
|
||||
}
|
||||
AddToAugmentations(SNA);
|
||||
|
||||
//For BitNode-2, add all Augmentations to crime/evil factions.
|
||||
//Do this before adding special Augmentations that become available in later BitNodes
|
||||
if (Player.bitNodeN === 2) {
|
||||
console.log("Adding all augmentations to crime factions for Bit node 2");
|
||||
Factions["Slum Snakes"].addAllAugmentations(Augmentations);
|
||||
Factions["Tetrads"].addAllAugmentations(Augmentations);
|
||||
Factions["The Syndicate"].addAllAugmentations(Augmentations);
|
||||
Factions["The Dark Army"].addAllAugmentations(Augmentations);
|
||||
Factions["Speakers for the Dead"].addAllAugmentations(Augmentations);
|
||||
Factions["NiteSec"].addAllAugmentations(Augmentations);
|
||||
Factions["The Black Hand"].addAllAugmentations(Augmentations);
|
||||
}
|
||||
|
||||
//Special Bladeburner Augmentations
|
||||
var BladeburnersFactionName = "Bladeburners";
|
||||
if (factionExists(BladeburnersFactionName)) {
|
||||
@@ -1708,6 +1695,7 @@ function initAugmentations() {
|
||||
"Increases the player's dexterity by 5%.",
|
||||
bladeburner_success_chance_mult: 1.03,
|
||||
dexterity_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
EsperEyewear.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(EsperEyewear);
|
||||
@@ -1725,6 +1713,7 @@ function initAugmentations() {
|
||||
bladeburner_success_chance_mult: 1.03,
|
||||
bladeburner_analysis_mult: 1.05,
|
||||
bladeburner_stamina_gain_mult: 1.02,
|
||||
isSpecial: true,
|
||||
});
|
||||
EMS4Recombination.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(EMS4Recombination);
|
||||
@@ -1743,6 +1732,7 @@ function initAugmentations() {
|
||||
strength_mult: 1.05,
|
||||
dexterity_mult: 1.05,
|
||||
bladeburner_success_chance_mult: 1.04,
|
||||
isSpecial: true,
|
||||
});
|
||||
OrionShoulder.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(OrionShoulder);
|
||||
@@ -1758,6 +1748,7 @@ function initAugmentations() {
|
||||
"This augmentation:<br>" +
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 6%.",
|
||||
bladeburner_success_chance_mult: 1.06,
|
||||
isSpecial: true,
|
||||
});
|
||||
HyperionV1.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(HyperionV1);
|
||||
@@ -1772,6 +1763,7 @@ function initAugmentations() {
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||
prereqs:[AugmentationNames.HyperionV1],
|
||||
bladeburner_success_chance_mult: 1.08,
|
||||
isSpecial: true,
|
||||
});
|
||||
HyperionV2.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(HyperionV2);
|
||||
@@ -1790,6 +1782,7 @@ function initAugmentations() {
|
||||
dexterity_mult: 1.07,
|
||||
agility_mult: 1.07,
|
||||
bladeburner_stamina_gain_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
GolemSerum.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(GolemSerum);
|
||||
@@ -1805,6 +1798,7 @@ function initAugmentations() {
|
||||
dexterity_exp_mult: 1.1,
|
||||
bladeburner_analysis_mult: 1.1,
|
||||
bladeburner_success_chance_mult: 1.04,
|
||||
isSpecial: true,
|
||||
});
|
||||
VangelisVirus.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(VangelisVirus);
|
||||
@@ -1824,6 +1818,7 @@ function initAugmentations() {
|
||||
dexterity_exp_mult: 1.1,
|
||||
bladeburner_analysis_mult: 1.15,
|
||||
bladeburner_success_chance_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
VangelisVirus3.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(VangelisVirus3);
|
||||
@@ -1842,6 +1837,7 @@ function initAugmentations() {
|
||||
dexterity_exp_mult: 1.05,
|
||||
agility_exp_mult: 1.05,
|
||||
bladeburner_max_stamina_mult: 1.1,
|
||||
isSpecial: true,
|
||||
});
|
||||
INTERLINKED.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(INTERLINKED);
|
||||
@@ -1859,6 +1855,7 @@ function initAugmentations() {
|
||||
agility_mult: 1.05,
|
||||
bladeburner_max_stamina_mult: 1.05,
|
||||
bladeburner_stamina_gain_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeRunner.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeRunner);
|
||||
@@ -1879,6 +1876,7 @@ function initAugmentations() {
|
||||
agility_mult: 1.04,
|
||||
bladeburner_stamina_gain_mult: 1.02,
|
||||
bladeburner_success_chance_mult: 1.03,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmor.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmor);
|
||||
@@ -1895,6 +1893,7 @@ function initAugmentations() {
|
||||
bladeburner_success_chance_mult: 1.05,
|
||||
bladeburner_stamina_gain_mult: 1.02,
|
||||
bladeburner_max_stamina_mult: 1.05,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorPowerCells.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorPowerCells);
|
||||
@@ -1909,6 +1908,7 @@ function initAugmentations() {
|
||||
prereqs:[AugmentationNames.BladeArmor],
|
||||
defense_mult: 1.05,
|
||||
bladeburner_success_chance_mult: 1.06,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorEnergyShielding.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorEnergyShielding);
|
||||
@@ -1922,6 +1922,7 @@ function initAugmentations() {
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||
prereqs:[AugmentationNames.BladeArmor],
|
||||
bladeburner_success_chance_mult: 1.08,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorUnibeam.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorUnibeam);
|
||||
@@ -1936,6 +1937,7 @@ function initAugmentations() {
|
||||
"Increases the player's success chance in Bladeburner contracts/operations by 10%.",
|
||||
prereqs:[AugmentationNames.BladeArmorUnibeam],
|
||||
bladeburner_success_chance_mult: 1.1,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorOmnibeam.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorOmnibeam);
|
||||
@@ -1951,6 +1953,7 @@ function initAugmentations() {
|
||||
prereqs:[AugmentationNames.BladeArmor],
|
||||
bladeburner_analysis_mult: 1.15,
|
||||
bladeburner_success_chance_mult: 1.02,
|
||||
isSpecial: true,
|
||||
});
|
||||
BladeArmorIPU.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladeArmorIPU);
|
||||
@@ -1963,7 +1966,8 @@ function initAugmentations() {
|
||||
"extremely large radius. These specially-modified holograms were specially " +
|
||||
"weaponized by Bladeburner units to be used against Synthoids.<br><br>" +
|
||||
"This augmentation allows you to perform Bladeburner actions and other " +
|
||||
"actions (such as working, commiting crimes, etc.) at the same time."
|
||||
"actions (such as working, commiting crimes, etc.) at the same time.",
|
||||
isSpecial: true,
|
||||
});
|
||||
BladesSimulacrum.addToFactions([BladeburnersFactionName]);
|
||||
resetAugmentation(BladesSimulacrum);
|
||||
|
||||
@@ -57,8 +57,9 @@ export function initBitNodes() {
|
||||
"For every Faction NOT listed above, reputation gains are halved<br>" +
|
||||
"You will no longer gain passive reputation with Factions<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File increases the player's crime success rate, " +
|
||||
"crime money, and charisma multipliers by:<br><br>" +
|
||||
"upgrade its level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes " +
|
||||
"once your karma decreases to a certain value. " +
|
||||
"It also increases the player's crime success rate, crime money, and charisma multipliers by:<br><br>" +
|
||||
"Level 1: 24%<br>" +
|
||||
"Level 2: 36%<br>" +
|
||||
"Level 3: 42%");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,35 @@
|
||||
import {Engine} from "./engine";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import {createElement} from "../utils/uiHelpers/createElement";
|
||||
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
|
||||
import {isString} from "../utils/helpers/isString";
|
||||
import { Engine } from "./engine";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
var cinematicTextFlag = false;
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
|
||||
//Lines must be an array of strings
|
||||
function writeCinematicText(lines) {
|
||||
export let cinematicTextFlag = false;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
cinematicTextFlag = true;
|
||||
|
||||
if (lines.constructor !== Array) {
|
||||
throw new Error("Invalid non-array argument passed into writeCinematicText()");
|
||||
}
|
||||
|
||||
//We'll reuse the 'Red Pill' content
|
||||
// Reuse the 'Red Pill' content
|
||||
Engine.loadCinematicTextContent();
|
||||
var container = document.getElementById("cinematic-text-container");
|
||||
const container = document.getElementById("cinematic-text-container");
|
||||
container.style.width = "75%";
|
||||
if (container == null) {throw new Error("Could not find cinematic-text-container for writeCinematicText()");}
|
||||
removeChildrenFromElement(container);
|
||||
|
||||
for (var i = 0; i < lines.length; ++i) {
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
if (!isString(lines[i])) {
|
||||
throw new Error("Invalid non-string element in 'lines' argument. writeCinematicText() failed");
|
||||
}
|
||||
@@ -45,11 +51,11 @@ function writeCinematicTextRecurse(lines, lineNumber=0) {
|
||||
|
||||
function writeCinematicTextLine(line) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var container = document.getElementById("cinematic-text-container");
|
||||
var pElem = document.createElement("p");
|
||||
const container = document.getElementById("cinematic-text-container");
|
||||
const pElem = document.createElement("p");
|
||||
container.appendChild(pElem);
|
||||
|
||||
var promise = writeCinematicTextLetter(pElem, line, 0);
|
||||
const promise = writeCinematicTextLetter(pElem, line, 0);
|
||||
promise.then(function(res) {
|
||||
resolve(res);
|
||||
}, function(e) {
|
||||
@@ -61,14 +67,15 @@ function writeCinematicTextLine(line) {
|
||||
function writeCinematicTextLetter(pElem, line, i=0) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
setTimeoutRef(function() {
|
||||
const textToShow = line.substring(0, i);
|
||||
|
||||
if (i >= line.length) {
|
||||
var textToShow = line.substring(0, i);
|
||||
pElem.innerHTML = textToShow;
|
||||
return resolve(true);
|
||||
}
|
||||
var textToShow = line.substring(0, i);
|
||||
|
||||
pElem.innerHTML = textToShow + "<span class='typed-cursor'> █ </span>";
|
||||
var promise = writeCinematicTextLetter(pElem, line, i+1);
|
||||
const promise = writeCinematicTextLetter(pElem, line, i+1);
|
||||
promise.then(function(res) {
|
||||
resolve(res);
|
||||
}, function(e) {
|
||||
@@ -96,5 +103,3 @@ function cinematicTextEnd() {
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
export {cinematicTextFlag, writeCinematicText};
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { CodingContract,
|
||||
CodingContractRewardType,
|
||||
CodingContractTypes } from "./CodingContracts";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { Player } from "./Player";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { GetServerByHostname } from "./Server/ServerHelpers";
|
||||
import {
|
||||
CodingContract,
|
||||
CodingContractRewardType,
|
||||
CodingContractTypes
|
||||
} from "./CodingContracts";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { Player } from "./Player";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { GetServerByHostname } from "./Server/ServerHelpers";
|
||||
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
|
||||
export function generateRandomContract() {
|
||||
// First select a random problem type
|
||||
@@ -127,14 +130,15 @@ function getRandomReward() {
|
||||
});
|
||||
|
||||
switch (reward.type) {
|
||||
case CodingContractRewardType.FactionReputation:
|
||||
case CodingContractRewardType.FactionReputation: {
|
||||
// Get a random faction that player is a part of. That
|
||||
// faction must allow hacking contracts
|
||||
var numFactions = factionsThatAllowHacking.length;
|
||||
var randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
|
||||
reward.name = randFaction;
|
||||
break;
|
||||
case CodingContractRewardType.CompanyReputation:
|
||||
}
|
||||
case CodingContractRewardType.CompanyReputation: {
|
||||
const allJobs = Object.keys(Player.jobs);
|
||||
if (allJobs.length > 0) {
|
||||
reward.name = allJobs[getRandomInt(0, allJobs.length - 1)];
|
||||
@@ -142,6 +146,7 @@ function getRandomReward() {
|
||||
reward.type = CodingContractRewardType.Money;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import { codingContractTypesMetadata,
|
||||
DescriptionFunc,
|
||||
GeneratorFunc,
|
||||
SolverFunc } from "./data/codingcontracttypes";
|
||||
import {
|
||||
codingContractTypesMetadata,
|
||||
DescriptionFunc,
|
||||
GeneratorFunc,
|
||||
SolverFunc
|
||||
} from "./data/codingcontracttypes";
|
||||
|
||||
import { IMap } from "./types";
|
||||
import { IMap } from "./types";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||
import {
|
||||
Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver
|
||||
} from "../utils/JSONReviver";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
@@ -13,6 +19,7 @@ import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
|
||||
|
||||
|
||||
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
||||
|
||||
/* Represents different types of problems that a Coding Contract can have */
|
||||
|
||||
208
src/Constants.ts
208
src/Constants.ts
@@ -3,98 +3,98 @@
|
||||
*
|
||||
* Constants for specific mechanics or features will NOT be here.
|
||||
*/
|
||||
import {IMap} from "./types";
|
||||
import { IMap } from "./types";
|
||||
|
||||
export let CONSTANTS: IMap<any> = {
|
||||
Version: "0.46.1",
|
||||
Version: "0.46.2",
|
||||
|
||||
//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
|
||||
//the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
|
||||
/** 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
|
||||
* the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
|
||||
*/
|
||||
MaxSkillLevel: 975,
|
||||
|
||||
//Milliseconds per game cycle
|
||||
// Milliseconds per game cycle
|
||||
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,
|
||||
|
||||
/* Base costs */
|
||||
// Base RAM costs
|
||||
BaseCostFor1GBOfRamHome: 32000,
|
||||
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
|
||||
|
||||
// Cost to travel to another city
|
||||
TravelCost: 200e3,
|
||||
|
||||
/* Faction and Company favor */
|
||||
BaseFavorToDonate: 150,
|
||||
DonateMoneyToRepDivisor: 1e6,
|
||||
// Faction and Company favor-related things
|
||||
BaseFavorToDonate: 150,
|
||||
DonateMoneyToRepDivisor: 1e6,
|
||||
FactionReputationToFavorBase: 500,
|
||||
FactionReputationToFavorMult: 1.02,
|
||||
CompanyReputationToFavorBase: 500,
|
||||
CompanyReputationToFavorMult: 1.02,
|
||||
|
||||
/* Augmentation */
|
||||
//NeuroFlux Governor cost multiplier as you level up
|
||||
// NeuroFlux Governor Augmentation cost multiplier
|
||||
NeuroFluxGovernorLevelMult: 1.14,
|
||||
|
||||
/* Netscript Constants */
|
||||
//RAM Costs for different commands
|
||||
ScriptBaseRamCost: 1.6,
|
||||
ScriptDomRamCost: 25,
|
||||
ScriptWhileRamCost: 0,
|
||||
ScriptForRamCost: 0,
|
||||
ScriptIfRamCost: 0,
|
||||
ScriptHackRamCost: 0.1,
|
||||
ScriptHackAnalyzeRamCost: 1,
|
||||
ScriptGrowRamCost: 0.15,
|
||||
ScriptGrowthAnalyzeRamCost: 1,
|
||||
ScriptWeakenRamCost: 0.15,
|
||||
ScriptScanRamCost: 0.2,
|
||||
ScriptPortProgramRamCost: 0.05,
|
||||
ScriptRunRamCost: 1.0,
|
||||
ScriptExecRamCost: 1.3,
|
||||
ScriptSpawnRamCost: 2.0,
|
||||
ScriptScpRamCost: 0.6,
|
||||
ScriptKillRamCost: 0.5, //Kill and killall
|
||||
ScriptHasRootAccessRamCost: 0.05,
|
||||
ScriptGetHostnameRamCost: 0.05, //getHostname() and getIp()
|
||||
ScriptGetHackingLevelRamCost: 0.05, //getHackingLevel()
|
||||
ScriptGetMultipliersRamCost: 4.0, //getHackingMultipliers() and getBitNodeMultipliers()
|
||||
ScriptGetServerRamCost: 0.1,
|
||||
ScriptFileExistsRamCost: 0.1,
|
||||
ScriptIsRunningRamCost: 0.1,
|
||||
ScriptHacknetNodesRamCost: 4.0, //Base cost for accessing Hacknet Node API
|
||||
ScriptHNUpgLevelRamCost: 0.4,
|
||||
ScriptHNUpgRamRamCost: 0.6,
|
||||
ScriptHNUpgCoreRamCost: 0.8,
|
||||
ScriptGetStockRamCost: 2.0,
|
||||
ScriptBuySellStockRamCost: 2.5,
|
||||
// RAM Costs for Netscript functions
|
||||
ScriptBaseRamCost: 1.6,
|
||||
ScriptDomRamCost: 25,
|
||||
ScriptWhileRamCost: 0,
|
||||
ScriptForRamCost: 0,
|
||||
ScriptIfRamCost: 0,
|
||||
ScriptHackRamCost: 0.1,
|
||||
ScriptHackAnalyzeRamCost: 1,
|
||||
ScriptGrowRamCost: 0.15,
|
||||
ScriptGrowthAnalyzeRamCost: 1,
|
||||
ScriptWeakenRamCost: 0.15,
|
||||
ScriptScanRamCost: 0.2,
|
||||
ScriptPortProgramRamCost: 0.05,
|
||||
ScriptRunRamCost: 1.0,
|
||||
ScriptExecRamCost: 1.3,
|
||||
ScriptSpawnRamCost: 2.0,
|
||||
ScriptScpRamCost: 0.6,
|
||||
ScriptKillRamCost: 0.5,
|
||||
ScriptHasRootAccessRamCost: 0.05,
|
||||
ScriptGetHostnameRamCost: 0.05,
|
||||
ScriptGetHackingLevelRamCost: 0.05,
|
||||
ScriptGetMultipliersRamCost: 4.0,
|
||||
ScriptGetServerRamCost: 0.1,
|
||||
ScriptFileExistsRamCost: 0.1,
|
||||
ScriptIsRunningRamCost: 0.1,
|
||||
ScriptHacknetNodesRamCost: 4.0,
|
||||
ScriptHNUpgLevelRamCost: 0.4,
|
||||
ScriptHNUpgRamRamCost: 0.6,
|
||||
ScriptHNUpgCoreRamCost: 0.8,
|
||||
ScriptGetStockRamCost: 2.0,
|
||||
ScriptBuySellStockRamCost: 2.5,
|
||||
ScriptGetPurchaseServerRamCost: 0.25,
|
||||
ScriptPurchaseServerRamCost: 2.25,
|
||||
ScriptGetPurchasedServerLimit: 0.05,
|
||||
ScriptPurchaseServerRamCost: 2.25,
|
||||
ScriptGetPurchasedServerLimit: 0.05,
|
||||
ScriptGetPurchasedServerMaxRam: 0.05,
|
||||
ScriptRoundRamCost: 0.05,
|
||||
ScriptReadWriteRamCost: 1.0,
|
||||
ScriptArbScriptRamCost: 1.0, // Functions that apply to all scripts regardless of args
|
||||
ScriptGetScriptRamCost: 0.1,
|
||||
ScriptGetHackTimeRamCost: 0.05,
|
||||
ScriptGetFavorToDonate: 0.10,
|
||||
ScriptCodingContractBaseRamCost:10,
|
||||
ScriptSleeveBaseRamCost: 4,
|
||||
ScriptRoundRamCost: 0.05,
|
||||
ScriptReadWriteRamCost: 1.0,
|
||||
ScriptArbScriptRamCost: 1.0,
|
||||
ScriptGetScriptRamCost: 0.1,
|
||||
ScriptGetHackTimeRamCost: 0.05,
|
||||
ScriptGetFavorToDonate: 0.10,
|
||||
ScriptCodingContractBaseRamCost: 10,
|
||||
ScriptSleeveBaseRamCost: 4,
|
||||
|
||||
ScriptSingularityFn1RamCost: 1,
|
||||
ScriptSingularityFn2RamCost: 2,
|
||||
ScriptSingularityFn3RamCost: 3,
|
||||
ScriptSingularityFn1RamCost: 1,
|
||||
ScriptSingularityFn2RamCost: 2,
|
||||
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
|
||||
ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate
|
||||
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
|
||||
|
||||
PurchasedServerLimit: 25,
|
||||
PurchasedServerMaxRam: 1048576, //2^20
|
||||
PurchasedServerMaxRam: 1048576, // 2^20
|
||||
|
||||
//Augmentation Constants
|
||||
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
|
||||
MultipleAugMultiplier: 1.9,
|
||||
// Augmentation Constants
|
||||
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
|
||||
MultipleAugMultiplier: 1.9,
|
||||
|
||||
//How much a TOR router costs
|
||||
TorRouterCost: 200000,
|
||||
// TOR Router
|
||||
TorRouterCost: 200e3,
|
||||
|
||||
//Infiltration constants
|
||||
// Infiltration
|
||||
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
|
||||
InfiltrationExpPow: 0.8,
|
||||
|
||||
//Stock market constants
|
||||
WSEAccountCost: 200e6,
|
||||
TIXAPICost: 5e9,
|
||||
MarketData4SCost: 1e9,
|
||||
// Stock market
|
||||
WSEAccountCost: 200e6,
|
||||
TIXAPICost: 5e9,
|
||||
MarketData4SCost: 1e9,
|
||||
MarketDataTixApi4SCost: 25e9,
|
||||
StockMarketCommission: 100e3,
|
||||
StockMarketCommission: 100e3,
|
||||
|
||||
//Hospital/Health
|
||||
// Hospital/Health
|
||||
HospitalCostPerHp: 100e3,
|
||||
|
||||
//Intelligence-related constants
|
||||
IntelligenceCrimeWeight: 0.05, //Weight for how much int affects crime success rates
|
||||
IntelligenceInfiltrationWeight: 0.1, //Weight for how much int affects infiltration success rates
|
||||
// Intelligence-related constants
|
||||
IntelligenceCrimeWeight: 0.05, // Weight for how much int affects crime success rates
|
||||
IntelligenceInfiltrationWeight: 0.1, // Weight for how much int affects infiltration success rates
|
||||
IntelligenceCrimeBaseExpGain: 0.001,
|
||||
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
|
||||
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
|
||||
IntelligenceSingFnBaseExpGain: 0.002,
|
||||
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
|
||||
HackingMissionRepToDiffConversion: 10000, //Faction rep is divided by this to get mission difficulty
|
||||
HackingMissionRepToRewardConversion: 7, //Faction rep divided byt his to get mission rep reward
|
||||
HackingMissionSpamTimeIncrease: 25000, //How much time limit increase is gained when conquering a Spam Node (ms)
|
||||
HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
|
||||
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)
|
||||
// Hacking Missions
|
||||
// TODO Move this into Hacking Mission implementation
|
||||
HackingMissionRepToDiffConversion: 10000, // Faction rep is divided by this to get mission difficulty
|
||||
HackingMissionRepToRewardConversion: 7, // Faction rep divided byt his to get mission rep reward
|
||||
HackingMissionSpamTimeIncrease: 25000, // How much time limit increase is gained when conquering a Spam Node (ms)
|
||||
HackingMissionTransferAttackIncrease: 1.05, // Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
|
||||
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>" +
|
||||
"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 " +
|
||||
@@ -192,7 +193,7 @@ export let CONSTANTS: IMap<any> = {
|
||||
"-Miscellaneous Nodes slowly raise their defense over time<br><br>" +
|
||||
"-Nodes slowly regenerate health over time.",
|
||||
|
||||
/* Time Constants */
|
||||
// Time-related constants
|
||||
MillisecondsPer20Hours: 72000000,
|
||||
GameCyclesPer20Hours: 72000000 / 200,
|
||||
|
||||
@@ -220,7 +221,7 @@ export let CONSTANTS: IMap<any> = {
|
||||
MillisecondsPerFiveMinutes: 300000,
|
||||
GameCyclesPerFiveMinutes: 300000 / 200,
|
||||
|
||||
/* Player Work / Action related Constants */
|
||||
// Player Work & Action
|
||||
FactionWorkHacking: "Faction Hacking Work",
|
||||
FactionWorkField: "Faction Field Work",
|
||||
FactionWorkSecurity: "Faction Security Work",
|
||||
@@ -263,20 +264,31 @@ export let CONSTANTS: IMap<any> = {
|
||||
CrimeAssassination: "assassinate a high-profile target",
|
||||
CrimeHeist: "pull off the ultimate heist",
|
||||
|
||||
/* Coding Contract Constants */
|
||||
CodingContractBaseFactionRepGain: 2500,
|
||||
CodingContractBaseCompanyRepGain: 4000,
|
||||
CodingContractBaseMoneyGain: 75e6,
|
||||
// Coding Contract
|
||||
// TODO Move this into Coding contract impelmentation?
|
||||
CodingContractBaseFactionRepGain: 2500,
|
||||
CodingContractBaseCompanyRepGain: 4000,
|
||||
CodingContractBaseMoneyGain: 75e6,
|
||||
|
||||
// BitNode/Source-File related stuff
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
LatestUpdate:
|
||||
`
|
||||
v0.46.2
|
||||
* Source-File 2 now allows you to form gangs in other BitNodes when your karma reaches a very large negative value
|
||||
** (Karma is a hidden stat and is lowered by committing crimes)
|
||||
* Gang changes:
|
||||
** Bug Fix: Gangs can no longer clash with themselve
|
||||
** Bug Fix: Winning against another gang should properly reduce their power
|
||||
|
||||
* Bug Fix: Terminal 'wget' command now works properly
|
||||
* Bug Fix: Hacknet Server Hash upgrades now properly reset upon installing Augs/switching BitNodes
|
||||
* Bug Fix: Fixed button for creating Corporations
|
||||
|
||||
v0.46.1
|
||||
* Added a very rudimentary directory system to the Terminal
|
||||
** Details here: https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#filesystem-directories
|
||||
|
||||
* Added numHashes(), hashCost(), and spendHashes() functions to the Netscript Hacknet Node API
|
||||
* 'Generate Coding Contract' hash upgrade is now more expensive
|
||||
* 'Generate Coding Contract' hash upgrade now generates the contract randomly on the server, rather than on home computer
|
||||
|
||||
189
src/DevMenu.jsx
189
src/DevMenu.jsx
@@ -1,38 +1,44 @@
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { CodingContractTypes } from "./CodingContracts";
|
||||
import { generateContract,
|
||||
generateRandomContract,
|
||||
generateRandomContractOnHome } from "./CodingContractGenerator";
|
||||
import { Companies } from "./Company/Companies";
|
||||
import { Company } from "./Company/Company";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { Player } from "./Player";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { GetServerByHostname } from "./Server/ServerHelpers";
|
||||
import { hackWorldDaemon } from "./RedPill";
|
||||
import { StockMarket,
|
||||
SymbolToStockMap } from "./StockMarket/StockMarket";
|
||||
import { Stock } from "./StockMarket/Stock";
|
||||
import { Terminal } from "./Terminal";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { CodingContractTypes } from "./CodingContracts";
|
||||
import {
|
||||
generateContract,
|
||||
generateRandomContract,
|
||||
generateRandomContractOnHome
|
||||
} from "./CodingContractGenerator";
|
||||
import { Companies } from "./Company/Companies";
|
||||
import { Company } from "./Company/Company";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { Player } from "./Player";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { GetServerByHostname } from "./Server/ServerHelpers";
|
||||
import { hackWorldDaemon } from "./RedPill";
|
||||
import { StockMarket, SymbolToStockMap } from "./StockMarket/StockMarket";
|
||||
import { Stock } from "./StockMarket/Stock";
|
||||
import { Terminal } from "./Terminal";
|
||||
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
|
||||
import { getSelectText } from "../utils/uiHelpers/getSelectData";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
|
||||
import { getSelectText } from "../utils/uiHelpers/getSelectData";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
|
||||
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 {
|
||||
constructor(props) {
|
||||
@@ -41,7 +47,7 @@ class ValueAdjusterComponent extends Component {
|
||||
this.setValue = this.setValue.bind(this);
|
||||
}
|
||||
setValue(event) {
|
||||
this.setState({ value: event.target.value });
|
||||
this.setState({ value: parseFloat(event.target.value) });
|
||||
}
|
||||
render() {
|
||||
const { title, add, subtract, reset } = this.props;
|
||||
@@ -124,7 +130,6 @@ class DevMenuComponent extends Component {
|
||||
this.setState({ codingcontract: event.target.value });
|
||||
}
|
||||
|
||||
|
||||
addMoney(n) {
|
||||
return function() {
|
||||
Player.gainMoney(n);
|
||||
@@ -186,14 +191,20 @@ class DevMenuComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
modifyKarma(modifier) {
|
||||
return function(amt) {
|
||||
Player.karma += (amt * modifier);
|
||||
}
|
||||
}
|
||||
|
||||
tonsOfExp() {
|
||||
Player.gainHackingExp(1e27);
|
||||
Player.gainStrengthExp(1e27);
|
||||
Player.gainDefenseExp(1e27);
|
||||
Player.gainDexterityExp(1e27);
|
||||
Player.gainAgilityExp(1e27);
|
||||
Player.gainCharismaExp(1e27);
|
||||
Player.gainIntelligenceExp(1e27);
|
||||
Player.gainHackingExp(tonsPP);
|
||||
Player.gainStrengthExp(tonsPP);
|
||||
Player.gainDefenseExp(tonsPP);
|
||||
Player.gainDexterityExp(tonsPP);
|
||||
Player.gainAgilityExp(tonsPP);
|
||||
Player.gainCharismaExp(tonsPP);
|
||||
Player.gainIntelligenceExp(tonsPP);
|
||||
Player.updateSkillLevels();
|
||||
}
|
||||
|
||||
@@ -237,6 +248,12 @@ class DevMenuComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
resetKarma() {
|
||||
return function() {
|
||||
Player.karma = 0;
|
||||
}
|
||||
}
|
||||
|
||||
enableIntelligence() {
|
||||
if(Player.intelligence === 0) {
|
||||
Player.intelligence = 1;
|
||||
@@ -296,7 +313,7 @@ class DevMenuComponent extends Component {
|
||||
|
||||
tonsOfRep() {
|
||||
for (const i in Factions) {
|
||||
Factions[i].playerReputation = 1e27;
|
||||
Factions[i].playerReputation = tonsPP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +325,7 @@ class DevMenuComponent extends Component {
|
||||
|
||||
tonsOfFactionFavor() {
|
||||
for (const i in Factions) {
|
||||
Factions[i].favor = 1e27;
|
||||
Factions[i].favor = tonsPP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +471,7 @@ class DevMenuComponent extends Component {
|
||||
|
||||
tonsOfRepCompanies() {
|
||||
for (const c in Companies) {
|
||||
Companies[c].playerReputation = 1e12;
|
||||
Companies[c].playerReputation = tonsP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,7 +483,7 @@ class DevMenuComponent extends Component {
|
||||
|
||||
tonsOfFavorCompanies() {
|
||||
for (const c in Companies) {
|
||||
Companies[c].favor = 1e12;
|
||||
Companies[c].favor = tonsP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +508,7 @@ class DevMenuComponent extends Component {
|
||||
|
||||
addTonsBladeburnerRank() {
|
||||
if (!!Player.bladeburner) {
|
||||
Player.bladeburner.changeRank(1e12);
|
||||
Player.bladeburner.changeRank(tonsP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,13 +528,13 @@ class DevMenuComponent extends Component {
|
||||
|
||||
addTonsBladeburnerCycles() {
|
||||
if (!!Player.bladeburner) {
|
||||
Player.bladeburner.storedCycles += 1e12;
|
||||
Player.bladeburner.storedCycles += tonsP;
|
||||
}
|
||||
}
|
||||
|
||||
addTonsGangCycles() {
|
||||
if (!!Player.gang) {
|
||||
Player.gang.storedCycles = 1e12;
|
||||
Player.gang.storedCycles = tonsP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,7 +554,7 @@ class DevMenuComponent extends Component {
|
||||
|
||||
addTonsCorporationCycles() {
|
||||
if (!!Player.corporation) {
|
||||
Player.corporation.storedCycles = 1e12;
|
||||
Player.corporation.storedCycles = tonsP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,16 +661,16 @@ class DevMenuComponent extends Component {
|
||||
|
||||
let sourceFiles = [];
|
||||
validSFN.forEach( i => sourceFiles.push(
|
||||
<tr key={'sf-'+i}>
|
||||
<td><span className="text">SF-{i}:</span></td>
|
||||
<td>
|
||||
<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, 2)}>2</button>
|
||||
<button className="std-button touch-left" onClick={this.setSF(i, 3)}>3</button>
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
<tr key={'sf-'+i}>
|
||||
<td><span className="text">SF-{i}:</span></td>
|
||||
<td>
|
||||
<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, 2)}>2</button>
|
||||
<button className="std-button touch-left" onClick={this.setSF(i, 3)}>3</button>
|
||||
</td>
|
||||
</tr>
|
||||
));
|
||||
|
||||
|
||||
|
||||
@@ -713,11 +730,11 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Hacking:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
title="hacking exp"
|
||||
add={this.modifyExp('hacking', 1)}
|
||||
subtract={this.modifyExp('hacking', -1)}
|
||||
reset={this.resetExperience('hacking')}
|
||||
<ValueAdjusterComponent
|
||||
title="hacking exp"
|
||||
add={this.modifyExp('hacking', 1)}
|
||||
subtract={this.modifyExp('hacking', -1)}
|
||||
reset={this.resetExperience('hacking')}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -726,7 +743,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Strength:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="strength exp"
|
||||
add={this.modifyExp('strength', 1)}
|
||||
subtract={this.modifyExp('strength', -1)}
|
||||
@@ -739,7 +756,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Defense:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="defense exp"
|
||||
add={this.modifyExp('defense', 1)}
|
||||
subtract={this.modifyExp('defense', -1)}
|
||||
@@ -752,7 +769,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Dexterity:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="dexterity exp"
|
||||
add={this.modifyExp('dexterity', 1)}
|
||||
subtract={this.modifyExp('dexterity', -1)}
|
||||
@@ -765,7 +782,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Agility:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="agility exp"
|
||||
add={this.modifyExp('agility', 1)}
|
||||
subtract={this.modifyExp('agility', -1)}
|
||||
@@ -778,7 +795,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Charisma:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="charisma exp"
|
||||
add={this.modifyExp('charisma', 1)}
|
||||
subtract={this.modifyExp('charisma', -1)}
|
||||
@@ -791,7 +808,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text text-center">Intelligence:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="intelligence exp"
|
||||
add={this.modifyExp('intelligence', 1)}
|
||||
subtract={this.modifyExp('intelligence', -1)}
|
||||
@@ -805,6 +822,19 @@ class DevMenuComponent extends Component {
|
||||
<button className="std-button" onClick={this.disableIntelligence}>Disable</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span className="text text-center">Karma:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
title="karma"
|
||||
add={this.modifyKarma(1)}
|
||||
subtract={this.modifyKarma(-1)}
|
||||
reset={this.resetKarma()}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -832,7 +862,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text">Reputation:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="reputation"
|
||||
add={this.modifyFactionRep(1)}
|
||||
subtract={this.modifyFactionRep(-1)}
|
||||
@@ -845,7 +875,7 @@ class DevMenuComponent extends Component {
|
||||
<span className="text">Favor:</span>
|
||||
</td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="favor"
|
||||
add={this.modifyFactionFavor(1)}
|
||||
subtract={this.modifyFactionFavor(-1)}
|
||||
@@ -979,7 +1009,7 @@ class DevMenuComponent extends Component {
|
||||
<tr>
|
||||
<td><span className="text">Reputation:</span></td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="reputation"
|
||||
add={this.modifyCompanyRep(1)}
|
||||
subtract={this.modifyCompanyRep(-1)}
|
||||
@@ -990,7 +1020,7 @@ class DevMenuComponent extends Component {
|
||||
<tr>
|
||||
<td><span className="text">Favor:</span></td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="favor"
|
||||
add={this.modifyCompanyFavor(1)}
|
||||
subtract={this.modifyCompanyFavor(-1)}
|
||||
@@ -1028,7 +1058,7 @@ class DevMenuComponent extends Component {
|
||||
<td><span className="text">Rank:</span></td>
|
||||
<td><button className="std-button" onClick={this.addTonsBladeburnerRank}>Tons</button></td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="rank"
|
||||
add={this.modifyBladeburnerRank(1)}
|
||||
subtract={this.modifyBladeburnerRank(-1)}
|
||||
@@ -1040,7 +1070,7 @@ class DevMenuComponent extends Component {
|
||||
<td><span className="text">Cycles:</span></td>
|
||||
<td><button className="std-button" onClick={this.addTonsBladeburnerCycles}>Tons</button></td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="cycles"
|
||||
add={this.modifyBladeburnerCycles(1)}
|
||||
subtract={this.modifyBladeburnerCycles(-1)}
|
||||
@@ -1064,7 +1094,7 @@ class DevMenuComponent extends Component {
|
||||
<td><span className="text">Cycles:</span></td>
|
||||
<td><button className="std-button" onClick={this.addTonsGangCycles}>Tons</button></td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="cycles"
|
||||
add={this.modifyGangCycles(1)}
|
||||
subtract={this.modifyGangCycles(-1)}
|
||||
@@ -1088,7 +1118,7 @@ class DevMenuComponent extends Component {
|
||||
<td><span className="text">Cycles:</span></td>
|
||||
<td><button className="std-button" onClick={this.addTonsCorporationCycles}>Tons</button></td>
|
||||
<td>
|
||||
<ValueAdjusterComponent
|
||||
<ValueAdjusterComponent
|
||||
title="cycles"
|
||||
add={this.modifyCorporationCycles(1)}
|
||||
subtract={this.modifyCorporationCycles(-1)}
|
||||
@@ -1121,7 +1151,7 @@ class DevMenuComponent extends Component {
|
||||
{contractTypes}
|
||||
</select>
|
||||
<button className="std-button" onClick={this.specificContract}>Generate Specified Contract Type on Home Comp</button>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -1185,7 +1215,6 @@ class DevMenuComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const devMenuContainerId = "dev-menu-container";
|
||||
|
||||
export function createDevMenu() {
|
||||
@@ -1199,11 +1228,11 @@ export function createDevMenu() {
|
||||
id: devMenuContainerId,
|
||||
});
|
||||
|
||||
const entireGameContainer = document.getElementById("entire-game-container");
|
||||
if (entireGameContainer == null) {
|
||||
throw new Error("Could not find entire-game-container DOM element");
|
||||
}
|
||||
entireGameContainer.appendChild(devMenuContainer);
|
||||
const entireGameContainer = document.getElementById("entire-game-container");
|
||||
if (entireGameContainer == null) {
|
||||
throw new Error("Could not find entire-game-container DOM element");
|
||||
}
|
||||
entireGameContainer.appendChild(devMenuContainer);
|
||||
|
||||
ReactDOM.render(<DevMenuComponent />, devMenuContainer);
|
||||
}
|
||||
|
||||
@@ -97,16 +97,6 @@ export class Faction {
|
||||
return [favorGain, rep];
|
||||
}
|
||||
|
||||
//Adds all Augmentations to this faction.
|
||||
addAllAugmentations(augs: object): void {
|
||||
this.augmentations.length = 0;
|
||||
for (const name in augs) {
|
||||
if (augs.hasOwnProperty(name)) {
|
||||
this.augmentations.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the current object to a JSON save state.
|
||||
*/
|
||||
|
||||
7
src/Faction/FactionHelpers.d.ts
vendored
Normal file
7
src/Faction/FactionHelpers.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Augmentation } from "../Augmentation/Augmentation";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
|
||||
export declare function getNextNeurofluxLevel(): number;
|
||||
export declare function hasAugmentationPrereqs(aug: Augmentation): boolean;
|
||||
export declare function purchaseAugmentationBoxCreate(aug: Augmentation, fac: Faction): void;
|
||||
export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void;
|
||||
@@ -1,694 +0,0 @@
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Engine } from "../engine";
|
||||
import { Faction } from "./Faction";
|
||||
import { Factions } from "./Factions";
|
||||
import { FactionInfos } from "./FactionInfo";
|
||||
import { HackingMission, setInMission } from "../Missions";
|
||||
import { Player } from "../Player";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../Settings/SettingEnums";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
|
||||
import { createSleevePurchasesFromCovenantPopup } from "../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||
|
||||
import {Page, routing} from "../ui/navigationTracking";
|
||||
import {numeralWrapper} from "../ui/numeralFormat";
|
||||
import {dialogBoxCreate} from "../../utils/DialogBox";
|
||||
import {factionInvitationBoxCreate} from "../../utils/FactionInvitationBox";
|
||||
import {removeChildrenFromElement} from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||
import {createElement} from "../../utils/uiHelpers/createElement";
|
||||
import {Reviver, Generic_toJSON,
|
||||
Generic_fromJSON} from "../../utils/JSONReviver";
|
||||
import {formatNumber} from "../../utils/StringHelperFunctions";
|
||||
import {yesNoBoxCreate, yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton, yesNoBoxClose} from "../../utils/YesNoBox";
|
||||
|
||||
function inviteToFaction(faction) {
|
||||
if (Settings.SuppressFactionInvites) {
|
||||
faction.alreadyInvited = true;
|
||||
Player.factionInvitations.push(faction.name);
|
||||
if (routing.isOn(Page.Factions)) {
|
||||
Engine.loadFactionsContent();
|
||||
}
|
||||
} else {
|
||||
factionInvitationBoxCreate(faction);
|
||||
}
|
||||
}
|
||||
|
||||
function joinFaction(faction) {
|
||||
faction.isMember = true;
|
||||
Player.factions.push(faction.name);
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
//Determine what factions you are banned from now that you have joined this faction
|
||||
for(const i in factionInfo.enemies) {
|
||||
const enemy = factionInfo.enemies[i];
|
||||
if (Factions[enemy] instanceof Faction) {
|
||||
Factions[enemy].isBanned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Displays the HTML content for a specific faction
|
||||
function displayFactionContent(factionName) {
|
||||
var faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error("Invalid factionName passed into displayFactionContent: " + factionName);
|
||||
}
|
||||
if (!faction.isMember) {
|
||||
throw new Error("Not a member of this faction, cannot display faction information");
|
||||
}
|
||||
var factionInfo = faction.getInfo();
|
||||
|
||||
removeChildrenFromElement(Engine.Display.factionContent);
|
||||
var elements = [];
|
||||
|
||||
//Header and faction info
|
||||
elements.push(createElement("h1", {
|
||||
innerText:factionName
|
||||
}));
|
||||
elements.push(createElement("pre", {
|
||||
innerHTML:"<i>" + factionInfo.infoText + "</i>"
|
||||
}));
|
||||
elements.push(createElement("p", {
|
||||
innerText:"---------------",
|
||||
}));
|
||||
|
||||
//Faction reputation and favor
|
||||
var favorGain = faction.getFavorGain();
|
||||
if (favorGain.length != 2) {favorGain = 0;}
|
||||
favorGain = favorGain[0];
|
||||
elements.push(createElement("p", {
|
||||
innerText: "Reputation: " + formatNumber(faction.playerReputation, 4),
|
||||
tooltip:"You will earn " + formatNumber(favorGain, 0) +
|
||||
" faction favor upon resetting after installing an Augmentation"
|
||||
}))
|
||||
elements.push(createElement("p", {
|
||||
innerText:"---------------",
|
||||
}));
|
||||
elements.push(createElement("p", {
|
||||
innerText:"Faction Favor: " + formatNumber(faction.favor, 0),
|
||||
tooltip:"Faction favor increases the rate at which " +
|
||||
"you earn reputation for this faction by 1% per favor. Faction favor " +
|
||||
"is gained whenever you reset after installing an Augmentation. The amount of " +
|
||||
"favor you gain depends on how much reputation you have with the faction"
|
||||
}));
|
||||
elements.push(createElement("p", {
|
||||
innerText:"---------------",
|
||||
}));
|
||||
|
||||
//Faction Work Description Text
|
||||
elements.push(createElement("pre", {
|
||||
id:"faction-work-description-text",
|
||||
innerText:"Perform work/carry out assignments for your faction to help further its cause! By doing so " +
|
||||
"you will earn reputation for your faction. You will also gain reputation passively over time, " +
|
||||
"although at a very slow rate. Earning reputation will allow you to purchase Augmentations " +
|
||||
"through this faction, which are powerful upgrades that enhance your abilities. Note that you cannot " +
|
||||
"use your terminal or create scripts when you are performing a task!"
|
||||
}));
|
||||
elements.push(createElement("br"));
|
||||
|
||||
//Hacking Mission Option
|
||||
var hackMissionDiv = createElement("div", { class:"faction-work-div" });
|
||||
var hackMissionDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
hackMissionDiv.appendChild(hackMissionDivWrapper);
|
||||
hackMissionDivWrapper.appendChild(createElement("a", {
|
||||
class:"a-link-button", innerText:"Hacking Mission",
|
||||
clickListener:()=>{
|
||||
Engine.loadMissionContent();
|
||||
var mission = new HackingMission(faction.playerReputation, faction);
|
||||
setInMission(true, mission); //Sets inMission flag to true
|
||||
mission.init();
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
hackMissionDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Attempt a hacking mission for your faction. " +
|
||||
"A mission is a mini game that, if won, earns you " +
|
||||
"significant reputation with this faction. (Recommended hacking level: 200+)"
|
||||
}));
|
||||
elements.push(hackMissionDiv);
|
||||
|
||||
//Hacking Contracts Option
|
||||
var hackDiv = createElement("div", { class:"faction-work-div", });
|
||||
var hackDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
hackDiv.appendChild(hackDivWrapper);
|
||||
hackDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Hacking Contracts",
|
||||
clickListener:()=>{
|
||||
Player.startFactionHackWork(faction);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
hackDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Complete hacking contracts for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your hacking skill. " +
|
||||
"You will gain hacking exp."
|
||||
}));
|
||||
elements.push(hackDiv);
|
||||
|
||||
//Field Work Option
|
||||
var fieldWorkDiv = createElement("div", { class:"faction-work-div" });
|
||||
var fieldWorkDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
fieldWorkDiv.appendChild(fieldWorkDivWrapper);
|
||||
fieldWorkDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Field Work",
|
||||
clickListener:()=>{
|
||||
Player.startFactionFieldWork(faction);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
fieldWorkDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Carry out field missions for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on all of your stats. " +
|
||||
"You will gain exp for all stats."
|
||||
}));
|
||||
elements.push(fieldWorkDiv);
|
||||
|
||||
//Security Work Option
|
||||
var securityWorkDiv = createElement("div", { class:"faction-work-div" });
|
||||
var securityWorkDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
securityWorkDiv.appendChild(securityWorkDivWrapper);
|
||||
securityWorkDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Security Work",
|
||||
clickListener:()=>{
|
||||
Player.startFactionSecurityWork(faction);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
securityWorkDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Serve in a security detail for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your combat stats. " +
|
||||
"You will gain exp for all combat stats."
|
||||
}));
|
||||
elements.push(securityWorkDiv);
|
||||
|
||||
//Donate for reputation
|
||||
var donateDiv = createElement("div", { class:"faction-work-div" });
|
||||
var donateDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
donateDiv.appendChild(donateDivWrapper);
|
||||
var donateRepGain = createElement("p", {
|
||||
innerText:"This donation will result in 0.000 reputation gain"
|
||||
});
|
||||
var donateAmountInput = createElement("input", {
|
||||
class: "text-input", placeholder:"Donation amount",
|
||||
inputListener:()=>{
|
||||
let amt = 0;
|
||||
if(donateAmountInput.value !== "") {
|
||||
amt = parseFloat(donateAmountInput.value);
|
||||
}
|
||||
if (isNaN(amt)) {
|
||||
donateRepGain.innerText = "Invalid donate amount entered!";
|
||||
} else {
|
||||
var repGain = amt / CONSTANTS.DonateMoneyToRepDivisor * Player.faction_rep_mult;
|
||||
donateRepGain.innerText = "This donation will result in " +
|
||||
formatNumber(repGain, 3) + " reputation gain";
|
||||
}
|
||||
},
|
||||
});
|
||||
donateDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button", innerText:"Donate Money",
|
||||
clickListener:()=>{
|
||||
var amt = parseFloat(donateAmountInput.value);
|
||||
if (isNaN(amt) || amt < 0) {
|
||||
dialogBoxCreate("Invalid amount entered!");
|
||||
} else if (Player.money.lt(amt)) {
|
||||
dialogBoxCreate("You cannot afford to donate this much money!");
|
||||
} else {
|
||||
Player.loseMoney(amt);
|
||||
var repGain = amt / CONSTANTS.DonateMoneyToRepDivisor * Player.faction_rep_mult;
|
||||
faction.playerReputation += repGain;
|
||||
dialogBoxCreate("You just donated " + numeralWrapper.format(amt, "$0.000a") + " to " +
|
||||
faction.name + " to gain " + formatNumber(repGain, 3) + " reputation");
|
||||
displayFactionContent(factionName);
|
||||
}
|
||||
}
|
||||
}));
|
||||
donateDivWrapper.appendChild(donateAmountInput);
|
||||
donateDivWrapper.appendChild(donateRepGain);
|
||||
elements.push(donateDiv);
|
||||
|
||||
//Purchase Augmentations
|
||||
const purchaseAugmentationsDiv = createElement("div", { class: "faction-work-div", display: "inline" });
|
||||
const purchaseAugmentationsDivWrapper = createElement("div", { class: "faction-work-div-wrapper" });
|
||||
purchaseAugmentationsDiv.appendChild(purchaseAugmentationsDivWrapper);
|
||||
purchaseAugmentationsDivWrapper.appendChild(createElement("a", {
|
||||
class:"std-button",
|
||||
innerText:"Purchase Augmentations",
|
||||
margin: "5px",
|
||||
clickListener:()=>{
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.factionAugmentationsContent.style.display = "block";
|
||||
|
||||
displayFactionAugmentations(factionName);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
purchaseAugmentationsDivWrapper.appendChild(createElement("pre", {
|
||||
innerHTML: "<br>As your reputation with this faction rises, you will " +
|
||||
"unlock Augmentations, which you can purchase to enhance " +
|
||||
"your abilities.<br><br>"
|
||||
}));
|
||||
elements.push(purchaseAugmentationsDiv);
|
||||
|
||||
//Gang (BitNode-2)
|
||||
if (Player.bitNodeN == 2 && (factionName == "Slum Snakes" || factionName == "Tetrads" ||
|
||||
factionName == "The Syndicate" || factionName == "The Dark Army" || factionName == "Speakers for the Dead" ||
|
||||
factionName == "NiteSec" || factionName == "The Black Hand")) {
|
||||
//Set everything else to invisible
|
||||
hackMissionDiv.style.display = "none";
|
||||
hackDiv.style.display = "none";
|
||||
fieldWorkDiv.style.display = "none";
|
||||
securityWorkDiv.style.display = "none";
|
||||
donateDiv.style.display = "none";
|
||||
|
||||
//Create the 'Manage Gang' button
|
||||
var gangDiv = createElement("div", {
|
||||
id:"faction-gang-div", class:"faction-work-div", display:"inline"
|
||||
});
|
||||
var gangDivWrapper = createElement("div", {class:"faction-work-div-wrapper"});
|
||||
gangDiv.appendChild(gangDivWrapper);
|
||||
gangDivWrapper.appendChild(createElement("a", {
|
||||
class:"a-link-button", innerText:"Manage Gang",
|
||||
clickListener: () => {
|
||||
if (!Player.inGang()) {
|
||||
// Determine whether this is a hacking gang
|
||||
let hacking = false;
|
||||
if (factionName === "NiteSec" || factionName === "The Black Hand") { hacking = true; }
|
||||
|
||||
// Configure Yes/No buttons for the pop-up
|
||||
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Create Gang";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", () => {
|
||||
Player.startGang(factionName, hacking);
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
Engine.loadGangContent();
|
||||
yesNoBoxClose();
|
||||
});
|
||||
noBtn.addEventListener("click", () => {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
// Pop-up text
|
||||
let gangTypeText = "";
|
||||
if (hacking) {
|
||||
gangTypeText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
"Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " +
|
||||
"is not as important.<br><br>";
|
||||
} else {
|
||||
gangTypeText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
|
||||
"is more important. However, well-managed combat gangs can progress faster than hacking ones.<br><br>";
|
||||
}
|
||||
yesNoBoxCreate(`Would you like to create a new Gang with ${factionName}?<br><br>` +
|
||||
"Note that this will prevent you from creating a Gang with any other Faction until " +
|
||||
"this BitNode is destroyed.<br><br>" +
|
||||
gangTypeText +
|
||||
"Other than hacking vs combat, there are NO differences between the Factions you can " +
|
||||
"create a Gang with, and each of these Factions have all Augmentations available.");
|
||||
} else {
|
||||
Engine.loadGangContent();
|
||||
}
|
||||
}
|
||||
}));
|
||||
gangDivWrapper.appendChild(createElement("p", {
|
||||
innerText:"Create and manage a gang for this Faction. " +
|
||||
"Gangs will earn you money and faction reputation."
|
||||
}));
|
||||
//Manage Gang button goes before Faction work stuff
|
||||
elements.splice(7, 1, gangDiv);
|
||||
|
||||
if (Player.inGang() && Player.gang.facName != factionName) {
|
||||
//If the player has a gang but its not for this faction
|
||||
gangDiv.style.display = "none";
|
||||
}
|
||||
//Display all elements
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
Engine.Display.factionContent.appendChild(elements[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Purchase Sleeves from Covenant
|
||||
if (factionName === "The Covenant" && Player.bitNodeN >= 10 && SourceFileFlags[10]) {
|
||||
const covenantPurchaseSleevesDiv = createElement("div", { class: "faction-work-div", display: "inline" });
|
||||
const covenantPurchaseSleevesDivWrapper = createElement("div", { class: "faction-work-div-wrapper" });
|
||||
covenantPurchaseSleevesDiv.appendChild(covenantPurchaseSleevesDivWrapper);
|
||||
covenantPurchaseSleevesDivWrapper.appendChild(createElement("a", {
|
||||
class: "std-button",
|
||||
innerText: "Purchase Duplicate Sleeves",
|
||||
clickListener: () => {
|
||||
createSleevePurchasesFromCovenantPopup(Player);
|
||||
}
|
||||
}));
|
||||
covenantPurchaseSleevesDivWrapper.appendChild(createElement("p", {
|
||||
innerText: "Purchase Duplicate Sleeves. These are permanent! You can purchase up to 5 total.",
|
||||
}));
|
||||
|
||||
elements.push(covenantPurchaseSleevesDiv);
|
||||
}
|
||||
|
||||
// Determine if actions should be possible
|
||||
donateDiv.style.display = faction.favor >= Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction) ? "inline" : "none";
|
||||
|
||||
hackMissionDiv.style.display = factionInfo.offerHackingMission ? "inline": "none";
|
||||
hackDiv.style.display = factionInfo.offerHackingWork ? "inline" : "none";
|
||||
fieldWorkDiv.style.display = factionInfo.offerFieldWork ? "inline" : "none";
|
||||
securityWorkDiv.style.display = factionInfo.offerSecurityWork ? "inline" : "none";
|
||||
|
||||
//Display all elements
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
Engine.Display.factionContent.appendChild(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function displayFactionAugmentations(factionName) {
|
||||
var faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error("Could not find faction " + factionName + " in displayFactionAugmentations");
|
||||
}
|
||||
|
||||
removeChildrenFromElement(Engine.Display.factionAugmentationsContent);
|
||||
var elements = [];
|
||||
|
||||
//Back button
|
||||
elements.push(createElement("a", {
|
||||
innerText:"Back", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Engine.loadFactionContent();
|
||||
displayFactionContent(factionName);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
//Header text
|
||||
elements.push(createElement("h1", {innerText:"Faction Augmentations"}));
|
||||
elements.push(createElement("p", {
|
||||
id:"faction-augmentations-page-desc",
|
||||
innerHTML:"Lists all Augmentations that are available to purchase from " + factionName + "<br><br>" +
|
||||
"Augmentations are powerful upgrades that will enhance your abilities."
|
||||
}));
|
||||
|
||||
elements.push(createElement("br"));
|
||||
elements.push(createElement("br"));
|
||||
|
||||
//Augmentations List
|
||||
var augmentationsList = createElement("ul");
|
||||
|
||||
//Sort buttons
|
||||
const sortByCostBtn = createElement("a", {
|
||||
innerText:"Sort by Cost", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Cost;
|
||||
var augs = faction.augmentations.slice();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
return aug1.baseCost - aug2.baseCost;
|
||||
});
|
||||
removeChildrenFromElement(augmentationsList);
|
||||
createFactionAugmentationDisplayElements(augmentationsList, augs, faction);
|
||||
}
|
||||
});
|
||||
const sortByRepBtn = createElement("a", {
|
||||
innerText:"Sort by Reputation", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Reputation;
|
||||
var augs = faction.augmentations.slice();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
return aug1.baseRepRequirement - aug2.baseRepRequirement;
|
||||
});
|
||||
removeChildrenFromElement(augmentationsList);
|
||||
createFactionAugmentationDisplayElements(augmentationsList, augs, faction);
|
||||
}
|
||||
});
|
||||
const defaultSortBtn = createElement("a", {
|
||||
innerText:"Sort by Default Order", class:"a-link-button",
|
||||
clickListener:()=>{
|
||||
Settings.PurchaseAugmentationsOrder = PurchaseAugmentationsOrderSetting.Default;
|
||||
removeChildrenFromElement(augmentationsList);
|
||||
createFactionAugmentationDisplayElements(augmentationsList, faction.augmentations, faction);
|
||||
}
|
||||
});
|
||||
elements.push(sortByCostBtn);
|
||||
elements.push(sortByRepBtn);
|
||||
elements.push(defaultSortBtn);
|
||||
switch(Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost:
|
||||
sortByCostBtn.click();
|
||||
break;
|
||||
case PurchaseAugmentationsOrderSetting.Reputation:
|
||||
sortByRepBtn.click();
|
||||
break;
|
||||
default:
|
||||
defaultSortBtn.click();
|
||||
break;
|
||||
}
|
||||
|
||||
elements.push(augmentationsList);
|
||||
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
Engine.Display.factionAugmentationsContent.appendChild(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//Takes in an array of Augmentation Names, constructs DOM elements
|
||||
//to list them on the faction page, and appends them to the given
|
||||
//DOM element
|
||||
// @augmentationsList DOM List to append Aug DOM elements to
|
||||
// @augs Array of Aug names
|
||||
// @faction Faction for which to display Augmentations
|
||||
function createFactionAugmentationDisplayElements(augmentationsList, augs, faction) {
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
for (var i = 0; i < augs.length; ++i) {
|
||||
(function () {
|
||||
var aug = Augmentations[augs[i]];
|
||||
if (aug == null) {
|
||||
throw new Error("Invalid Augmentation when trying to create Augmentation display Elements");
|
||||
}
|
||||
var owned = false;
|
||||
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name == aug.name) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < Player.augmentations.length; ++j) {
|
||||
if (Player.augmentations[j].name == aug.name) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var item = createElement("li");
|
||||
var span = createElement("span", { display:"inline-block", margin: "4px", padding: "4px" });
|
||||
var aDiv = createElement("div", {tooltip:aug.info});
|
||||
var aElem = createElement("a", {
|
||||
innerText:aug.name, display:"inline",
|
||||
clickListener:()=>{
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
purchaseAugmentationBoxCreate(aug, faction);
|
||||
} else {
|
||||
purchaseAugmentation(aug, faction);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
aElem.innerText += " - Level " + (getNextNeurofluxLevel());
|
||||
}
|
||||
var pElem = createElement("p", {
|
||||
display:"inline",
|
||||
})
|
||||
var req = aug.baseRepRequirement * factionInfo.augmentationRepRequirementMult;
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
aElem.setAttribute("class", "a-link-button-inactive");
|
||||
pElem.innerHTML = "LOCKED (Requires " + aug.prereqs.join(",") + " as prerequisite(s))";
|
||||
pElem.style.color = "red";
|
||||
} else if (aug.name != AugmentationNames.NeuroFluxGovernor && (aug.owned || owned)) {
|
||||
aElem.setAttribute("class", "a-link-button-inactive");
|
||||
pElem.innerHTML = "ALREADY OWNED";
|
||||
} else if (faction.playerReputation >= req) {
|
||||
aElem.setAttribute("class", "a-link-button");
|
||||
pElem.innerHTML = "UNLOCKED - " + numeralWrapper.format(aug.baseCost * factionInfo.augmentationPriceMult, "$0.000a");
|
||||
} else {
|
||||
aElem.setAttribute("class", "a-link-button-inactive");
|
||||
pElem.innerHTML = "LOCKED (Requires " + formatNumber(req, 1) + " faction reputation) - " + numeralWrapper.format(aug.baseCost * factionInfo.augmentationPriceMult, "$0.000a");
|
||||
pElem.style.color = "red";
|
||||
}
|
||||
aDiv.appendChild(aElem);
|
||||
span.appendChild(aDiv);
|
||||
span.appendChild(pElem);
|
||||
item.appendChild(span);
|
||||
augmentationsList.appendChild(item);
|
||||
}()); //Immediate invocation closure
|
||||
}
|
||||
}
|
||||
|
||||
function purchaseAugmentationBoxCreate(aug, fac) {
|
||||
const factionInfo = fac.getInfo();
|
||||
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Purchase";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
purchaseAugmentation(aug, fac);
|
||||
});
|
||||
noBtn.addEventListener("click", function() {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
|
||||
aug.info + "<br><br>" +
|
||||
"<br>Would you like to purchase the " + aug.name + " Augmentation for $" +
|
||||
formatNumber(aug.baseCost * factionInfo.augmentationPriceMult, 2) + "?");
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
function hasAugmentationPrereqs(aug) {
|
||||
var hasPrereqs = true;
|
||||
if (aug.prereqs && aug.prereqs.length > 0) {
|
||||
for (var i = 0; i < aug.prereqs.length; ++i) {
|
||||
var prereqAug = Augmentations[aug.prereqs[i]];
|
||||
if (prereqAug == null) {
|
||||
console.log("ERROR: Invalid prereq Augmentation: " + aug.prereqs[i]);
|
||||
continue;
|
||||
}
|
||||
if (prereqAug.owned === false) {
|
||||
hasPrereqs = false;
|
||||
|
||||
//Check if the aug is purchased
|
||||
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name === prereqAug.name) {
|
||||
hasPrereqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasPrereqs;
|
||||
}
|
||||
|
||||
function purchaseAugmentation(aug, fac, sing=false) {
|
||||
const factionInfo = fac.getInfo();
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
|
||||
"purchase this one.";
|
||||
if (sing) {return txt;} else {dialogBoxCreate(txt);}
|
||||
} else if (aug.baseCost !== 0 && Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
let txt = "You don't have enough money to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (fac.playerReputation < aug.baseRepRequirement) {
|
||||
let txt = "You don't have enough faction reputation to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
if (Player.firstAugPurchased === false) {
|
||||
Player.firstAugPurchased = true;
|
||||
document.getElementById("augmentations-tab").style.display = "list-item";
|
||||
document.getElementById("character-menu-header").click();
|
||||
document.getElementById("character-menu-header").click();
|
||||
}
|
||||
|
||||
var queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
queuedAugmentation.level = getNextNeurofluxLevel();
|
||||
}
|
||||
Player.queuedAugmentations.push(queuedAugmentation);
|
||||
|
||||
Player.loseMoney((aug.baseCost * factionInfo.augmentationPriceMult));
|
||||
|
||||
//If you just purchased Neuroflux Governor, recalculate the cost
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
var nextLevel = getNextNeurofluxLevel();
|
||||
--nextLevel;
|
||||
var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
||||
aug.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||
aug.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
|
||||
for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) {
|
||||
aug.baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in Augmentations) {
|
||||
if (Augmentations.hasOwnProperty(name)) {
|
||||
Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (sing) {
|
||||
return "You purchased " + aug.name;
|
||||
} else {
|
||||
if(!Settings.SuppressBuyAugmentationConfirmation){
|
||||
dialogBoxCreate("You purchased " + aug.name + ". It's enhancements will not take " +
|
||||
"effect until they are installed. To install your augmentations, go to the " +
|
||||
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
||||
"augmentations will now be more expensive.");
|
||||
}
|
||||
}
|
||||
|
||||
displayFactionAugmentations(fac.name);
|
||||
} else {
|
||||
dialogBoxCreate("Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.");
|
||||
}
|
||||
yesNoBoxClose();
|
||||
}
|
||||
|
||||
function getNextNeurofluxLevel() {
|
||||
// Get current Neuroflux level based on Player's augmentations
|
||||
let currLevel = 0;
|
||||
for (var i = 0; i < Player.augmentations.length; ++i) {
|
||||
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
||||
currLevel = Player.augmentations[i].level;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for purchased but uninstalled Augmentations
|
||||
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||
++currLevel;
|
||||
}
|
||||
}
|
||||
return currLevel + 1;
|
||||
}
|
||||
|
||||
function processPassiveFactionRepGain(numCycles) {
|
||||
var numTimesGain = (numCycles / 600) * Player.faction_rep_mult;
|
||||
for (var name in Factions) {
|
||||
if (Factions.hasOwnProperty(name)) {
|
||||
var faction = Factions[name];
|
||||
|
||||
//TODO Get hard value of 1 rep per "rep gain cycle"" for now..
|
||||
//maybe later make this based on
|
||||
//a player's 'status' like how powerful they are and how much money they have
|
||||
if (faction.isMember) {faction.playerReputation += (numTimesGain * BitNodeMultipliers.FactionPassiveRepGain);}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {getNextNeurofluxLevel, inviteToFaction,
|
||||
joinFaction, displayFactionContent, processPassiveFactionRepGain,
|
||||
purchaseAugmentation};
|
||||
240
src/Faction/FactionHelpers.jsx
Normal file
240
src/Faction/FactionHelpers.jsx
Normal file
@@ -0,0 +1,240 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { FactionRoot } from "./ui/Root";
|
||||
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Engine } from "../engine";
|
||||
import { Faction } from "./Faction";
|
||||
import { Factions } from "./Factions";
|
||||
import { HackingMission, setInMission } from "../Missions";
|
||||
import { Player } from "../Player";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
|
||||
import { Page, routing } from "../ui/navigationTracking";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { factionInvitationBoxCreate } from "../../utils/FactionInvitationBox";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON
|
||||
} from "../../utils/JSONReviver";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
import {
|
||||
yesNoBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxClose
|
||||
} from "../../utils/YesNoBox";
|
||||
|
||||
export function inviteToFaction(faction) {
|
||||
if (Settings.SuppressFactionInvites) {
|
||||
faction.alreadyInvited = true;
|
||||
Player.factionInvitations.push(faction.name);
|
||||
if (routing.isOn(Page.Factions)) {
|
||||
Engine.loadFactionsContent();
|
||||
}
|
||||
} else {
|
||||
factionInvitationBoxCreate(faction);
|
||||
}
|
||||
}
|
||||
|
||||
export function joinFaction(faction) {
|
||||
faction.isMember = true;
|
||||
Player.factions.push(faction.name);
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
//Determine what factions you are banned from now that you have joined this faction
|
||||
for(const i in factionInfo.enemies) {
|
||||
const enemy = factionInfo.enemies[i];
|
||||
if (Factions[enemy] instanceof Faction) {
|
||||
Factions[enemy].isBanned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function startHackingMission(faction) {
|
||||
const mission = new HackingMission(faction.playerReputation, faction);
|
||||
setInMission(true, mission); //Sets inMission flag to true
|
||||
mission.init();
|
||||
}
|
||||
|
||||
//Displays the HTML content for a specific faction
|
||||
export function displayFactionContent(factionName, initiallyOnAugmentationsPage=false) {
|
||||
const faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error(`Invalid factionName passed into displayFactionContent(): ${factionName}`);
|
||||
}
|
||||
|
||||
if (!faction.isMember) {
|
||||
throw new Error(`Not a member of this faction. Cannot display faction information`);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<FactionRoot
|
||||
engine={Engine}
|
||||
initiallyOnAugmentationsPage={initiallyOnAugmentationsPage}
|
||||
faction={faction}
|
||||
p={Player}
|
||||
startHackingMissionFn={startHackingMission}
|
||||
/>,
|
||||
Engine.Display.factionContent
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export function purchaseAugmentationBoxCreate(aug, fac) {
|
||||
const factionInfo = fac.getInfo();
|
||||
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
yesBtn.innerHTML = "Purchase";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
purchaseAugmentation(aug, fac);
|
||||
});
|
||||
|
||||
const noBtn = yesNoBoxGetNoButton();
|
||||
noBtn.innerHTML = "Cancel";
|
||||
noBtn.addEventListener("click", function() {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
|
||||
aug.info + "<br><br>" +
|
||||
"<br>Would you like to purchase the " + aug.name + " Augmentation for $" +
|
||||
formatNumber(aug.baseCost * factionInfo.augmentationPriceMult, 2) + "?");
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
export function hasAugmentationPrereqs(aug) {
|
||||
let hasPrereqs = true;
|
||||
if (aug.prereqs && aug.prereqs.length > 0) {
|
||||
for (let i = 0; i < aug.prereqs.length; ++i) {
|
||||
const prereqAug = Augmentations[aug.prereqs[i]];
|
||||
if (prereqAug == null) {
|
||||
console.error(`Invalid prereq Augmentation ${aug.prereqs[i]}`);
|
||||
continue;
|
||||
}
|
||||
if (prereqAug.owned === false) {
|
||||
hasPrereqs = false;
|
||||
|
||||
// Check if the aug is purchased
|
||||
for (let j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name === prereqAug.name) {
|
||||
hasPrereqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasPrereqs;
|
||||
}
|
||||
|
||||
export function purchaseAugmentation(aug, fac, sing=false) {
|
||||
const factionInfo = fac.getInfo();
|
||||
var hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
|
||||
"purchase this one.";
|
||||
if (sing) {return txt;} else {dialogBoxCreate(txt);}
|
||||
} else if (aug.baseCost !== 0 && Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
let txt = "You don't have enough money to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (fac.playerReputation < aug.baseRepRequirement) {
|
||||
let txt = "You don't have enough faction reputation to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
if (Player.firstAugPurchased === false) {
|
||||
Player.firstAugPurchased = true;
|
||||
document.getElementById("augmentations-tab").style.display = "list-item";
|
||||
document.getElementById("character-menu-header").click();
|
||||
document.getElementById("character-menu-header").click();
|
||||
}
|
||||
|
||||
var queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
queuedAugmentation.level = getNextNeurofluxLevel();
|
||||
}
|
||||
Player.queuedAugmentations.push(queuedAugmentation);
|
||||
|
||||
Player.loseMoney((aug.baseCost * factionInfo.augmentationPriceMult));
|
||||
|
||||
// If you just purchased Neuroflux Governor, recalculate the cost
|
||||
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
|
||||
var nextLevel = getNextNeurofluxLevel();
|
||||
--nextLevel;
|
||||
var mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
|
||||
aug.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||
aug.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||
|
||||
for (var i = 0; i < Player.queuedAugmentations.length-1; ++i) {
|
||||
aug.baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in Augmentations) {
|
||||
if (Augmentations.hasOwnProperty(name)) {
|
||||
Augmentations[name].baseCost *= CONSTANTS.MultipleAugMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (sing) {
|
||||
return "You purchased " + aug.name;
|
||||
} else {
|
||||
if(!Settings.SuppressBuyAugmentationConfirmation){
|
||||
dialogBoxCreate("You purchased " + aug.name + ". It's enhancements will not take " +
|
||||
"effect until they are installed. To install your augmentations, go to the " +
|
||||
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
||||
"augmentations will now be more expensive.");
|
||||
}
|
||||
}
|
||||
|
||||
// Force a rerender of the Augmentations page
|
||||
displayFactionContent(fac.name, true);
|
||||
} else {
|
||||
dialogBoxCreate("Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.");
|
||||
}
|
||||
yesNoBoxClose();
|
||||
}
|
||||
|
||||
export function getNextNeurofluxLevel() {
|
||||
// Get current Neuroflux level based on Player's augmentations
|
||||
let currLevel = 0;
|
||||
for (var i = 0; i < Player.augmentations.length; ++i) {
|
||||
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
|
||||
currLevel = Player.augmentations[i].level;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for purchased but uninstalled Augmentations
|
||||
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
|
||||
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
|
||||
++currLevel;
|
||||
}
|
||||
}
|
||||
return currLevel + 1;
|
||||
}
|
||||
|
||||
export function processPassiveFactionRepGain(numCycles) {
|
||||
var numTimesGain = (numCycles / 600) * Player.faction_rep_mult;
|
||||
for (var name in Factions) {
|
||||
if (Factions.hasOwnProperty(name)) {
|
||||
var faction = Factions[name];
|
||||
|
||||
//TODO Get hard value of 1 rep per "rep gain cycle"" for now..
|
||||
//maybe later make this based on
|
||||
//a player's 'status' like how powerful they are and how much money they have
|
||||
if (faction.isMember) {faction.playerReputation += (numTimesGain * BitNodeMultipliers.FactionPassiveRepGain);}
|
||||
}
|
||||
}
|
||||
}
|
||||
163
src/Faction/ui/AugmentationsPage.tsx
Normal file
163
src/Faction/ui/AugmentationsPage.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Root React Component for displaying a faction's "Purchase Augmentations" page
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
routeToMainPage: () => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
sortOrder: PurchaseAugmentationsOrderSetting;
|
||||
}
|
||||
|
||||
const infoStyleMarkup = {
|
||||
width: "70%",
|
||||
}
|
||||
|
||||
export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
// Flag for whether the player has a gang with this faction
|
||||
isPlayersGang: boolean;
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.isPlayersGang = props.p.inGang() && (props.p.getGangName() === props.faction.name);
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
sortOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||
}
|
||||
|
||||
this.rerender = this.rerender.bind(this);
|
||||
}
|
||||
|
||||
getAugs() {
|
||||
if (this.isPlayersGang) {
|
||||
const augs: string[] = [];
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug.isSpecial) {
|
||||
augs.push(augName);
|
||||
}
|
||||
}
|
||||
|
||||
return augs;
|
||||
} else {
|
||||
return this.props.faction.augmentations.slice();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSorted() {
|
||||
switch (Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost: {
|
||||
return this.getAugsSortedByCost();
|
||||
}
|
||||
case PurchaseAugmentationsOrderSetting.Reputation: {
|
||||
return this.getAugsSortedByReputation();
|
||||
}
|
||||
default:
|
||||
return this.getAugsSortedByDefault();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSortedByCost() {
|
||||
const augs = this.getAugs();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
|
||||
return aug1.baseCost - aug2.baseCost;
|
||||
});
|
||||
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByReputation() {
|
||||
const augs = this.getAugs();
|
||||
augs.sort((augName1, augName2)=>{
|
||||
var aug1 = Augmentations[augName1], aug2 = Augmentations[augName2];
|
||||
if (aug1 == null || aug2 == null) {
|
||||
throw new Error("Invalid Augmentation Names");
|
||||
}
|
||||
return aug1.baseRepRequirement - aug2.baseRepRequirement;
|
||||
});
|
||||
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByDefault() {
|
||||
return this.getAugs();
|
||||
}
|
||||
|
||||
switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting) {
|
||||
Settings.PurchaseAugmentationsOrder = newOrder;
|
||||
this.rerender();
|
||||
}
|
||||
|
||||
rerender() {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const augs = this.getAugsSorted();
|
||||
const augList = augs.map((aug) => {
|
||||
return (
|
||||
<PurchaseableAugmentation
|
||||
augName={aug}
|
||||
faction={this.props.faction}
|
||||
key={aug}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton
|
||||
onClick={this.props.routeToMainPage}
|
||||
text={"Back"}
|
||||
/>
|
||||
<h1>Faction Augmentations</h1>
|
||||
<p style={infoStyleMarkup}>
|
||||
These are all of the Augmentations that are available to purchase
|
||||
from {this.props.faction.name}. Augmentations are powerful upgrades
|
||||
that will enhance your abilities.
|
||||
</p>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}
|
||||
text={"Sort by Cost"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
||||
text={"Sort by Reputation"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
||||
text={"Sort by Default Order"}
|
||||
/>
|
||||
<br />
|
||||
{augList}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
101
src/Faction/ui/DonateOption.tsx
Normal file
101
src/Faction/ui/DonateOption.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* React component for a donate option on the Faction UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
donateAmt: number;
|
||||
statusTxt: string;
|
||||
}
|
||||
|
||||
const inputStyleMarkup = {
|
||||
margin: "5px",
|
||||
}
|
||||
|
||||
export class DonateOption extends React.Component<IProps, IState> {
|
||||
// Style markup for block elements. Stored as property
|
||||
blockStyle: object = { display: "block" };
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
donateAmt: 0,
|
||||
statusTxt: "",
|
||||
}
|
||||
|
||||
this.calculateRepGain = this.calculateRepGain.bind(this);
|
||||
this.donate = this.donate.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
|
||||
// Returns rep gain for the current donation amount
|
||||
calculateRepGain(): number {
|
||||
return this.state.donateAmt / CONSTANTS.DonateMoneyToRepDivisor * this.props.p.faction_rep_mult;
|
||||
}
|
||||
|
||||
donate(): void {
|
||||
const fac = this.props.faction;
|
||||
const amt = this.state.donateAmt;
|
||||
if (isNaN(amt) || amt <= 0) {
|
||||
dialogBoxCreate(`Invalid amount entered!`);
|
||||
} else if (!this.props.p.canAfford(amt)) {
|
||||
dialogBoxCreate(`You cannot afford to donate this much money!`);
|
||||
} else {
|
||||
this.props.p.loseMoney(amt);
|
||||
const repGain = this.calculateRepGain();
|
||||
this.props.faction.playerReputation += repGain;
|
||||
dialogBoxCreate(`You just donated ${numeralWrapper.formatMoney(amt)} to ${fac.name} to gain ` +
|
||||
`${numeralWrapper.format(repGain, "0,0.000")} reputation`);
|
||||
this.props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const amt = parseFloat(e.target.value);
|
||||
|
||||
if (isNaN(amt)) {
|
||||
this.setState({
|
||||
donateAmt: 0,
|
||||
statusTxt: "Invalid donate amount entered!",
|
||||
});
|
||||
} else {
|
||||
const repGain = this.calculateRepGain();
|
||||
this.setState({
|
||||
donateAmt: amt,
|
||||
statusTxt: `This donation will result in ${numeralWrapper.format(repGain, "0,0.000")} reputation gain`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={"faction-work-div"}>
|
||||
<div className={"faction-work-div-wrapper"}>
|
||||
<input onChange={this.handleChange} placeholder={"Donation amount"} style={inputStyleMarkup} />
|
||||
<StdButton
|
||||
onClick={this.donate}
|
||||
text={"Donate Money"}
|
||||
/>
|
||||
<p style={this.blockStyle}>{this.state.statusTxt}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
72
src/Faction/ui/Info.tsx
Normal file
72
src/Faction/ui/Info.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* React component for general information about the faction. This includes the
|
||||
* factions "motto", reputation, favor, and gameplay instructions
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { FactionInfo } from "../../Faction/FactionInfo";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { AutoupdatingParagraph } from "../../ui/React/AutoupdatingParagraph";
|
||||
import { ParagraphWithTooltip } from "../../ui/React/ParagraphWithTooltip";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
factionInfo: FactionInfo;
|
||||
}
|
||||
|
||||
type IInnerHTMLMarkup = {
|
||||
__html: string;
|
||||
}
|
||||
|
||||
const blockStyleMarkup = {
|
||||
display: "block",
|
||||
}
|
||||
|
||||
const infoStyleMarkup = {
|
||||
display: "block",
|
||||
width: "70%",
|
||||
}
|
||||
|
||||
export class Info extends React.Component<IProps, any> {
|
||||
render() {
|
||||
|
||||
const formattedRep = numeralWrapper.format(this.props.faction.playerReputation, "0.000a");
|
||||
const favorGain = this.props.faction.getFavorGain()[0];
|
||||
const favorTooltip = "Faction favor increases the rate at which you earn reputation for " +
|
||||
"this faction by 1% per favor. Faction favor is gained whenever you " +
|
||||
"reset after installing an Augmentation. The amount of " +
|
||||
"favor you gain depends on how much reputation you have with the faction"
|
||||
|
||||
const infoText: IInnerHTMLMarkup = {
|
||||
__html: this.props.factionInfo.infoText,
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<i className={"text"} style={infoStyleMarkup} dangerouslySetInnerHTML={infoText}></i>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<AutoupdatingParagraph
|
||||
intervalTime={5e3}
|
||||
text={`Reputation: ${formattedRep}`}
|
||||
tooltip={`You will earn ${numeralWrapper.format(favorGain, "0,0")} faction favor upon resetting after installing an Augmentation`}
|
||||
/>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<ParagraphWithTooltip
|
||||
text={`Faction Favor: ${numeralWrapper.format(this.props.faction.favor, "0,0")}`}
|
||||
tooltip={favorTooltip}
|
||||
/>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<p style={infoStyleMarkup}>
|
||||
Perform work/carry out assignments for your faction to help further its cause!
|
||||
By doing so you will earn reputation for your faction. You will also gain
|
||||
reputation passively over time, although at a very slow rate. Earning
|
||||
reputation will allow you to purchase Augmentations through this faction, which
|
||||
are powerful upgrades that enhance your abilities. Note that you cannot use your
|
||||
terminal or create scripts when you are performing a task!
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
30
src/Faction/ui/Option.tsx
Normal file
30
src/Faction/ui/Option.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* React component for a selectable option on the Faction UI. These
|
||||
* options including working for the faction, hacking missions, purchasing
|
||||
* augmentations, etc.
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
buttonText: string;
|
||||
infoText: string;
|
||||
onClick: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
}
|
||||
|
||||
export class Option extends React.Component<IProps, any> {
|
||||
render() {
|
||||
return (
|
||||
<div className={"faction-work-div"}>
|
||||
<div className={"faction-work-div-wrapper"}>
|
||||
<StdButton
|
||||
onClick={this.props.onClick}
|
||||
text={this.props.buttonText}
|
||||
/>
|
||||
<p>{this.props.infoText}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
151
src/Faction/ui/PurchaseableAugmentation.tsx
Normal file
151
src/Faction/ui/PurchaseableAugmentation.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* React component for displaying a single augmentation for purchase through
|
||||
* the faction UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
getNextNeurofluxLevel,
|
||||
hasAugmentationPrereqs,
|
||||
purchaseAugmentation,
|
||||
purchaseAugmentationBoxCreate,
|
||||
} from "../FactionHelpers";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { IMap } from "../../types";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
augName: string;
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
const spanStyleMarkup = {
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}
|
||||
|
||||
const inlineStyleMarkup = {
|
||||
display: "inline-block",
|
||||
}
|
||||
|
||||
export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
aug: Augmentation | null;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.aug = Augmentations[this.props.augName];
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
getMoneyCost(): number {
|
||||
return this.aug!.baseCost * this.props.faction.getInfo().augmentationPriceMult;
|
||||
}
|
||||
|
||||
getRepCost(): number {
|
||||
return this.aug!.baseRepRequirement * this.props.faction.getInfo().augmentationRepRequirementMult;
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
purchaseAugmentationBoxCreate(this.aug!, this.props.faction);
|
||||
} else {
|
||||
purchaseAugmentation(this.aug!, this.props.faction);
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the player has the prerequisite Augmentations
|
||||
hasPrereqs(): boolean {
|
||||
return hasAugmentationPrereqs(this.aug!);
|
||||
}
|
||||
|
||||
// Whether the player has enough rep for this Augmentation
|
||||
hasReputation(): boolean {
|
||||
return this.props.faction.playerReputation >= this.getRepCost();
|
||||
}
|
||||
|
||||
// Whether the player has this augmentations (purchased OR installed)
|
||||
owned(): boolean {
|
||||
let owned = false;
|
||||
for (const queuedAug of this.props.p.queuedAugmentations) {
|
||||
if (queuedAug.name === this.props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const installedAug of this.props.p.augmentations) {
|
||||
if (installedAug.name === this.props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return owned;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.aug == null) {
|
||||
console.error(`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${this.props.augName}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const moneyCost = this.getMoneyCost();
|
||||
const repCost = this.getRepCost();
|
||||
|
||||
// Determine UI properties
|
||||
let disabled: boolean = false;
|
||||
let statusTxt: string = "";
|
||||
let color: string = "";
|
||||
if (!this.hasPrereqs()) {
|
||||
disabled = true;
|
||||
statusTxt = `LOCKED (Requires ${this.aug.prereqs.join(",")} as prerequisite(s))`;
|
||||
color = "red";
|
||||
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
||||
disabled = true;
|
||||
statusTxt = "ALREADY OWNED";
|
||||
} else if (this.hasReputation()) {
|
||||
statusTxt = `UNLOCKED - ${numeralWrapper.formatMoney(moneyCost)}`;
|
||||
} else {
|
||||
disabled = true;
|
||||
statusTxt = `LOCKED (Requires ${numeralWrapper.format(repCost, "0,0.0")} faction reputation - ${numeralWrapper.formatMoney(moneyCost)})`;
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const txtStyle: IMap<string> = {
|
||||
display: "inline-block",
|
||||
}
|
||||
if (color !== "") { txtStyle.color = color; }
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = this.aug.name;
|
||||
if (this.aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeurofluxLevel()}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<li>
|
||||
<span style={spanStyleMarkup}>
|
||||
<StdButton
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
style={inlineStyleMarkup}
|
||||
text={btnTxt}
|
||||
/>
|
||||
<p style={txtStyle}>{statusTxt}</p>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
}
|
||||
298
src/Faction/ui/Root.tsx
Normal file
298
src/Faction/ui/Root.tsx
Normal file
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* Root React Component for displaying a Faction's UI.
|
||||
* This is the component for displaying a single faction's UI, not the list of all
|
||||
* accessible factions
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { AugmentationsPage } from "./AugmentationsPage";
|
||||
import { DonateOption } from "./DonateOption";
|
||||
import { Info } from "./Info";
|
||||
import { Option } from "./Option";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { createSleevePurchasesFromCovenantPopup } from "../../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
import {
|
||||
yesNoBoxClose,
|
||||
yesNoBoxCreate,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxGetYesButton,
|
||||
} from "../../../utils/YesNoBox";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
initiallyOnAugmentationsPage?: boolean;
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
startHackingMissionFn: (faction: Faction) => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
purchasingAugs: boolean;
|
||||
}
|
||||
|
||||
// Info text for all options on the UI
|
||||
const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and " +
|
||||
"faction reputation";
|
||||
const hackingMissionInfo = "Attempt a hacking mission for your faction. " +
|
||||
"A mission is a mini game that, if won, earns you " +
|
||||
"significant reputation with this faction. (Recommended hacking level: 200+)";
|
||||
const hackingContractsInfo = "Complete hacking contracts for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your hacking skill. " +
|
||||
"You will gain hacking exp.";
|
||||
const fieldWorkInfo = "Carry out field missions for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on all of your stats. " +
|
||||
"You will gain exp for all stats.";
|
||||
const securityWorkInfo = "Serve in a security detail for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
"reputation you gain for this faction, is based on your combat stats. " +
|
||||
"You will gain exp for all combat stats.";
|
||||
const augmentationsInfo = "As your reputation with this faction rises, you will " +
|
||||
"unlock Augmentations, which you can purchase to enhance " +
|
||||
"your abilities.";
|
||||
const sleevePurchasesInfo = "Purchase Duplicate Sleeves and upgrades. These are permanent!";
|
||||
|
||||
const GangNames = [
|
||||
"Slum Snakes",
|
||||
"Tetrads",
|
||||
"The Syndicate",
|
||||
"The Dark Army",
|
||||
"Speakers for the Dead",
|
||||
"NiteSec",
|
||||
"The Black Hand"
|
||||
];
|
||||
|
||||
export class FactionRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
purchasingAugs: props.initiallyOnAugmentationsPage ? props.initiallyOnAugmentationsPage : false,
|
||||
}
|
||||
|
||||
this.manageGang = this.manageGang.bind(this);
|
||||
this.rerender = this.rerender.bind(this);
|
||||
this.routeToMain = this.routeToMain.bind(this);
|
||||
this.routeToPurchaseAugs = this.routeToPurchaseAugs.bind(this);
|
||||
this.sleevePurchases = this.sleevePurchases.bind(this);
|
||||
this.startFieldWork = this.startFieldWork.bind(this);
|
||||
this.startHackingContracts = this.startHackingContracts.bind(this);
|
||||
this.startHackingMission = this.startHackingMission.bind(this);
|
||||
this.startSecurityWork = this.startSecurityWork.bind(this);
|
||||
}
|
||||
|
||||
manageGang() {
|
||||
// If player already has a gang, just go to the gang UI
|
||||
if (this.props.p.inGang()) {
|
||||
return this.props.engine.loadGangContent();
|
||||
}
|
||||
|
||||
// Otherwise, we have to create the gang
|
||||
const facName = this.props.faction.name;
|
||||
let isHacking = false;
|
||||
if (facName === "NiteSec" || facName === "The Black Hand") {
|
||||
isHacking = true;
|
||||
}
|
||||
|
||||
// A Yes/No popup box will allow the player to confirm gang creation
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
const noBtn = yesNoBoxGetNoButton();
|
||||
if (yesBtn == null || noBtn == null) { return; }
|
||||
|
||||
yesBtn.innerHTML = "Create Gang";
|
||||
yesBtn.addEventListener("click", () => {
|
||||
this.props.p.startGang(facName, isHacking);
|
||||
const worldMenuHeader = document.getElementById("world-menu-header");
|
||||
if (worldMenuHeader instanceof HTMLElement) {
|
||||
worldMenuHeader.click(); worldMenuHeader.click();
|
||||
}
|
||||
|
||||
this.props.engine.loadGangContent();
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
noBtn.innerHTML = "Cancel";
|
||||
noBtn.addEventListener("click", () => {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
// Pop-up text
|
||||
let gangTypeText = "";
|
||||
if (isHacking) {
|
||||
gangTypeText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
"Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " +
|
||||
"is not as important.<br><br>";
|
||||
} else {
|
||||
gangTypeText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
|
||||
"is more important. However, well-managed combat gangs can progress faster than hacking ones.<br><br>";
|
||||
}
|
||||
yesNoBoxCreate(`Would you like to create a new Gang with ${facName}?<br><br>` +
|
||||
"Note that this will prevent you from creating a Gang with any other Faction until " +
|
||||
"this BitNode is destroyed. It also resets your reputation with this faction.<br><br>" +
|
||||
gangTypeText +
|
||||
"Other than hacking vs combat, there are NO differences between the Factions you can " +
|
||||
"create a Gang with, and each of these Factions have all Augmentations available.");
|
||||
}
|
||||
|
||||
rerender() {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Route to the main faction page
|
||||
routeToMain() {
|
||||
this.setState({ purchasingAugs: false });
|
||||
}
|
||||
|
||||
// Route to the purchase augmentation UI for this faction
|
||||
routeToPurchaseAugs() {
|
||||
this.setState({ purchasingAugs: true });
|
||||
}
|
||||
|
||||
sleevePurchases() {
|
||||
createSleevePurchasesFromCovenantPopup(this.props.p);
|
||||
}
|
||||
|
||||
startFieldWork() {
|
||||
this.props.p.startFactionFieldWork(this.props.faction);
|
||||
}
|
||||
|
||||
startHackingContracts() {
|
||||
this.props.p.startFactionHackWork(this.props.faction);
|
||||
}
|
||||
|
||||
startHackingMission() {
|
||||
const fac = this.props.faction;
|
||||
this.props.engine.loadMissionContent();
|
||||
this.props.startHackingMissionFn(fac);
|
||||
}
|
||||
|
||||
startSecurityWork() {
|
||||
this.props.p.startFactionSecurityWork(this.props.faction);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.purchasingAugs ? this.renderAugmentationsPage() : this.renderMainPage();
|
||||
}
|
||||
|
||||
renderMainPage() {
|
||||
const p = this.props.p;
|
||||
const faction = this.props.faction;
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
// gang faction because if the player has a gang, they cannot do any other action
|
||||
const isPlayersGang = p.inGang() && (p.getGangName() === faction.name);
|
||||
|
||||
|
||||
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
|
||||
// should be shown
|
||||
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
const canDonate = faction.favor >= favorToDonate;
|
||||
|
||||
const canPurchaseSleeves = (faction.name === "The Covenant" && p.bitNodeN >= 10 && SourceFileFlags[10]);
|
||||
|
||||
let canAccessGang = (p.canAccessGang() && GangNames.includes(faction.name));
|
||||
if (p.inGang() && (p.getGangName() !== faction.name)) {
|
||||
canAccessGang = false;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{faction.name}</h1>
|
||||
<Info
|
||||
faction={faction}
|
||||
factionInfo={factionInfo}
|
||||
/>
|
||||
{
|
||||
canAccessGang &&
|
||||
<Option
|
||||
buttonText={"Manage Gang"}
|
||||
infoText={gangInfo}
|
||||
onClick={this.manageGang}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerHackingMission) &&
|
||||
<Option
|
||||
buttonText={"Hacking Mission"}
|
||||
infoText={hackingMissionInfo}
|
||||
onClick={this.startHackingMission}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerHackingWork) &&
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={this.startHackingContracts}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerFieldWork) &&
|
||||
<Option
|
||||
buttonText={"Field Work"}
|
||||
infoText={fieldWorkInfo}
|
||||
onClick={this.startFieldWork}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && factionInfo.offerSecurityWork) &&
|
||||
<Option
|
||||
buttonText={"Security Work"}
|
||||
infoText={securityWorkInfo}
|
||||
onClick={this.startSecurityWork}
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && canDonate) &&
|
||||
<DonateOption
|
||||
faction={this.props.faction}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
/>
|
||||
}
|
||||
<Option
|
||||
buttonText={"Purchase Augmentations"}
|
||||
infoText={augmentationsInfo}
|
||||
onClick={this.routeToPurchaseAugs}
|
||||
/>
|
||||
{
|
||||
canPurchaseSleeves &&
|
||||
<Option
|
||||
buttonText={"Purchase Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={this.sleevePurchases}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderAugmentationsPage() {
|
||||
return (
|
||||
<div>
|
||||
<AugmentationsPage
|
||||
faction={this.props.faction}
|
||||
p={this.props.p}
|
||||
routeToMainPage={this.routeToMain}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
157
src/Gang.js
157
src/Gang.js
@@ -1,31 +1,39 @@
|
||||
/*
|
||||
Also add police clashes
|
||||
balance point to keep them from running out of control
|
||||
/**
|
||||
* TODO
|
||||
* Add police clashes
|
||||
* balance point to keep them from running out of control
|
||||
*/
|
||||
|
||||
import { gangMemberTasksMetadata } from "./data/gangmembertasks";
|
||||
import { gangMemberUpgradesMetadata } from "./data/gangmemberupgrades";
|
||||
import { gangMemberTasksMetadata } from "./data/gangmembertasks";
|
||||
import { gangMemberUpgradesMetadata } from "./data/gangmemberupgrades";
|
||||
|
||||
import { Engine } from "./engine";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON
|
||||
} from "../utils/JSONReviver";
|
||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
|
||||
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { removeElement } from "../utils/uiHelpers/removeElement";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
import { Engine } from "./engine";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { Reviver, Generic_toJSON,
|
||||
Generic_fromJSON } from "../utils/JSONReviver";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { Page,
|
||||
routing } from "./ui/navigationTracking";
|
||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { removeElement } from "../utils/uiHelpers/removeElement";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
// Constants
|
||||
const GangRespectToReputationRatio = 5; // Respect is divided by this to get rep gain
|
||||
@@ -50,7 +58,7 @@ $(document).keydown(function(event) {
|
||||
}
|
||||
});
|
||||
|
||||
//Delete upgrade box when clicking outside
|
||||
// Delete upgrade box when clicking outside
|
||||
$(document).mousedown(function(event) {
|
||||
var boxId = "gang-member-upgrade-popup-box";
|
||||
var contentId = "gang-member-upgrade-popup-box-content";
|
||||
@@ -66,8 +74,16 @@ $(document).mousedown(function(event) {
|
||||
}
|
||||
});
|
||||
|
||||
let GangNames = ["Slum Snakes", "Tetrads", "The Syndicate", "The Dark Army", "Speakers for the Dead",
|
||||
"NiteSec", "The Black Hand"];
|
||||
const GangNames = [
|
||||
"Slum Snakes",
|
||||
"Tetrads",
|
||||
"The Syndicate",
|
||||
"The Dark Army",
|
||||
"Speakers for the Dead",
|
||||
"NiteSec",
|
||||
"The Black Hand"
|
||||
];
|
||||
|
||||
export let AllGangs = {
|
||||
"Slum Snakes" : {
|
||||
power: 1,
|
||||
@@ -137,12 +153,12 @@ export function loadAllGangs(saveString) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param facName - Name of corresponding faction
|
||||
* @param hacking - Boolean indicating whether or not its a hacking gang
|
||||
* @param facName {string} Name of corresponding faction
|
||||
* @param hacking {bollean} Whether or not its a hacking gang
|
||||
*/
|
||||
export function Gang(facName, hacking=false) {
|
||||
this.facName = facName;
|
||||
this.members = []; //Array of GangMembers
|
||||
this.members = [];
|
||||
this.wanted = 1;
|
||||
this.respect = 1;
|
||||
|
||||
@@ -197,7 +213,7 @@ Gang.prototype.process = 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;
|
||||
for (var i = 0; i < this.members.length; ++i) {
|
||||
respectGains += (this.members[i].calculateRespectGain(this));
|
||||
@@ -291,9 +307,9 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
|
||||
}
|
||||
|
||||
// Then process territory
|
||||
for (var i = 0; i < GangNames.length; ++i) {
|
||||
for (let i = 0; i < GangNames.length; ++i) {
|
||||
const others = GangNames.filter((e) => {
|
||||
return e !== i;
|
||||
return e !== GangNames[i];
|
||||
});
|
||||
const other = getRandomInt(0, others.length - 1);
|
||||
|
||||
@@ -318,6 +334,7 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
|
||||
AllGangs[otherGang].territory -= 0.0001;
|
||||
if (thisGang === gangName) {
|
||||
this.clash(true); // Player won
|
||||
AllGangs[otherGang].power *= (1 / 1.01);
|
||||
} else if (otherGang === gangName) {
|
||||
this.clash(false); // Player lost
|
||||
} else {
|
||||
@@ -333,6 +350,7 @@ Gang.prototype.processTerritoryAndPowerGains = function(numCycles=1) {
|
||||
this.clash(false); // Player lost
|
||||
} else if (otherGang === gangName) {
|
||||
this.clash(true); // Player won
|
||||
AllGangs[thisGang].power *= (1 / 1.01);
|
||||
} else {
|
||||
AllGangs[thisGang].power *= (1 / 1.01);
|
||||
}
|
||||
@@ -562,10 +580,9 @@ Gang.fromJSON = function(value) {
|
||||
|
||||
Reviver.constructors.Gang = Gang;
|
||||
|
||||
/*** Gang Member object ***/
|
||||
function GangMember(name) {
|
||||
this.name = name;
|
||||
this.task = "Unassigned"; //GangMemberTask object
|
||||
this.task = "Unassigned";
|
||||
|
||||
this.earnedRespect = 0;
|
||||
|
||||
@@ -597,11 +614,11 @@ function GangMember(name) {
|
||||
this.agi_asc_mult = 1;
|
||||
this.cha_asc_mult = 1;
|
||||
|
||||
this.upgrades = []; //Names of upgrades
|
||||
this.augmentations = []; //Names only
|
||||
this.upgrades = []; // Names of upgrades
|
||||
this.augmentations = []; // Names of augmentations only
|
||||
}
|
||||
|
||||
//Same formula for Player
|
||||
// Same skill calculation formula as Player
|
||||
GangMember.prototype.calculateSkill = function(exp, mult=1) {
|
||||
return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1);
|
||||
}
|
||||
@@ -645,7 +662,7 @@ GangMember.prototype.getTask = function() {
|
||||
return GangMemberTasks["Unassigned"];
|
||||
}
|
||||
|
||||
//Gains are per cycle
|
||||
// Gains are per cycle
|
||||
GangMember.prototype.calculateRespectGain = function(gang) {
|
||||
const task = this.getTask();
|
||||
if (task == null || !(task instanceof GangMemberTask) || task.baseRespect === 0) {return 0;}
|
||||
@@ -770,9 +787,11 @@ GangMember.prototype.ascend = function() {
|
||||
|
||||
// Returns the multipliers that would be gained from ascension
|
||||
GangMember.prototype.getAscensionResults = function() {
|
||||
// Calculate ascension bonus to stat multipliers.
|
||||
// This is based on the current number of multipliers from Non-Augmentation upgrades
|
||||
// + Ascension Bonus = N% of current bonus from Augmentations
|
||||
/**
|
||||
* Calculate ascension bonus to stat multipliers.
|
||||
* 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 str = 1;
|
||||
let def = 1;
|
||||
@@ -837,7 +856,7 @@ GangMember.fromJSON = function(value) {
|
||||
|
||||
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,
|
||||
params={baseRespect: 0, baseWanted: 0, baseMoney: 0,
|
||||
hackWeight: 0, strWeight: 0, defWeight: 0,
|
||||
@@ -935,7 +954,7 @@ GangMemberUpgrade.prototype.createDescription = function() {
|
||||
this.desc = lines.join("<br>");
|
||||
}
|
||||
|
||||
//Passes in a GangMember object
|
||||
// Passes in a GangMember object
|
||||
GangMemberUpgrade.prototype.apply = function(member) {
|
||||
if (this.mults.str != null) { member.str_mult *= this.mults.str; }
|
||||
if (this.mults.def != null) { member.def_mult *= this.mults.def; }
|
||||
@@ -971,7 +990,7 @@ gangMemberUpgradesMetadata.forEach((e) => {
|
||||
Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
|
||||
const boxId = "gang-member-upgrade-popup-box";
|
||||
if (UIElems.gangMemberUpgradeBoxOpened) {
|
||||
//Already opened, refreshing
|
||||
// Already opened, refreshing
|
||||
if (UIElems.gangMemberUpgradeBoxElements == null || UIElems.gangMemberUpgradeBox == null || UIElems.gangMemberUpgradeBoxContent == null) {
|
||||
console.error("Refreshing Gang member upgrade box throws error because required elements are null");
|
||||
return;
|
||||
@@ -991,7 +1010,7 @@ Gang.prototype.createGangMemberUpgradeBox = function(player, initialFilter="") {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//New popup
|
||||
// New popup
|
||||
UIElems.gangMemberUpgradeBoxFilter = createElement("input", {
|
||||
type:"text", placeholder:"Filter gang members",
|
||||
value:initialFilter,
|
||||
@@ -1023,7 +1042,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) {
|
||||
var container = createElement("div", {
|
||||
border:"1px solid white",
|
||||
@@ -1045,7 +1064,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
|
||||
"Cha: " + this.cha + " (x" + formatNumber(this.cha_mult * this.cha_asc_mult, 2) + ")\n",
|
||||
});
|
||||
|
||||
//Already purchased upgrades
|
||||
// Already purchased upgrades
|
||||
const ownedUpgradesElements = [];
|
||||
function pushOwnedUpgrade(upgName) {
|
||||
const upg = GangMemberUpgrades[upgName];
|
||||
@@ -1071,7 +1090,7 @@ GangMember.prototype.createGangMemberUpgradePanel = function(gangObj, player) {
|
||||
container.appendChild(ownedUpgrades);
|
||||
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 armorUpgrades = [];
|
||||
const vehicleUpgrades = [];
|
||||
@@ -1203,18 +1222,18 @@ Gang.prototype.displayGangContent = function(player) {
|
||||
if (!UIElems.gangContentCreated || UIElems.gangContainer == null) {
|
||||
UIElems.gangContentCreated = true;
|
||||
|
||||
//Create gang container
|
||||
// Create gang container
|
||||
UIElems.gangContainer = createElement("div", {
|
||||
id:"gang-container", class:"generic-menupage-container",
|
||||
});
|
||||
|
||||
//Get variables
|
||||
// Get variables
|
||||
var facName = this.facName,
|
||||
members = this.members,
|
||||
wanted = this.wanted,
|
||||
respect = this.respect;
|
||||
|
||||
//Back button
|
||||
// Back button
|
||||
UIElems.gangContainer.appendChild(createElement("a", {
|
||||
class:"a-link-button", display:"inline-block", innerText:"Back",
|
||||
clickListener:()=>{
|
||||
@@ -1224,7 +1243,7 @@ Gang.prototype.displayGangContent = function(player) {
|
||||
}
|
||||
}));
|
||||
|
||||
//Buttons to switch between panels
|
||||
// Buttons to switch between panels
|
||||
UIElems.managementButton = createElement("a", {
|
||||
id:"gang-management-subpage-button", class:"a-link-button-inactive",
|
||||
display:"inline-block", innerHTML: "Gang Management (Alt+1)",
|
||||
@@ -1256,7 +1275,7 @@ Gang.prototype.displayGangContent = function(player) {
|
||||
UIElems.gangContainer.appendChild(UIElems.managementButton);
|
||||
UIElems.gangContainer.appendChild(UIElems.territoryButton);
|
||||
|
||||
//Subpage for managing gang members
|
||||
// Subpage for managing gang members
|
||||
UIElems.gangManagementSubpage = createElement("div", {
|
||||
display:"block", id:"gang-management-subpage",
|
||||
});
|
||||
@@ -1352,7 +1371,7 @@ Gang.prototype.displayGangContent = function(player) {
|
||||
});
|
||||
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.gangExpandAllButton = createElement("a", {
|
||||
class:"a-link-button", display:"inline-block",
|
||||
@@ -1400,17 +1419,17 @@ Gang.prototype.displayGangContent = function(player) {
|
||||
UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberFilter);
|
||||
UIElems.gangManagementSubpage.appendChild(UIElems.gangManageEquipmentButton);
|
||||
|
||||
//Gang Member list
|
||||
// Gang Member list
|
||||
UIElems.gangMemberList = createElement("ul", {id:"gang-member-list"});
|
||||
this.displayGangMemberList();
|
||||
UIElems.gangManagementSubpage.appendChild(UIElems.gangMemberList);
|
||||
|
||||
//Subpage for seeing gang territory information
|
||||
// Subpage for seeing gang territory information
|
||||
UIElems.gangTerritorySubpage = createElement("div", {
|
||||
id:"gang-territory-subpage", display:"none"
|
||||
});
|
||||
|
||||
//Info text for territory page
|
||||
// Info text for territory page
|
||||
UIElems.gangTerritoryDescText = createElement("p", {
|
||||
width:"70%",
|
||||
innerHTML:
|
||||
@@ -1575,7 +1594,7 @@ Gang.prototype.updateGangContent = function() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Update information for overall gang
|
||||
// Update information for overall gang
|
||||
if (UIElems.gangInfo instanceof Element) {
|
||||
var faction = Factions[this.facName];
|
||||
var rep;
|
||||
@@ -1585,7 +1604,7 @@ Gang.prototype.updateGangContent = function() {
|
||||
rep = faction.playerReputation;
|
||||
}
|
||||
removeChildrenFromElement(UIElems.gangInfo);
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Respect
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Respect
|
||||
display: "inline-block",
|
||||
innerText: "Respect: " + formatNumber(this.respect, 6) +
|
||||
" (" + formatNumber(5*this.respectGainRate, 6) + " / sec)",
|
||||
@@ -1596,7 +1615,7 @@ Gang.prototype.updateGangContent = function() {
|
||||
}));
|
||||
UIElems.gangInfo.appendChild(createElement("br"));
|
||||
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Wanted level
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Wanted level
|
||||
display: "inline-block",
|
||||
innerText: "Wanted Level: " + formatNumber(this.wanted, 6) +
|
||||
" (" + formatNumber(5*this.wantedGainRate, 6) + " / sec)",
|
||||
@@ -1608,20 +1627,20 @@ Gang.prototype.updateGangContent = function() {
|
||||
|
||||
var wantedPenalty = this.getWantedPenalty();
|
||||
wantedPenalty = (1 - wantedPenalty) * 100;
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Wanted Level multiplier
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Wanted Level multiplier
|
||||
display: "inline-block",
|
||||
innerText: `Wanted Level Penalty: -${formatNumber(wantedPenalty, 2)}%`,
|
||||
tooltip: "Penalty for respect and money gain rates due to Wanted Level"
|
||||
}));
|
||||
UIElems.gangInfo.appendChild(createElement("br"));
|
||||
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Money gain rate
|
||||
UIElems.gangInfo.appendChild(createElement("p", { // Money gain rate
|
||||
display: "inline-block",
|
||||
innerText: `Money gain rate: ${numeralWrapper.format(5 * this.moneyGainRate, "$0.000a")} / sec`,
|
||||
}));
|
||||
UIElems.gangInfo.appendChild(createElement("br"));
|
||||
|
||||
//Fix some rounding issues graphically
|
||||
// Fix some rounding issues graphically
|
||||
var territoryMult = AllGangs[this.facName].territory * 100;
|
||||
let displayNumber;
|
||||
if (territoryMult <= 0) {
|
||||
@@ -1656,7 +1675,7 @@ Gang.prototype.updateGangContent = function() {
|
||||
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 respectCost = this.getRespectNeededToRecruitMember();
|
||||
|
||||
@@ -1674,14 +1693,14 @@ Gang.prototype.updateGangContent = function() {
|
||||
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) {
|
||||
this.updateGangMemberDisplayElement(this.members[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Takes in a GangMember object
|
||||
// Takes in a GangMember object
|
||||
Gang.prototype.createGangMemberDisplayElement = function(memberObj) {
|
||||
if (!UIElems.gangContentCreated) { return; }
|
||||
const name = memberObj.name;
|
||||
@@ -1822,7 +1841,7 @@ Gang.prototype.createGangMemberDisplayElement = function(memberObj) {
|
||||
taskDiv.appendChild(taskSelector);
|
||||
taskDiv.appendChild(gainInfo);
|
||||
|
||||
//Panel for Description of task
|
||||
// Panel for Description of task
|
||||
var taskDescDiv = createElement("div", {
|
||||
class:"gang-member-info-div",
|
||||
id: name + "gang-member-task-desc",
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
* to TypeScript at the moment
|
||||
*/
|
||||
export interface IEngine {
|
||||
hideAllContent: () => void;
|
||||
loadBladeburnerContent: () => void;
|
||||
loadFactionContent: () => void;
|
||||
loadFactionsContent: () => void;
|
||||
loadGangContent: () => void;
|
||||
loadInfiltrationContent: () => void;
|
||||
loadMissionContent: () => void;
|
||||
loadResleevingContent: () => void;
|
||||
loadStockMarketContent: () => void;
|
||||
}
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { infiltrationBoxCreate } from "../utils/InfiltrationBox";
|
||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
|
||||
/* Infiltration.js
|
||||
*
|
||||
* Kill
|
||||
* Knockout (nonlethal)
|
||||
* Stealth Knockout (nonlethal)
|
||||
* Assassinate
|
||||
*
|
||||
* Hack Security
|
||||
* Destroy Security
|
||||
* Sneak past Security
|
||||
*
|
||||
* Pick the locked door
|
||||
*
|
||||
* Bribe security
|
||||
*
|
||||
* Escape
|
||||
*/
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { infiltrationBoxCreate } from "../utils/InfiltrationBox";
|
||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
|
||||
let InfiltrationScenarios = {
|
||||
Guards: "You see an armed security guard patrolling the area.",
|
||||
@@ -35,21 +17,21 @@ let InfiltrationScenarios = {
|
||||
}
|
||||
|
||||
function InfiltrationInstance(companyName, startLevel, val, maxClearance, diff) {
|
||||
this.companyName = companyName;
|
||||
this.clearanceLevel = 0;
|
||||
this.maxClearanceLevel = maxClearance;
|
||||
this.securityLevel = startLevel;
|
||||
this.difficulty = diff; //Affects how much security level increases. Represents a percentage
|
||||
this.baseValue = val; //Base value of company secrets
|
||||
this.secretsStolen = []; //Numbers representing value of stolen secrets
|
||||
this.companyName = companyName;
|
||||
this.clearanceLevel = 0;
|
||||
this.maxClearanceLevel = maxClearance;
|
||||
this.securityLevel = startLevel;
|
||||
this.difficulty = diff; // Affects how much security level increases. Represents a percentage
|
||||
this.baseValue = val; // Base value of company secrets
|
||||
this.secretsStolen = []; // Numbers representing value of stolen secrets
|
||||
|
||||
this.hackingExpGained = 0;
|
||||
this.strExpGained = 0;
|
||||
this.defExpGained = 0;
|
||||
this.dexExpGained = 0;
|
||||
this.agiExpGained = 0;
|
||||
this.chaExpGained = 0;
|
||||
this.intExpGained = 0;
|
||||
this.hackingExpGained = 0;
|
||||
this.strExpGained = 0;
|
||||
this.defExpGained = 0;
|
||||
this.dexExpGained = 0;
|
||||
this.agiExpGained = 0;
|
||||
this.chaExpGained = 0;
|
||||
this.intExpGained = 0;
|
||||
}
|
||||
|
||||
InfiltrationInstance.prototype.expMultiplier = function() {
|
||||
@@ -124,7 +106,7 @@ InfiltrationInstance.prototype.gainIntelligenceExp = function(amt) {
|
||||
|
||||
InfiltrationInstance.prototype.calcGainedIntelligenceExp = function() {
|
||||
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) {
|
||||
@@ -177,7 +159,7 @@ function nextInfiltrationLevel(inst) {
|
||||
bribeButton.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;
|
||||
switch (rand) {
|
||||
case 1:
|
||||
@@ -460,7 +442,7 @@ function nextInfiltrationLevel(inst) {
|
||||
|
||||
|
||||
function endInfiltrationLevel(inst) {
|
||||
//Check if you gained any secrets
|
||||
// Check if you gained any secrets
|
||||
if (inst.clearanceLevel % 5 == 0) {
|
||||
var baseSecretValue = inst.baseValue * inst.clearanceLevel / 2;
|
||||
var secretValue = baseSecretValue * Player.faction_rep_mult *
|
||||
@@ -474,12 +456,12 @@ function endInfiltrationLevel(inst) {
|
||||
"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));
|
||||
writeInfiltrationStatusText("You move on to the facility's next clearance level. This " +
|
||||
"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) {
|
||||
endInfiltration(inst, true);
|
||||
} else {
|
||||
@@ -647,8 +629,8 @@ function updateInfiltrationButtons(inst, scenario) {
|
||||
|
||||
let intWgt = CONSTANTS.IntelligenceInfiltrationWeight;
|
||||
|
||||
//Kill
|
||||
//Success: 5%, Failure 10%, -Karma
|
||||
// Kill
|
||||
// Success: 5%, Failure 10%, -Karma
|
||||
function attemptInfiltrationKill(inst) {
|
||||
var chance = getInfiltrationKillChance(inst);
|
||||
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
|
||||
@@ -673,8 +655,8 @@ function getInfiltrationKillChance(inst) {
|
||||
}
|
||||
|
||||
|
||||
//Knockout
|
||||
//Success: 3%, Failure: 10%
|
||||
// Knockout
|
||||
// Success: 3%, Failure: 10%
|
||||
function attemptInfiltrationKnockout(inst) {
|
||||
var chance = getInfiltrationKnockoutChance(inst);
|
||||
inst.gainStrengthExp(inst.securityLevel / 70) * Player.strength_exp_mult;
|
||||
@@ -698,8 +680,8 @@ function getInfiltrationKnockoutChance(inst) {
|
||||
Player.agility) / (1.7 * lvl));
|
||||
}
|
||||
|
||||
//Stealth knockout
|
||||
//Success: 0%, Failure: 10%
|
||||
// Stealth knockout
|
||||
// Success: 0%, Failure: 10%
|
||||
function attemptInfiltrationStealthKnockout(inst) {
|
||||
var chance = getInfiltrationStealthKnockoutChance(inst);
|
||||
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
|
||||
@@ -722,8 +704,8 @@ function getInfiltrationStealthKnockoutChance(inst) {
|
||||
intWgt * Player.intelligence) / (3 * lvl));
|
||||
}
|
||||
|
||||
//Assassination
|
||||
//Success: 0%, Failure: 5%, -Karma
|
||||
// Assassination
|
||||
// Success: 0%, Failure: 5%, -Karma
|
||||
function attemptInfiltrationAssassinate(inst) {
|
||||
var chance = getInfiltrationAssassinateChance(inst);
|
||||
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
|
||||
@@ -746,8 +728,8 @@ function getInfiltrationAssassinateChance(inst) {
|
||||
}
|
||||
|
||||
|
||||
//Destroy security
|
||||
//Success: 5%, Failure: 10%
|
||||
// Destroy security
|
||||
// Success: 5%, Failure: 10%
|
||||
function attemptInfiltrationDestroySecurity(inst) {
|
||||
var chance = getInfiltrationDestroySecurityChance(inst);
|
||||
inst.gainStrengthExp(inst.securityLevel / 75) * Player.strength_exp_mult;
|
||||
@@ -773,8 +755,8 @@ function getInfiltrationDestroySecurityChance(inst) {
|
||||
}
|
||||
|
||||
|
||||
//Hack security
|
||||
//Success: 3%, Failure: 5%
|
||||
// Hack security
|
||||
// Success: 3%, Failure: 5%
|
||||
function attemptInfiltrationHack(inst) {
|
||||
var chance = getInfiltrationHackChance(inst);
|
||||
inst.gainHackingExp(inst.securityLevel / 30) * Player.hacking_exp_mult;
|
||||
@@ -796,8 +778,8 @@ function getInfiltrationHackChance(inst) {
|
||||
(intWgt * Player.intelligence)) / lvl);
|
||||
}
|
||||
|
||||
//Sneak past security
|
||||
//Success: 0%, Failure: 8%
|
||||
// Sneak past security
|
||||
// Success: 0%, Failure: 8%
|
||||
function attemptInfiltrationSneak(inst) {
|
||||
var chance = getInfiltrationSneakChance(inst);
|
||||
inst.gainAgilityExp(inst.securityLevel / 30) * Player.agility_exp_mult;
|
||||
@@ -817,8 +799,8 @@ function getInfiltrationSneakChance(inst) {
|
||||
intWgt * Player.intelligence) / (2 * lvl));
|
||||
}
|
||||
|
||||
//Pick locked door
|
||||
//Success: 1%, Failure: 3%
|
||||
// Pick locked door
|
||||
// Success: 1%, Failure: 3%
|
||||
function attemptInfiltrationPickLockedDoor(inst) {
|
||||
var chance = getInfiltrationPickLockedDoorChance(inst);
|
||||
inst.gainDexterityExp(inst.securityLevel / 25) * Player.dexterity_exp_mult;
|
||||
@@ -838,8 +820,8 @@ function getInfiltrationPickLockedDoorChance(inst) {
|
||||
intWgt * Player.intelligence) / lvl);
|
||||
}
|
||||
|
||||
//Bribe
|
||||
//Success: 0%, Failure: 15%,
|
||||
// Bribe
|
||||
// Success: 0%, Failure: 15%,
|
||||
function attemptInfiltrationBribe(inst) {
|
||||
var chance = getInfiltrationBribeChance(inst);
|
||||
inst.gainCharismaExp(inst.securityLevel / 8) * Player.charisma_exp_mult;
|
||||
@@ -857,8 +839,8 @@ function getInfiltrationBribeChance(inst) {
|
||||
(Player.charisma) / lvl);
|
||||
}
|
||||
|
||||
//Escape
|
||||
//Failure: 5%
|
||||
// Escape
|
||||
// Failure: 5%
|
||||
function attemptInfiltrationEscape(inst) {
|
||||
var chance = getInfiltrationEscapeChance(inst);
|
||||
inst.gainAgilityExp(inst.securityLevel / 30) * Player.agility_exp_mult;
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { initializeMainMenuLinks } from "./ui/MainMenu/Links";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
|
||||
//Ordered array of keys to Interactive Tutorial Steps
|
||||
import { initializeMainMenuLinks } from "./ui/MainMenu/Links";
|
||||
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
|
||||
// Ordered array of keys to Interactive Tutorial Steps
|
||||
const orderedITutorialSteps = [
|
||||
"Start",
|
||||
"GoToCharacterPage", //Click on 'Stats' page
|
||||
"CharacterPage", //Introduction to 'Stats' page
|
||||
"CharacterGoToTerminalPage", //Go back to Terminal
|
||||
"TerminalIntro", //Introduction to Terminal
|
||||
"TerminalHelp", //Using 'help' Terminal command
|
||||
"TerminalLs", //Using 'ls' Terminal command
|
||||
"TerminalScan", //Using 'scan' Terminal command
|
||||
"TerminalScanAnalyze1", //Using 'scan-analyze' Terminal command
|
||||
"TerminalScanAnalyze2", //Using 'scan-analyze 3' Terminal command
|
||||
"TerminalConnect", //Connecting to foodnstuff
|
||||
"TerminalAnalyze", //Analyzing foodnstuff
|
||||
"TerminalNuke", //NUKE foodnstuff
|
||||
"TerminalManualHack", //Hack foodnstuff
|
||||
"TerminalHackingMechanics", //Explanation of hacking mechanics
|
||||
"TerminalCreateScript", //Create a script using 'nano'
|
||||
"TerminalTypeScript", //Script Editor page - Type script and then save & close
|
||||
"TerminalFree", //Using 'Free' Terminal command
|
||||
"TerminalRunScript", //Running script using 'run' Terminal command
|
||||
"GoToCharacterPage", // Click on 'Stats' page
|
||||
"CharacterPage", // Introduction to 'Stats' page
|
||||
"CharacterGoToTerminalPage", // Go back to Terminal
|
||||
"TerminalIntro", // Introduction to Terminal
|
||||
"TerminalHelp", // Using 'help' Terminal command
|
||||
"TerminalLs", // Using 'ls' Terminal command
|
||||
"TerminalScan", // Using 'scan' Terminal command
|
||||
"TerminalScanAnalyze1", // Using 'scan-analyze' Terminal command
|
||||
"TerminalScanAnalyze2", // Using 'scan-analyze 3' Terminal command
|
||||
"TerminalConnect", // Connecting to foodnstuff
|
||||
"TerminalAnalyze", // Analyzing foodnstuff
|
||||
"TerminalNuke", // NUKE foodnstuff
|
||||
"TerminalManualHack", // Hack foodnstuff
|
||||
"TerminalHackingMechanics", // Explanation of hacking mechanics
|
||||
"TerminalCreateScript", // Create a script using 'nano'
|
||||
"TerminalTypeScript", // Script Editor page - Type script and then save & close
|
||||
"TerminalFree", // Using 'Free' Terminal command
|
||||
"TerminalRunScript", // Running script using 'run' Terminal command
|
||||
"TerminalGoToActiveScriptsPage",
|
||||
"ActiveScriptsPage",
|
||||
"ActiveScriptsToTerminal",
|
||||
@@ -41,22 +44,22 @@ const orderedITutorialSteps = [
|
||||
"End"
|
||||
]
|
||||
|
||||
//Create an 'enum' for the Steps
|
||||
// Create an 'enum' for the Steps
|
||||
const iTutorialSteps = {};
|
||||
for (let i = 0; i < orderedITutorialSteps.length; ++i) {
|
||||
iTutorialSteps[orderedITutorialSteps[i]] = i;
|
||||
}
|
||||
|
||||
var ITutorial = {
|
||||
currStep: 0, //iTutorialSteps.Start
|
||||
currStep: 0, // iTutorialSteps.Start
|
||||
isRunning: false,
|
||||
|
||||
//Keeps track of whether each step has been done
|
||||
// Keeps track of whether each step has been done
|
||||
stepIsDone: {},
|
||||
}
|
||||
|
||||
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 = {};
|
||||
for (let i = 0; i < orderedITutorialSteps.length; ++i) {
|
||||
ITutorial.stepIsDone[i] = false;
|
||||
@@ -64,7 +67,7 @@ function iTutorialStart() {
|
||||
|
||||
Engine.loadTerminalContent();
|
||||
|
||||
//Don't autosave during this interactive tutorial
|
||||
// Don't autosave during this interactive tutorial
|
||||
Engine.Counters.autoSaveCounter = Infinity;
|
||||
console.log("Interactive Tutorial started");
|
||||
ITutorial.currStep = 0;
|
||||
@@ -72,21 +75,21 @@ function iTutorialStart() {
|
||||
|
||||
document.getElementById("interactive-tutorial-container").style.display = "block";
|
||||
|
||||
//Exit tutorial button
|
||||
// Exit tutorial button
|
||||
var exitButton = clearEventListeners("interactive-tutorial-exit");
|
||||
exitButton.addEventListener("click", function() {
|
||||
iTutorialEnd();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Back button
|
||||
// Back button
|
||||
var backButton = clearEventListeners("interactive-tutorial-back");
|
||||
backButton.addEventListener("click", function() {
|
||||
iTutorialPrevStep();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Next button
|
||||
// Next button
|
||||
var nextButton = clearEventListeners("interactive-tutorial-next");
|
||||
nextButton.addEventListener("click", function() {
|
||||
iTutorialNextStep();
|
||||
@@ -99,7 +102,7 @@ function iTutorialStart() {
|
||||
function iTutorialEvaluateStep() {
|
||||
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 statsMainMenu = clearEventListeners("stats-menu-link");
|
||||
var activeScriptsMainMenu = clearEventListeners("active-scripts-menu-link");
|
||||
@@ -113,7 +116,7 @@ function iTutorialEvaluateStep() {
|
||||
cityMainMenu.removeAttribute("class");
|
||||
tutorialMainMenu.removeAttribute("class");
|
||||
|
||||
//Interactive Tutorial Next button
|
||||
// Interactive Tutorial Next button
|
||||
var nextBtn = document.getElementById("interactive-tutorial-next");
|
||||
|
||||
switch(ITutorial.currStep) {
|
||||
@@ -131,7 +134,7 @@ function iTutorialEvaluateStep() {
|
||||
"the main navigation menu (left-hand side of the screen)");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadCharacterContent();
|
||||
@@ -151,7 +154,7 @@ function iTutorialEvaluateStep() {
|
||||
"main navigation menu.");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadTerminalContent();
|
||||
@@ -169,13 +172,13 @@ function iTutorialEvaluateStep() {
|
||||
Engine.loadTerminalContent();
|
||||
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)");
|
||||
nextBtn.style.display = "none"; //next step triggered by terminal command
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalLs:
|
||||
Engine.loadTerminalContent();
|
||||
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");
|
||||
nextBtn.style.display = "none"; //next step triggered by terminal command
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalScan:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -184,7 +187,7 @@ function iTutorialEvaluateStep() {
|
||||
"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 " +
|
||||
"the 'scan' command.");
|
||||
nextBtn.style.display = "none"; //next step triggered by terminal command
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalScanAnalyze1:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -194,7 +197,7 @@ function iTutorialEvaluateStep() {
|
||||
"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 " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalScanAnalyze2:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -202,7 +205,7 @@ function iTutorialEvaluateStep() {
|
||||
"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 " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalConnect:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -212,7 +215,7 @@ function iTutorialEvaluateStep() {
|
||||
"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 " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalAnalyze:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -221,7 +224,7 @@ function iTutorialEvaluateStep() {
|
||||
"on servers and computers. Using your hacking abilities, you can hack servers " +
|
||||
"to steal money and gain experience. <br><br> " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalNuke:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -233,13 +236,13 @@ function iTutorialEvaluateStep() {
|
||||
"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 " +
|
||||
"'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;
|
||||
case iTutorialSteps.TerminalManualHack:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText("You now have root access! You can hack the server using the 'hack' command. " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalHackingMechanics:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -262,7 +265,7 @@ function iTutorialEvaluateStep() {
|
||||
"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" +
|
||||
" 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;
|
||||
case iTutorialSteps.TerminalTypeScript:
|
||||
Engine.loadScriptEditorContent("foodnstuff.script", "");
|
||||
@@ -278,7 +281,7 @@ function iTutorialEvaluateStep() {
|
||||
"For anyone with basic programming experience, this code should be straightforward. " +
|
||||
"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.");
|
||||
nextBtn.style.display = "none"; //next step triggered in saveAndCloseScriptEditor() (Script.js)
|
||||
nextBtn.style.display = "none"; // next step triggered in saveAndCloseScriptEditor() (Script.js)
|
||||
break;
|
||||
case iTutorialSteps.TerminalFree:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -286,13 +289,13 @@ function iTutorialEvaluateStep() {
|
||||
"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 " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalRunScript:
|
||||
Engine.loadTerminalContent();
|
||||
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'.");
|
||||
nextBtn.style.display = "none"; //next step triggered by terminal commmand
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal commmand
|
||||
break;
|
||||
case iTutorialSteps.TerminalGoToActiveScriptsPage:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -306,7 +309,7 @@ function iTutorialEvaluateStep() {
|
||||
"'Active Scripts' link in the main navigation menu.");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadActiveScriptsContent();
|
||||
@@ -322,7 +325,7 @@ function iTutorialEvaluateStep() {
|
||||
"link.");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadTerminalContent();
|
||||
@@ -335,7 +338,7 @@ function iTutorialEvaluateStep() {
|
||||
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 " +
|
||||
"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;
|
||||
case iTutorialSteps.TerminalTailScript:
|
||||
Engine.loadTerminalContent();
|
||||
@@ -356,7 +359,7 @@ function iTutorialEvaluateStep() {
|
||||
"the 'Hacknet Nodes' page through the main navigation menu now.");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadHacknetNodesContent();
|
||||
@@ -368,7 +371,7 @@ function iTutorialEvaluateStep() {
|
||||
Engine.loadHacknetNodesContent();
|
||||
iTutorialSetText("From this page you can purchase new Hacknet Nodes and upgrade your " +
|
||||
"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;
|
||||
case iTutorialSteps.HacknetNodesGoToWorldPage:
|
||||
Engine.loadHacknetNodesContent();
|
||||
@@ -379,7 +382,7 @@ function iTutorialEvaluateStep() {
|
||||
"Let's go to the 'City' page through the main navigation menu.");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadLocationContent();
|
||||
@@ -396,7 +399,7 @@ function iTutorialEvaluateStep() {
|
||||
"Lastly, click on the 'Tutorial' link in the main navigation menu.");
|
||||
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.addEventListener("click", function() {
|
||||
Engine.loadTutorialContent();
|
||||
@@ -425,9 +428,9 @@ function iTutorialEvaluateStep() {
|
||||
}
|
||||
}
|
||||
|
||||
//Go to the next step and evaluate it
|
||||
// Go to the next step and evaluate it
|
||||
function iTutorialNextStep() {
|
||||
//Special behavior for certain steps
|
||||
// Special behavior for certain steps
|
||||
if (ITutorial.currStep === iTutorialSteps.GoToCharacterPage) {
|
||||
document.getElementById("stats-menu-link").removeAttribute("class");
|
||||
}
|
||||
@@ -457,7 +460,7 @@ function iTutorialNextStep() {
|
||||
iTutorialEvaluateStep();
|
||||
}
|
||||
|
||||
//Go to previous step and evaluate
|
||||
// Go to previous step and evaluate
|
||||
function iTutorialPrevStep() {
|
||||
if (ITutorial.currStep > iTutorialSteps.Start) {
|
||||
ITutorial.currStep -= 1;
|
||||
@@ -466,7 +469,7 @@ function iTutorialPrevStep() {
|
||||
}
|
||||
|
||||
function iTutorialEnd() {
|
||||
//Re-enable auto save
|
||||
// Re-enable auto save
|
||||
if (Settings.AutosaveInterval === 0) {
|
||||
Engine.Counters.autoSaveCounter = Infinity;
|
||||
} else {
|
||||
@@ -491,7 +494,7 @@ function iTutorialEnd() {
|
||||
ITutorial.isRunning = false;
|
||||
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 txt = createElement("p", {
|
||||
innerHTML:
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
|
||||
/* Literature.js
|
||||
* Lore / world building literature that can be found on servers
|
||||
/**
|
||||
* Lore / world building literature files that can be found on servers.
|
||||
* These files can be read by the player
|
||||
*/
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
|
||||
function Literature(title, filename, txt) {
|
||||
this.title = title;
|
||||
this.fn = filename;
|
||||
@@ -10,10 +11,9 @@ function Literature(title, filename, txt) {
|
||||
}
|
||||
|
||||
function showLiterature(fn) {
|
||||
var litObj = Literatures[fn];
|
||||
if (litObj == null) {return;}
|
||||
var txt = "<i>" + litObj.title + "</i><br><br>" +
|
||||
litObj.txt;
|
||||
const litObj = Literatures[fn];
|
||||
if (litObj == null) { return; }
|
||||
const txt = `<i>${litObj.title}</i><br><br>${litObj.txt}`;
|
||||
dialogBoxCreate(txt);
|
||||
}
|
||||
|
||||
@@ -430,7 +430,10 @@ function initLiterature() {
|
||||
fn = "the-secret-war.lit";
|
||||
txt = ""
|
||||
Literatures[fn] = new Literature(title, fn, txt);
|
||||
|
||||
}
|
||||
|
||||
export {Literatures, initLiterature, showLiterature};
|
||||
export {
|
||||
Literatures,
|
||||
initLiterature,
|
||||
showLiterature
|
||||
};
|
||||
|
||||
@@ -108,7 +108,7 @@ export function createPurchaseServerPopup(ram: number, p: IPlayer) {
|
||||
* Create a popup that lets the player start a Corporation
|
||||
*/
|
||||
export function createStartCorporationPopup(p: IPlayer) {
|
||||
if (!p.canAccessCorporation() || p.hasCorporation) { return; }
|
||||
if (!p.canAccessCorporation() || p.hasCorporation()) { return; }
|
||||
|
||||
const popupId = "create-corporation-popup";
|
||||
const txt = createElement("p", {
|
||||
|
||||
324
src/Missions.js
324
src/Missions.js
@@ -1,16 +1,21 @@
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||
import { Player } from "./Player";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { addOffset } from "../utils/helpers/addOffset";
|
||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
import jsplumb from 'jsplumb'
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||
import { Player } from "./Player";
|
||||
|
||||
let inMission = false; //Flag to denote whether a mission is running
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||
|
||||
import { addOffset } from "../utils/helpers/addOffset";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
|
||||
import jsplumb from "jsplumb";
|
||||
|
||||
|
||||
let inMission = false; // Flag to denote whether a mission is running
|
||||
let currMission = null;
|
||||
function setInMission(bool, mission) {
|
||||
inMission = bool;
|
||||
@@ -21,26 +26,26 @@ function setInMission(bool, mission) {
|
||||
}
|
||||
}
|
||||
|
||||
//Keyboard shortcuts
|
||||
// Keyboard shortcuts
|
||||
$(document).keydown(function(e) {
|
||||
if (inMission && currMission && currMission.selectedNode.length != 0) {
|
||||
switch (e.keyCode) {
|
||||
case 65: //a for Attack
|
||||
case 65: // a for Attack
|
||||
currMission.actionButtons[0].click();
|
||||
break;
|
||||
case 83: //s for Scan
|
||||
case 83: // s for Scan
|
||||
currMission.actionButtons[1].click();
|
||||
break;
|
||||
case 87: //w for Weaken
|
||||
case 87: // w for Weaken
|
||||
currMission.actionButtons[2].click();
|
||||
break;
|
||||
case 70: //f for Fortify
|
||||
case 70: // f for Fortify
|
||||
currMission.actionButtons[3].click();
|
||||
break;
|
||||
case 82: //r for Overflow
|
||||
case 82: // r for Overflow
|
||||
currMission.actionButtons[4].click();
|
||||
break;
|
||||
case 68: //d for Detach connection
|
||||
case 68: // d for Detach connection
|
||||
currMission.actionButtons[5].click();
|
||||
break;
|
||||
default:
|
||||
@@ -50,20 +55,20 @@ $(document).keydown(function(e) {
|
||||
});
|
||||
|
||||
let NodeTypes = {
|
||||
Core: "CPU Core Node", //All actions available
|
||||
Firewall: "Firewall Node", //No actions available
|
||||
Database: "Database Node", //No actions available
|
||||
Spam: "Spam Node", //No actions Available
|
||||
Transfer: "Transfer Node", //Can Weaken, Scan, Fortify and Overflow
|
||||
Shield: "Shield Node" //Can Fortify
|
||||
Core: "CPU Core Node", // All actions available
|
||||
Firewall: "Firewall Node", // No actions available
|
||||
Database: "Database Node", // No actions available
|
||||
Spam: "Spam Node", // No actions Available
|
||||
Transfer: "Transfer Node", // Can Weaken, Scan, Fortify and Overflow
|
||||
Shield: "Shield Node" // Can Fortify
|
||||
}
|
||||
|
||||
let NodeActions = {
|
||||
Attack: "Attacking", //Damaged based on attack stat + hacking level + opp def
|
||||
Scan: "Scanning", //-Def 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
|
||||
Overflow: "Overflowing", //+Attack but -Defense for Node, affected by hacking level
|
||||
Attack: "Attacking", // Damaged based on attack stat + hacking level + opp def
|
||||
Scan: "Scanning", // -Def 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
|
||||
Overflow: "Overflowing", // +Attack but -Defense for Node, affected by hacking level
|
||||
}
|
||||
|
||||
function Node(type, stats) {
|
||||
@@ -74,14 +79,15 @@ function Node(type, stats) {
|
||||
this.maxhp = this.hp;
|
||||
this.plyrCtrl = false;
|
||||
this.enmyCtrl = false;
|
||||
this.pos = [0, 0]; //x, y
|
||||
this.el = null; //Holds the Node's DOM element
|
||||
this.pos = [0, 0]; // x, y
|
||||
this.el = null; // Holds the Node's DOM element
|
||||
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
|
||||
//can only have 1 outgoing Connection)
|
||||
/**
|
||||
* Holds the JsPlumb Connection object for this Node, where this Node is the Source (since each Node
|
||||
* can only have 1 outgoing Connection)
|
||||
*/
|
||||
this.conn = null;
|
||||
}
|
||||
|
||||
@@ -107,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) {
|
||||
if (this.enmyCtrl) {return;}
|
||||
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) {
|
||||
actionButtons[i].classList.remove("a-link-button");
|
||||
actionButtons[i].classList.add("a-link-button-inactive");
|
||||
@@ -120,7 +126,7 @@ Node.prototype.select = function(actionButtons) {
|
||||
|
||||
switch(this.type) {
|
||||
case NodeTypes.Core:
|
||||
//All buttons active
|
||||
// All buttons active
|
||||
for (var i = 0; i < actionButtons.length; ++i) {
|
||||
actionButtons[i].classList.remove("a-link-button-inactive");
|
||||
actionButtons[i].classList.add("a-link-button");
|
||||
@@ -165,31 +171,33 @@ Node.prototype.untarget = function() {
|
||||
--this.targetedCount;
|
||||
}
|
||||
|
||||
//Hacking mission instance
|
||||
//Takes in the reputation of the Faction for which the mission is
|
||||
//being conducted
|
||||
/**
|
||||
* Hacking mission instance
|
||||
* @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) {
|
||||
this.faction = fac;
|
||||
|
||||
this.started = false;
|
||||
this.time = 180000; //5 minutes to start, milliseconds
|
||||
this.time = 180000; // 5 minutes to start, milliseconds
|
||||
|
||||
this.playerCores = [];
|
||||
this.playerNodes = []; //Non-core nodes
|
||||
this.playerNodes = []; // Non-core nodes
|
||||
this.playerAtk = 0;
|
||||
this.playerDef = 0;
|
||||
|
||||
this.enemyCores = [];
|
||||
this.enemyDatabases = [];
|
||||
this.enemyNodes = []; //Non-core nodes
|
||||
this.enemyNodes = []; // Non-core nodes
|
||||
this.enemyAtk = 0;
|
||||
this.enemyDef = 0;
|
||||
|
||||
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 = [];
|
||||
for (var r = 0; r < 8; ++r) {
|
||||
@@ -211,10 +219,10 @@ function HackingMission(rep, fac) {
|
||||
}
|
||||
|
||||
HackingMission.prototype.init = function() {
|
||||
//Create Header DOM
|
||||
// Create Header DOM
|
||||
this.createPageDom();
|
||||
|
||||
//Create player starting nodes
|
||||
// Create player starting nodes
|
||||
var home = Player.getHomeComputer()
|
||||
for (var i = 0; i < home.cpuCores; ++i) {
|
||||
var stats = {
|
||||
@@ -228,7 +236,7 @@ HackingMission.prototype.init = function() {
|
||||
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 numFirewalls = Math.min(20,
|
||||
getRandomInt(Math.round(this.difficulty/3), Math.round(this.difficulty/3) + 1));
|
||||
@@ -304,10 +312,10 @@ HackingMission.prototype.createPageDom = function() {
|
||||
wikiGuideBtn.style.display = "inline-block";
|
||||
wikiGuideBtn.classList.add("hack-mission-header-element");
|
||||
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");
|
||||
startBtn.innerHTML = "Start";
|
||||
startBtn.setAttribute("id", "hack-mission-start-btn");
|
||||
@@ -334,15 +342,15 @@ HackingMission.prototype.createPageDom = function() {
|
||||
timer.style.display = "inline-block";
|
||||
timer.style.margin = "6px";
|
||||
|
||||
//Create Action Buttons (Attack/Scan/Weaken/ etc...)
|
||||
// Create Action Buttons (Attack/Scan/Weaken/ etc...)
|
||||
var actionsContainer = document.createElement("span");
|
||||
actionsContainer.style.display = "block";
|
||||
actionsContainer.classList.add("hack-mission-action-buttons-container");
|
||||
for (var i = 0; i < 6; ++i) {
|
||||
this.actionButtons.push(document.createElement("a"));
|
||||
this.actionButtons[i].style.display = "inline-block";
|
||||
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("a-link-button-inactive"); // Disabled at start
|
||||
this.actionButtons[i].classList.add("tooltip"); // Disabled at start
|
||||
this.actionButtons[i].classList.add("hack-mission-header-element");
|
||||
actionsContainer.appendChild(this.actionButtons[i]);
|
||||
}
|
||||
@@ -383,7 +391,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
"also be done by simply clicking the white connection line.";
|
||||
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 enemyStats = document.createElement("p");
|
||||
playerStats.style.display = "inline-block";
|
||||
@@ -397,7 +405,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
actionsContainer.appendChild(playerStats);
|
||||
actionsContainer.appendChild(enemyStats);
|
||||
|
||||
//Set Action Button event listeners
|
||||
// Set Action Button event listeners
|
||||
this.actionButtons[0].addEventListener("click", ()=>{
|
||||
if (!(this.selectedNode.length > 0)) {
|
||||
console.log("ERR: Pressing Action button without selected node");
|
||||
@@ -405,7 +413,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
}
|
||||
if (this.selectedNode[0].type !== NodeTypes.Core) {return;}
|
||||
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){
|
||||
node.action = NodeActions.Attack;
|
||||
});
|
||||
@@ -416,10 +424,10 @@ HackingMission.prototype.createPageDom = function() {
|
||||
console.log("ERR: Pressing Action button without selected node");
|
||||
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;}
|
||||
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){
|
||||
node.action = NodeActions.Scan;
|
||||
});
|
||||
@@ -430,10 +438,10 @@ HackingMission.prototype.createPageDom = function() {
|
||||
console.log("ERR: Pressing Action button without selected node");
|
||||
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;}
|
||||
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){
|
||||
node.action = NodeActions.Weaken;
|
||||
});
|
||||
@@ -445,7 +453,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
return;
|
||||
}
|
||||
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){
|
||||
node.action = NodeActions.Fortify;
|
||||
});
|
||||
@@ -459,7 +467,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
var nodeType = this.selectedNode[0].type;
|
||||
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
|
||||
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){
|
||||
node.action = NodeActions.Overflow;
|
||||
});
|
||||
@@ -477,11 +485,7 @@ HackingMission.prototype.createPageDom = function() {
|
||||
}
|
||||
node.action = NodeActions.Fortify;
|
||||
});
|
||||
// if (this.selectedNode.conn) {
|
||||
// var endpoints = this.selectedNode.conn.endpoints;
|
||||
// endpoints[0].detachFrom(endpoints[1]);
|
||||
// }
|
||||
})
|
||||
});
|
||||
|
||||
var timeDisplay = document.createElement("p");
|
||||
|
||||
@@ -508,8 +512,10 @@ HackingMission.prototype.setActionButtonsActive = function(nodeType=null) {
|
||||
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) {
|
||||
switch (nodeType) {
|
||||
case NodeTypes.Firewall:
|
||||
@@ -535,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) {
|
||||
if (isString(i)) {
|
||||
switch (i) {
|
||||
@@ -652,7 +658,7 @@ HackingMission.prototype.setNodePosition = function(nodeObj, x, y) {
|
||||
HackingMission.prototype.setNodeRandomPosition = function(nodeObj, xlimit=0) {
|
||||
var i = getRandomInt(0, this.availablePositions.length - 1);
|
||||
if (this.availablePositions[i][1] < xlimit) {
|
||||
//Recurse if not within limit
|
||||
// Recurse if not within limit
|
||||
return this.setNodeRandomPosition(nodeObj, xlimit);
|
||||
}
|
||||
var pos = this.availablePositions.splice(i, 1);
|
||||
@@ -661,15 +667,15 @@ HackingMission.prototype.setNodeRandomPosition = function(nodeObj, xlimit=0) {
|
||||
}
|
||||
|
||||
HackingMission.prototype.createMap = function() {
|
||||
//Use a grid
|
||||
// Use a grid
|
||||
var map = document.createElement("div");
|
||||
map.classList.add("hack-mission-grid");
|
||||
map.setAttribute("id", "hacking-mission-map");
|
||||
document.getElementById("mission-container").appendChild(map);
|
||||
|
||||
//Create random Nodes for every space in the map that
|
||||
//hasn't been filled yet. The stats of each Node will be based on
|
||||
//the player/enemy attack
|
||||
// Create random Nodes for every space in the map that
|
||||
// hasn't been filled yet. The stats of each Node will be based on
|
||||
// the player/enemy attack
|
||||
var averageAttack = (this.playerAtk + this.enemyAtk) / 2;
|
||||
for (var x = 0; x < 8; ++x) {
|
||||
for (var y = 0; y < 8; ++y) {
|
||||
@@ -677,7 +683,7 @@ HackingMission.prototype.createMap = function() {
|
||||
var node, type = getRandomInt(0, 2);
|
||||
var randMult = addOffset(0.85 + (this.difficulty / 2), 15);
|
||||
switch (type) {
|
||||
case 0: //Spam
|
||||
case 0: // Spam
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: averageAttack * 1.1 + getRandomInt(15, 45),
|
||||
@@ -685,7 +691,7 @@ HackingMission.prototype.createMap = function() {
|
||||
}
|
||||
node = new Node(NodeTypes.Spam, stats);
|
||||
break;
|
||||
case 1: //Transfer
|
||||
case 1: // Transfer
|
||||
var stats = {
|
||||
atk: 0,
|
||||
def: averageAttack * 1.1 + getRandomInt(15, 45),
|
||||
@@ -693,7 +699,7 @@ HackingMission.prototype.createMap = function() {
|
||||
}
|
||||
node = new Node(NodeTypes.Transfer, stats);
|
||||
break;
|
||||
case 2: //Shield
|
||||
case 2: // Shield
|
||||
default:
|
||||
var stats = {
|
||||
atk: 0,
|
||||
@@ -710,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 c = 0; c < 8; ++c) {
|
||||
this.createNodeDomElement(this.map[r][c]);
|
||||
}
|
||||
}
|
||||
|
||||
//Configure all Player CPUS
|
||||
// Configure all Player CPUS
|
||||
for (var i = 0; i < this.playerCores.length; ++i) {
|
||||
console.log("Configuring Player Node: " + this.playerCores[i].el.id);
|
||||
this.configurePlayerNodeElement(this.playerCores[i].el);
|
||||
@@ -728,12 +734,12 @@ HackingMission.prototype.createNodeDomElement = function(nodeObj) {
|
||||
var nodeDiv = document.createElement("a"), txtEl = document.createElement('p');
|
||||
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];
|
||||
nodeDiv.setAttribute("id", id);
|
||||
txtEl.setAttribute("id", id + "-txt");
|
||||
|
||||
//Set node classes for owner
|
||||
// Set node classes for owner
|
||||
nodeDiv.classList.add("hack-mission-node");
|
||||
if (nodeObj.plyrCtrl) {
|
||||
nodeDiv.classList.add("hack-mission-player-node");
|
||||
@@ -741,7 +747,7 @@ HackingMission.prototype.createNodeDomElement = function(nodeObj) {
|
||||
nodeDiv.classList.add("hack-mission-enemy-node");
|
||||
}
|
||||
|
||||
//Set node classes based on type
|
||||
// Set node classes based on type
|
||||
var txt;
|
||||
switch (nodeObj.type) {
|
||||
case NodeTypes.Core:
|
||||
@@ -794,7 +800,7 @@ HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
|
||||
var id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1];
|
||||
var nodeDiv = document.getElementById(id), txtEl = document.getElementById(id + "-txt");
|
||||
|
||||
//Set node classes based on type
|
||||
// Set node classes based on type
|
||||
var txt;
|
||||
switch (nodeObj.type) {
|
||||
case NodeTypes.Core:
|
||||
@@ -832,9 +838,11 @@ HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
|
||||
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
|
||||
//an argument
|
||||
/**
|
||||
* Gets a Node DOM element's corresponding Node object using its
|
||||
* element id. Function accepts either the DOM element object or the ID as
|
||||
* an argument
|
||||
*/
|
||||
HackingMission.prototype.getNodeFromElement = function(el) {
|
||||
var id;
|
||||
if (isString(el)) {
|
||||
@@ -897,14 +905,16 @@ function clearAllSelectedNodes(hackMissionInst) {
|
||||
}
|
||||
}
|
||||
|
||||
//Configures a DOM element representing a player-owned node to
|
||||
//be selectable and actionable
|
||||
//Note: Does NOT change its css class. This is handled by Node.setControlledBy...
|
||||
/**
|
||||
* Configures a DOM element representing a player-owned node to
|
||||
* be selectable and actionable.
|
||||
* Note: Does NOT change its css class. This is handled by Node.setControlledBy...
|
||||
*/
|
||||
HackingMission.prototype.configurePlayerNodeElement = function(el) {
|
||||
var nodeObj = this.getNodeFromElement(el);
|
||||
if (nodeObj == null) {console.log("Error getting Node object");}
|
||||
|
||||
//Add event listener
|
||||
// Add event listener
|
||||
var self = this;
|
||||
function selectNodeWrapper() {
|
||||
selectNode(self, el);
|
||||
@@ -922,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) {
|
||||
//Deselect node if it was the selected node
|
||||
// Deselect node if it was the selected node
|
||||
var nodeObj = this.getNodeFromElement(el);
|
||||
for (var i = 0; i < this.selectedNode.length; ++i) {
|
||||
if (this.selectedNode[i] == nodeObj) {
|
||||
@@ -936,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) {
|
||||
var x = node.pos[0], y = node.pos[1];
|
||||
if (x > 0 && this.map[x-1][y].plyrCtrl) {return true;}
|
||||
@@ -980,7 +994,7 @@ HackingMission.prototype.initJsPlumb = function() {
|
||||
|
||||
this.jsplumbinstance = instance;
|
||||
|
||||
//All player cores are sources
|
||||
// All player cores are sources
|
||||
for (var i = 0; i < this.playerCores.length; ++i) {
|
||||
instance.makeSource(this.playerCores[i].el, {
|
||||
deleteEndpointsOnEmpty:true,
|
||||
@@ -990,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) {
|
||||
instance.makeTarget(this.enemyCores[i].el, {
|
||||
maxConnections:-1,
|
||||
@@ -1020,7 +1034,7 @@ HackingMission.prototype.initJsPlumb = function() {
|
||||
});
|
||||
}
|
||||
|
||||
//Clicking a connection drops it
|
||||
// Clicking a connection drops it
|
||||
instance.bind("click", (conn, originalEvent) => {
|
||||
// Cannot drop enemy's connections
|
||||
const sourceNode = this.getNodeFromElement(conn.source);
|
||||
@@ -1030,15 +1044,15 @@ HackingMission.prototype.initJsPlumb = function() {
|
||||
endpoints[0].detachFrom(endpoints[1]);
|
||||
});
|
||||
|
||||
//Connection events
|
||||
// Connection events
|
||||
instance.bind("connection", (info) => {
|
||||
var targetNode = this.getNodeFromElement(info.target);
|
||||
|
||||
//Do not detach for enemy nodes
|
||||
// Do not detach for enemy nodes
|
||||
var thisNode = this.getNodeFromElement(info.source);
|
||||
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)) {
|
||||
info.sourceEndpoint.detachFrom(info.targetEndpoint);
|
||||
return;
|
||||
@@ -1050,7 +1064,7 @@ HackingMission.prototype.initJsPlumb = function() {
|
||||
++targetNode.targetedCount;
|
||||
});
|
||||
|
||||
//Detach Connection events
|
||||
// Detach Connection events
|
||||
instance.bind("connectionDetached", (info, originalEvent)=>{
|
||||
var sourceNode = this.getNodeFromElement(info.source);
|
||||
sourceNode.conn = null;
|
||||
@@ -1060,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) {
|
||||
var allConns = this.jsplumbinstance.getAllConnections();
|
||||
for (var i = allConns.length-1; i >= 0; --i) {
|
||||
@@ -1070,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) {
|
||||
var allConns = this.jsplumbinstance.getAllConnections();
|
||||
for (var i = allConns.length-1; i >= 0; --i) {
|
||||
@@ -1085,10 +1099,10 @@ var storedCycles = 0;
|
||||
HackingMission.prototype.process = function(numCycles=1) {
|
||||
if (!this.started) {return;}
|
||||
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;
|
||||
//Process actions of all player nodes
|
||||
// Process actions of all player nodes
|
||||
this.playerCores.forEach((node)=>{
|
||||
res |= this.processNode(node, storedCycles);
|
||||
});
|
||||
@@ -1101,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.enemyAISelectAction(node);
|
||||
res |= this.processNode(node, storedCycles);
|
||||
@@ -1116,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)=>{
|
||||
node.maxhp += (0.1 * storedCycles);
|
||||
node.hp += (0.1 * storedCycles);
|
||||
@@ -1127,19 +1141,19 @@ HackingMission.prototype.process = function(numCycles=1) {
|
||||
this.calculateDefenses();
|
||||
}
|
||||
|
||||
//Win if all enemy databases are conquered
|
||||
// Win if all enemy databases are conquered
|
||||
if (this.enemyDatabases.length === 0) {
|
||||
this.finishMission(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Lose if all your cores are gone
|
||||
// Lose if all your cores are gone
|
||||
if (this.playerCores.length === 0) {
|
||||
this.finishMission(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//Defense/hp of misc nodes increases slowly over time
|
||||
// Defense/hp of misc nodes increases slowly over time
|
||||
this.miscNodes.forEach((node)=>{
|
||||
node.def += (0.1 * storedCycles);
|
||||
node.maxhp += (0.05 * storedCycles);
|
||||
@@ -1148,7 +1162,7 @@ HackingMission.prototype.process = function(numCycles=1) {
|
||||
this.updateNodeDomElement(node);
|
||||
});
|
||||
|
||||
//Update timer and check if player lost
|
||||
// Update timer and check if player lost
|
||||
this.time -= (storedCycles * Engine._idleSpeed);
|
||||
if (this.time <= 0) {
|
||||
this.finishMission(false);
|
||||
@@ -1159,7 +1173,7 @@ HackingMission.prototype.process = function(numCycles=1) {
|
||||
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) {
|
||||
if (nodeObj.action == null) {
|
||||
return;
|
||||
@@ -1174,21 +1188,21 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
}
|
||||
|
||||
if (targetNode == null) {
|
||||
//Player is in the middle of dragging the connection,
|
||||
//so the target node is null. Do nothing here
|
||||
// Player is in the middle of dragging the connection,
|
||||
// so the target node is null. Do nothing here
|
||||
} else if (targetNode.plyrCtrl) {
|
||||
def = this.playerDef;
|
||||
atk = this.enemyAtk;
|
||||
} else if (targetNode.enmyCtrl) {
|
||||
def = this.enemyDef;
|
||||
atk = this.playerAtk;
|
||||
} else { //Misc Node
|
||||
} else { // Misc Node
|
||||
def = targetNode.def;
|
||||
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 enmyHacking = this.difficulty * CONSTANTS.HackingMissionDifficultyToHacking;
|
||||
switch(nodeObj.action) {
|
||||
@@ -1229,13 +1243,13 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Stats can't go below 0
|
||||
// Stats can't go below 0
|
||||
if (nodeObj.atk < 0) {nodeObj.atk = 0;}
|
||||
if (nodeObj.def < 0) {nodeObj.def = 0;}
|
||||
if (targetNode && targetNode.atk < 0) {targetNode.atk = 0;}
|
||||
if (targetNode && targetNode.def < 0) {targetNode.def = 0;}
|
||||
|
||||
//Conquering a node
|
||||
// Conquering a node
|
||||
if (targetNode && targetNode.hp <= 0) {
|
||||
var conqueredByPlayer = nodeObj.plyrCtrl;
|
||||
targetNode.hp = targetNode.maxhp;
|
||||
@@ -1245,18 +1259,18 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
targetNode.deselect(this.actionButtons);
|
||||
}
|
||||
|
||||
//The conquered node has its stats reduced
|
||||
// The conquered node has its stats reduced
|
||||
targetNode.atk /= 2;
|
||||
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;
|
||||
|
||||
//Remove all connections from Node
|
||||
// Remove all connections from Node
|
||||
this.dropAllConnectionsToNode(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) {
|
||||
targetNode.setControlledByPlayer();
|
||||
this.jsplumbinstance.unmakeTarget(targetNode.el);
|
||||
@@ -1268,7 +1282,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
});
|
||||
} else {
|
||||
targetNode.setControlledByEnemy();
|
||||
nodeObj.conn = null; //Clear connection
|
||||
nodeObj.conn = null; // Clear connection
|
||||
this.jsplumbinstance.unmakeSource(targetNode.el);
|
||||
this.jsplumbinstance.makeTarget(targetNode.el, {
|
||||
maxConnections:-1,
|
||||
@@ -1279,7 +1293,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
|
||||
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) {
|
||||
for (var i = 0; i < orig.length; ++i) {
|
||||
if (orig[i] == targetNode) {
|
||||
@@ -1319,7 +1333,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
case NodeTypes.Spam:
|
||||
if (conqueredByPlayer) {
|
||||
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;
|
||||
} else {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
|
||||
@@ -1327,7 +1341,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
|
||||
break;
|
||||
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) {
|
||||
swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
|
||||
this.playerCores.forEach(function(node) {
|
||||
@@ -1353,7 +1367,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
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) {
|
||||
this.miscNodes.forEach((node)=>{
|
||||
if (node.targetedCount === 0) {
|
||||
@@ -1363,23 +1377,25 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
|
||||
}
|
||||
}
|
||||
|
||||
//Update node DOMs
|
||||
// Update node DOMs
|
||||
this.updateNodeDomElement(nodeObj);
|
||||
if (targetNode) {this.updateNodeDomElement(targetNode);}
|
||||
return calcStats;
|
||||
}
|
||||
|
||||
//Enemy "AI" for CPU Core and Transfer Nodes
|
||||
// Enemy "AI" for CPU Core and Transfer Nodes
|
||||
HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
|
||||
if (nodeObj == null) {return;}
|
||||
switch(nodeObj.type) {
|
||||
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
|
||||
//be selected for now, and the next time process() gets called this will repeat
|
||||
/**
|
||||
* Select a single RANDOM target from miscNodes and player's Nodes
|
||||
* 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 (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 node;
|
||||
if (this.playerNodes.length === 0) {
|
||||
@@ -1388,23 +1404,23 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
|
||||
node = this.playerNodes[rand];
|
||||
}
|
||||
if (this.nodeReachableByEnemy(node)) {
|
||||
//Create connection
|
||||
// Create connection
|
||||
nodeObj.conn = this.jsplumbinstance.connect({
|
||||
source:nodeObj.el,
|
||||
target:node.el
|
||||
});
|
||||
++node.targetedCount;
|
||||
} 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);
|
||||
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 {
|
||||
node = this.playerCores[rand];
|
||||
}
|
||||
|
||||
if (this.nodeReachableByEnemy(node)) {
|
||||
//Create connection
|
||||
// Create connection
|
||||
nodeObj.conn = this.jsplumbinstance.connect({
|
||||
source:nodeObj.el,
|
||||
target:node.el
|
||||
@@ -1413,7 +1429,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
|
||||
}
|
||||
}
|
||||
} 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 node = this.miscNodes[rand];
|
||||
if (this.nodeReachableByEnemy(node)) {
|
||||
@@ -1425,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;
|
||||
} else {
|
||||
//If this node has a selected target
|
||||
// If this node has a selected target
|
||||
var targetNode;
|
||||
if (nodeObj.conn.target) {
|
||||
targetNode = this.getNodeFromElement(nodeObj.conn.target);
|
||||
@@ -1453,7 +1469,7 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
|
||||
}
|
||||
break;
|
||||
case NodeTypes.Transfer:
|
||||
//Switch between fortifying and overflowing as necessary
|
||||
// Switch between fortifying and overflowing as necessary
|
||||
if (nodeObj.def < 125) {
|
||||
nodeObj.action = NodeActions.Fortify;
|
||||
} else {
|
||||
@@ -1469,11 +1485,11 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
|
||||
}
|
||||
}
|
||||
|
||||
var hackEffWeightSelf = 130; //Weight for Node actions on self
|
||||
var hackEffWeightTarget = 25; //Weight for Node Actions against Target
|
||||
var hackEffWeightAttack = 80; //Weight for Attack action
|
||||
var hackEffWeightSelf = 130; // Weight for Node actions on self
|
||||
var hackEffWeightTarget = 25; // Weight for Node Actions against Target
|
||||
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) {
|
||||
return Math.max(0.55 * (atk + (hacking / hackEffWeightAttack) - def), 1);
|
||||
}
|
||||
@@ -1494,11 +1510,11 @@ HackingMission.prototype.calculateOverflowEffect = function(hacking=0) {
|
||||
return 0.95 * hacking / hackEffWeightSelf;
|
||||
}
|
||||
|
||||
//Updates timer display
|
||||
// Updates timer display
|
||||
HackingMission.prototype.updateTimer = function() {
|
||||
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 minutes = Math.trunc(seconds / 60);
|
||||
seconds %= 60;
|
||||
@@ -1506,7 +1522,7 @@ HackingMission.prototype.updateTimer = function() {
|
||||
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) {
|
||||
inMission = false;
|
||||
currMission = null;
|
||||
@@ -1525,13 +1541,13 @@ HackingMission.prototype.finishMission = function(win) {
|
||||
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
|
||||
}
|
||||
|
||||
//Clear mission container
|
||||
// Clear mission container
|
||||
var container = document.getElementById("mission-container");
|
||||
while(container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
|
||||
//Return to Faction page
|
||||
// Return to Faction page
|
||||
document.getElementById("mainmenu-container").style.visibility = "visible";
|
||||
document.getElementById("character-overview-wrapper").style.visibility = "visible";
|
||||
Engine.loadFactionContent();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Player} from "./Player";
|
||||
import {Bladeburner} from "./Bladeburner";
|
||||
import {makeRuntimeRejectMsg} from "./NetscriptEvaluator";
|
||||
import { Player } from "./Player";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
||||
|
||||
function unknownBladeburnerActionErrorMessage(functionName, actionType, actionName) {
|
||||
return `ERROR: bladeburner.${functionName}() failed due to an invalid action specified. ` +
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {NetscriptFunctions} from "./NetscriptFunctions";
|
||||
import {NetscriptPort} from "./NetscriptPort";
|
||||
import { NetscriptFunctions } from "./NetscriptFunctions";
|
||||
import { NetscriptPort } from "./NetscriptPort";
|
||||
|
||||
/* Environment
|
||||
* NetScript program environment
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Player } from "./Player";
|
||||
import { Environment } from "./NetscriptEnvironment";
|
||||
import { WorkerScript, addWorkerScript} from "./NetscriptWorker";
|
||||
import { Server } from "./Server/Server";
|
||||
import { getServer } from "./Server/ServerHelpers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import { Script } from "./Script/Script";
|
||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Player } from "./Player";
|
||||
import { Environment } from "./NetscriptEnvironment";
|
||||
import { WorkerScript, addWorkerScript } from "./NetscriptWorker";
|
||||
import { Server } from "./Server/Server";
|
||||
import { getServer } from "./Server/ServerHelpers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import { Script } from "./Script/Script";
|
||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
||||
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { parse, Node } from "../utils/acorn";
|
||||
|
||||
import {parse, Node} from "../utils/acorn";
|
||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||
import {isString} from "../utils/helpers/isString";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { isValidIPAddress } from "../utils/helpers/isValidIPAddress";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
|
||||
export function evaluateImport(exp, workerScript, checkingRam=false) {
|
||||
//When its checking RAM, it exports an array of nodes for each imported function
|
||||
|
||||
@@ -1,117 +1,149 @@
|
||||
var sprintf = require('sprintf-js').sprintf,
|
||||
vsprintf = require('sprintf-js').vsprintf
|
||||
const sprintf = require("sprintf-js").sprintf;
|
||||
const vsprintf = require("sprintf-js").vsprintf;
|
||||
|
||||
import {updateActiveScriptsItems} from "./ActiveScriptsUI";
|
||||
import { Augmentation } from "./Augmentation/Augmentation";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import { augmentationExists,
|
||||
installAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { findCrime } from "./Crime/CrimeHelpers";
|
||||
import {Bladeburner} from "./Bladeburner";
|
||||
import {Company} from "./Company/Company";
|
||||
import {Companies, companyExists} from "./Company/Companies";
|
||||
import {CompanyPosition} from "./Company/CompanyPosition";
|
||||
import {CompanyPositions} from "./Company/CompanyPositions";
|
||||
import {CONSTANTS} from "./Constants";
|
||||
import { DarkWebItems } from "./DarkWeb/DarkWebItems";
|
||||
import {calculateHackingChance,
|
||||
calculateHackingExpGain,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingTime,
|
||||
calculateGrowTime,
|
||||
calculateWeakenTime} from "./Hacking";
|
||||
import {AllGangs} from "./Gang";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { Factions,
|
||||
factionExists } from "./Faction/Factions";
|
||||
import { joinFaction,
|
||||
purchaseAugmentation } from "./Faction/FactionHelpers";
|
||||
import { FactionWorkType } from "./Faction/FactionWorkTypeEnum";
|
||||
import { netscriptCanGrow,
|
||||
netscriptCanHack,
|
||||
netscriptCanWeaken } from "./Hacking/netscriptCanHack";
|
||||
import { updateActiveScriptsItems } from "./ActiveScriptsUI";
|
||||
import { Augmentation } from "./Augmentation/Augmentation";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import {
|
||||
augmentationExists,
|
||||
installAugmentations
|
||||
} from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { findCrime } from "./Crime/CrimeHelpers";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { Company } from "./Company/Company";
|
||||
import { Companies, companyExists } from "./Company/Companies";
|
||||
import { CompanyPosition } from "./Company/CompanyPosition";
|
||||
import { CompanyPositions } from "./Company/CompanyPositions";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { DarkWebItems } from "./DarkWeb/DarkWebItems";
|
||||
import {
|
||||
calculateHackingChance,
|
||||
calculateHackingExpGain,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingTime,
|
||||
calculateGrowTime,
|
||||
calculateWeakenTime
|
||||
} from "./Hacking";
|
||||
import { AllGangs } from "./Gang";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { Factions, factionExists } from "./Faction/Factions";
|
||||
import { joinFaction, purchaseAugmentation } from "./Faction/FactionHelpers";
|
||||
import { FactionWorkType } from "./Faction/FactionWorkTypeEnum";
|
||||
import {
|
||||
netscriptCanGrow,
|
||||
netscriptCanHack,
|
||||
netscriptCanWeaken
|
||||
} from "./Hacking/netscriptCanHack";
|
||||
|
||||
import { getCostOfNextHacknetNode,
|
||||
getCostOfNextHacknetServer,
|
||||
purchaseHacknet,
|
||||
hasHacknetServers,
|
||||
purchaseHashUpgrade } from "./Hacknet/HacknetHelpers";
|
||||
import { CityName } from "./Locations/data/CityNames";
|
||||
import { LocationName } from "./Locations/data/LocationNames";
|
||||
import {
|
||||
getCostOfNextHacknetNode,
|
||||
getCostOfNextHacknetServer,
|
||||
purchaseHacknet,
|
||||
hasHacknetServers,
|
||||
purchaseHashUpgrade
|
||||
} from "./Hacknet/HacknetHelpers";
|
||||
import { CityName } from "./Locations/data/CityNames";
|
||||
import { LocationName } from "./Locations/data/LocationNames";
|
||||
|
||||
import { HacknetServer } from "./Hacknet/HacknetServer";
|
||||
import { Message } from "./Message/Message";
|
||||
import { Messages } from "./Message/MessageHelpers";
|
||||
import {inMission} from "./Missions";
|
||||
import {Player} from "./Player";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { Script } from "./Script/Script";
|
||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||
import { AllServers,
|
||||
AddToAllServers } from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import { GetServerByHostname,
|
||||
getServer,
|
||||
getServerOnNetwork,
|
||||
numCycleForGrowth,
|
||||
processSingleServerGrowth } from "./Server/ServerHelpers";
|
||||
import { getPurchaseServerCost,
|
||||
getPurchaseServerLimit,
|
||||
getPurchaseServerMaxRam } from "./Server/ServerPurchases";
|
||||
import {Settings} from "./Settings/Settings";
|
||||
import {SpecialServerIps} from "./Server/SpecialServerIps";
|
||||
import {Stock} from "./StockMarket/Stock";
|
||||
import {StockMarket, StockSymbols, SymbolToStockMap,
|
||||
initStockMarket, initSymbolToStockMap, buyStock,
|
||||
sellStock, updateStockPlayerPosition,
|
||||
shortStock, sellShort, OrderTypes,
|
||||
PositionTypes, placeOrder, cancelOrder} from "./StockMarket/StockMarket";
|
||||
import { getStockmarket4SDataCost,
|
||||
getStockMarket4STixApiCost } from "./StockMarket/StockMarketCosts";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags"
|
||||
import {TextFile, getTextFile, createTextFile} from "./TextFile";
|
||||
import { HacknetServer } from "./Hacknet/HacknetServer";
|
||||
import { Message } from "./Message/Message";
|
||||
import { Messages } from "./Message/MessageHelpers";
|
||||
import { inMission } from "./Missions";
|
||||
import { Player } from "./Player";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { Script } from "./Script/Script";
|
||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||
import { AllServers, AddToAllServers } from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import {
|
||||
GetServerByHostname,
|
||||
getServer,
|
||||
getServerOnNetwork,
|
||||
numCycleForGrowth,
|
||||
processSingleServerGrowth
|
||||
} from "./Server/ServerHelpers";
|
||||
import {
|
||||
getPurchaseServerCost,
|
||||
getPurchaseServerLimit,
|
||||
getPurchaseServerMaxRam
|
||||
} from "./Server/ServerPurchases";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { SpecialServerIps } from "./Server/SpecialServerIps";
|
||||
import { Stock } from "./StockMarket/Stock";
|
||||
import {
|
||||
StockMarket,
|
||||
StockSymbols,
|
||||
SymbolToStockMap,
|
||||
initStockMarket,
|
||||
initSymbolToStockMap,
|
||||
buyStock,
|
||||
sellStock,
|
||||
updateStockPlayerPosition,
|
||||
shortStock,
|
||||
sellShort,
|
||||
OrderTypes,
|
||||
PositionTypes,
|
||||
placeOrder,
|
||||
cancelOrder
|
||||
} from "./StockMarket/StockMarket";
|
||||
import {
|
||||
getStockmarket4SDataCost,
|
||||
getStockMarket4STixApiCost
|
||||
} from "./StockMarket/StockMarketCosts";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { TextFile, getTextFile, createTextFile } from "./TextFile";
|
||||
|
||||
import {unknownBladeburnerActionErrorMessage,
|
||||
unknownBladeburnerExceptionMessage,
|
||||
checkBladeburnerAccess} from "./NetscriptBladeburner";
|
||||
import * as nsGang from "./NetscriptGang";
|
||||
import {WorkerScript, workerScripts,
|
||||
killWorkerScript, NetscriptPorts} from "./NetscriptWorker";
|
||||
import {makeRuntimeRejectMsg, netscriptDelay,
|
||||
runScriptFromScript} from "./NetscriptEvaluator";
|
||||
import {NetscriptPort} from "./NetscriptPort";
|
||||
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/Sleeve";
|
||||
import {
|
||||
unknownBladeburnerActionErrorMessage,
|
||||
unknownBladeburnerExceptionMessage,
|
||||
checkBladeburnerAccess
|
||||
} from "./NetscriptBladeburner";
|
||||
import * as nsGang from "./NetscriptGang";
|
||||
import {
|
||||
WorkerScript,
|
||||
workerScripts,
|
||||
killWorkerScript,
|
||||
NetscriptPorts
|
||||
} from "./NetscriptWorker";
|
||||
import {
|
||||
makeRuntimeRejectMsg,
|
||||
netscriptDelay,
|
||||
runScriptFromScript
|
||||
} from "./NetscriptEvaluator";
|
||||
import { NetscriptPort } from "./NetscriptPort";
|
||||
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/Sleeve";
|
||||
|
||||
import {Page, routing} from "./ui/navigationTracking";
|
||||
import {numeralWrapper} from "./ui/numeralFormat";
|
||||
import {post} from "./ui/postToTerminal";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { is2DArray } from "./utils/helpers/is2DArray";
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { post } from "./ui/postToTerminal";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { is2DArray } from "./utils/helpers/is2DArray";
|
||||
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
import {isPowerOfTwo} from "../utils/helpers/isPowerOfTwo";
|
||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||
import {createRandomIp} from "../utils/IPAddress";
|
||||
import {formatNumber, isHTML} from "../utils/StringHelperFunctions";
|
||||
import {isString} from "../utils/helpers/isString";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { isPowerOfTwo } from "../utils/helpers/isPowerOfTwo";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { createRandomIp } from "../utils/IPAddress";
|
||||
import { formatNumber, isHTML } from "../utils/StringHelperFunctions";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
var hasCorporationSF = false, //Source-File 3
|
||||
hasSingularitySF = false, //Source-File 4
|
||||
hasAISF = false, //Source-File 5
|
||||
hasBladeburnerSF = false, //Source-File 6
|
||||
hasBladeburner2079SF = false, //Source-File 7
|
||||
hasWallStreetSF = false, //Source-File 8
|
||||
hasBn11SF = false; //Source-File 11
|
||||
let hasCorporationSF = false; // Source-File 3
|
||||
let hasSingularitySF = false; // Source-File 4
|
||||
let hasAISF = false; // Source-File 5
|
||||
let hasBladeburnerSF = false; // Source-File 6
|
||||
let hasBladeburner2079SF = false; // Source-File 7
|
||||
let hasWallStreetSF = false; // Source-File 8
|
||||
let hasBn11SF = false; // Source-File 11
|
||||
|
||||
var singularitySFLvl=1, wallStreetSFLvl=1;
|
||||
let singularitySFLvl = 1;
|
||||
let wallStreetSFLvl = 1;
|
||||
|
||||
var possibleLogs = {
|
||||
ALL: true,
|
||||
@@ -184,7 +216,7 @@ var possibleLogs = {
|
||||
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() {
|
||||
for (var i = 0; i < Player.sourceFiles.length; ++i) {
|
||||
if (Player.sourceFiles[i].n === 3) {hasCorporationSF = true;}
|
||||
@@ -423,10 +455,10 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "hack() error. Invalid IP or hostname passed in: " + ip + ". Stopping...");
|
||||
}
|
||||
|
||||
//Calculate the hacking time
|
||||
var hackingTime = calculateHackingTime(server); //This is in seconds
|
||||
// Calculate the hacking time
|
||||
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);
|
||||
if (!canHack.res) {
|
||||
workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
|
||||
@@ -443,18 +475,17 @@ function NetscriptFunctions(workerScript) {
|
||||
var rand = Math.random();
|
||||
var expGainedOnSuccess = calculateHackingExpGain(server) * threads;
|
||||
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
||||
if (rand < hackChance) { //Success!
|
||||
if (rand < hackChance) { // Success!
|
||||
const percentHacked = calculatePercentMoneyHacked(server);
|
||||
let maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax));
|
||||
if (isNaN(maxThreadNeeded)) {
|
||||
//Server has a 'max money' of 0 (probably).
|
||||
//We'll set this to an arbitrarily large value
|
||||
// Server has a 'max money' of 0 (probably). We'll set this to an arbitrarily large value
|
||||
maxThreadNeeded = 1e6;
|
||||
}
|
||||
|
||||
let moneyGained = Math.floor(server.moneyAvailable * percentHacked) * threads;
|
||||
|
||||
//Over-the-top safety checks
|
||||
// Over-the-top safety checks
|
||||
if (moneyGained <= 0) {
|
||||
moneyGained = 0;
|
||||
expGainedOnSuccess = expGainedOnFailure;
|
||||
@@ -476,7 +507,7 @@ function NetscriptFunctions(workerScript) {
|
||||
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
|
||||
return Promise.resolve(moneyGained);
|
||||
} else {
|
||||
//Player only gains 25% exp for failure?
|
||||
// Player only gains 25% exp for failure?
|
||||
Player.gainHackingExp(expGainedOnFailure);
|
||||
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
|
||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.hack == null) {
|
||||
@@ -554,7 +585,7 @@ function NetscriptFunctions(workerScript) {
|
||||
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);
|
||||
if (!canHack.res) {
|
||||
workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
|
||||
@@ -568,7 +599,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return netscriptDelay(growTime * 1000, workerScript).then(function() {
|
||||
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
|
||||
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);
|
||||
const moneyAfter = server.moneyAvailable;
|
||||
workerScript.scriptRef.recordGrow(server.ip, threads);
|
||||
@@ -616,7 +647,7 @@ function NetscriptFunctions(workerScript) {
|
||||
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);
|
||||
if (!canHack.res) {
|
||||
workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
|
||||
@@ -1043,7 +1074,7 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERROR: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
|
||||
}
|
||||
if (scriptname && scriptname.constructor === Array) {
|
||||
//Recursively call scp on all elements of array
|
||||
// Recursively call scp on all elements of array
|
||||
var res = false;
|
||||
scriptname.forEach(function(script) {
|
||||
if (NetscriptFunctions(workerScript).scp(script, ip1, ip2)) {
|
||||
@@ -1089,7 +1120,7 @@ function NetscriptFunctions(workerScript) {
|
||||
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")) {
|
||||
var found = false;
|
||||
for (var i = 0; i < currServ.messages.length; ++i) {
|
||||
@@ -1109,7 +1140,7 @@ function NetscriptFunctions(workerScript) {
|
||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) {
|
||||
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
|
||||
}
|
||||
return true; //Already exists
|
||||
return true; // Already exists
|
||||
}
|
||||
}
|
||||
destServer.messages.push(scriptname);
|
||||
@@ -1119,7 +1150,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Scp for text files
|
||||
// Scp for text files
|
||||
if (scriptname.endsWith(".txt")) {
|
||||
var found = false, txtFile;
|
||||
for (var i = 0; i < currServ.textFiles.length; ++i) {
|
||||
@@ -1137,7 +1168,7 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
for (var i = 0; i < destServer.textFiles.length; ++i) {
|
||||
if (destServer.textFiles[i].fn === scriptname) {
|
||||
//Overwrite
|
||||
// Overwrite
|
||||
destServer.textFiles[i].text = txtFile.text;
|
||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) {
|
||||
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
|
||||
@@ -1153,7 +1184,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Scp for script files
|
||||
// Scp for script files
|
||||
var sourceScript = null;
|
||||
for (var i = 0; i < currServ.scripts.length; ++i) {
|
||||
if (scriptname == currServ.scripts[i].filename) {
|
||||
@@ -1166,7 +1197,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Overwrite script if it already exists
|
||||
// Overwrite script if it already exists
|
||||
for (var i = 0; i < destServer.scripts.length; ++i) {
|
||||
if (scriptname == destServer.scripts[i].filename) {
|
||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.scp == null) {
|
||||
@@ -1181,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();
|
||||
newScript.filename = scriptname;
|
||||
newScript.code = sourceScript.code;
|
||||
@@ -1207,7 +1238,7 @@ function NetscriptFunctions(workerScript) {
|
||||
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;
|
||||
if (arguments.length >= 2) {
|
||||
filter = grep.toString();
|
||||
@@ -1271,7 +1302,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
//Sort the files alphabetically then print each
|
||||
// Sort the files alphabetically then print each
|
||||
allFiles.sort();
|
||||
return allFiles;
|
||||
},
|
||||
@@ -1676,7 +1707,7 @@ function NetscriptFunctions(workerScript) {
|
||||
var gains = stock.price * shares - CONSTANTS.StockMarketCommission;
|
||||
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;
|
||||
if (isNaN(netProfit)) {netProfit = 0;}
|
||||
workerScript.scriptRef.onlineMoneyMade += netProfit;
|
||||
@@ -1876,7 +1907,7 @@ function NetscriptFunctions(workerScript) {
|
||||
if (stock == null) {
|
||||
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) {
|
||||
if (workerScript.checkingRam) {
|
||||
@@ -1892,7 +1923,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
var forecast = 50;
|
||||
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() {
|
||||
if (workerScript.checkingRam) {
|
||||
@@ -2055,25 +2086,25 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
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) {
|
||||
workerScript.scriptRef.log("ERROR: deleteServer() failed because you are currently connected to the server you are trying to delete");
|
||||
return false;
|
||||
}
|
||||
|
||||
//A server cannot delete itself
|
||||
// A server cannot delete itself
|
||||
if (ip === workerScript.serverIp) {
|
||||
workerScript.scriptRef.log("ERROR: Cannot call deleteServer() on self. deleteServer() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Delete all scripts running on server
|
||||
// Delete all scripts running on server
|
||||
if (server.runningScripts.length > 0) {
|
||||
workerScript.scriptRef.log("ERROR: Cannot delete server " + server.hostname + " because it still has scripts running.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Delete from player's purchasedServers array
|
||||
// Delete from player's purchasedServers array
|
||||
var found = false;
|
||||
for (var i = 0; i < Player.purchasedServers.length; ++i) {
|
||||
if (ip == Player.purchasedServers[i]) {
|
||||
@@ -2089,10 +2120,10 @@ function NetscriptFunctions(workerScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Delete from all servers
|
||||
// Delete from all servers
|
||||
delete AllServers[ip];
|
||||
|
||||
//Delete from home computer
|
||||
// Delete from home computer
|
||||
found = false;
|
||||
var homeComputer = Player.getHomeComputer();
|
||||
for (var i = 0; i < homeComputer.serversOnNetwork.length; ++i) {
|
||||
@@ -2104,7 +2135,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//Wasn't found on home computer
|
||||
// Wasn't found on home computer
|
||||
workerScript.scriptRef.log("ERROR: Could not find server " + server.hostname +
|
||||
"as a purchased server. This is likely a bug please contact game dev");
|
||||
return false;
|
||||
@@ -2133,8 +2164,8 @@ function NetscriptFunctions(workerScript) {
|
||||
return updateStaticRam("write", CONSTANTS.ScriptReadWriteRamCost);
|
||||
}
|
||||
updateDynamicRam("write", CONSTANTS.ScriptReadWriteRamCost);
|
||||
if (!isNaN(port)) { //Write to port
|
||||
//Port 1-10
|
||||
if (!isNaN(port)) { // Write to port
|
||||
// Port 1-10
|
||||
port = Math.round(port);
|
||||
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to write to invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid.");
|
||||
@@ -2144,17 +2175,17 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer");
|
||||
}
|
||||
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 server = workerScript.getServer();
|
||||
if (server == null) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in write(). This is a bug please contact game dev");
|
||||
}
|
||||
if (isScriptFilename(fn)) {
|
||||
//Write to script
|
||||
// Write to script
|
||||
let script = workerScript.getScriptOnServer(fn);
|
||||
if (script == null) {
|
||||
//Create a new script
|
||||
// Create a new script
|
||||
script = new Script(fn, data, server.ip);
|
||||
server.scripts.push(script);
|
||||
return true;
|
||||
@@ -2162,7 +2193,7 @@ function NetscriptFunctions(workerScript) {
|
||||
mode === "w" ? script.code = data : script.code += data;
|
||||
script.updateRamUsage();
|
||||
} else {
|
||||
//Write to text file
|
||||
// Write to text file
|
||||
let txtFile = getTextFile(fn, server);
|
||||
if (txtFile == null) {
|
||||
txtFile = createTextFile(fn, data, server);
|
||||
@@ -2203,8 +2234,8 @@ function NetscriptFunctions(workerScript) {
|
||||
return updateStaticRam("read", CONSTANTS.ScriptReadWriteRamCost);
|
||||
}
|
||||
updateDynamicRam("read", CONSTANTS.ScriptReadWriteRamCost);
|
||||
if (!isNaN(port)) { //Read from port
|
||||
//Port 1-10
|
||||
if (!isNaN(port)) { // Read from port
|
||||
// Port 1-10
|
||||
port = Math.round(port);
|
||||
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to read from invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid.");
|
||||
@@ -2214,21 +2245,21 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERROR: Could not find port: " + port + ". This is a bug contact the game developer");
|
||||
}
|
||||
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 server = getServer(workerScript.serverIp);
|
||||
if (server == null) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in read(). This is a bug please contact game dev");
|
||||
}
|
||||
if (isScriptFilename(fn)) {
|
||||
//Read from script
|
||||
// Read from script
|
||||
let script = workerScript.getScriptOnServer(fn);
|
||||
if (script == null) {
|
||||
return "";
|
||||
}
|
||||
return script.code;
|
||||
} else {
|
||||
//Read from text file
|
||||
// Read from text file
|
||||
let txtFile = getTextFile(fn, server);
|
||||
if (txtFile !== null) {
|
||||
return txtFile.text;
|
||||
@@ -2263,7 +2294,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return updateStaticRam("clear", CONSTANTS.ScriptReadWriteRamCost);
|
||||
}
|
||||
updateDynamicRam("clear", CONSTANTS.ScriptReadWriteRamCost);
|
||||
if (!isNaN(port)) { //Clear port
|
||||
if (!isNaN(port)) { // Clear port
|
||||
port = Math.round(port);
|
||||
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERROR: Trying to clear invalid port: " + port + ". Only ports 1-" + CONSTANTS.NumNetscriptPorts + " are valid");
|
||||
@@ -2273,7 +2304,7 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "ERROR: Could not find port: " + port + ". This is a bug contact the game developer");
|
||||
}
|
||||
return port.clear();
|
||||
} else if (isString(port)) { //Clear text file
|
||||
} else if (isString(port)) { // Clear text file
|
||||
var fn = port;
|
||||
var server = getServer(workerScript.serverIp);
|
||||
if (server == null) {
|
||||
@@ -2391,7 +2422,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.scriptRef.log("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) {
|
||||
if (workerScript.checkingRam) {
|
||||
@@ -2403,7 +2434,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.scriptRef.log("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) {
|
||||
if (workerScript.checkingRam) {
|
||||
@@ -2415,7 +2446,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.scriptRef.log("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) {
|
||||
if (workerScript.checkingRam) {
|
||||
@@ -2423,13 +2454,13 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
updateDynamicRam("getScriptIncome", CONSTANTS.ScriptGetScriptRamCost);
|
||||
if (arguments.length === 0) {
|
||||
//Get total script income
|
||||
// Get total script income
|
||||
var res = [];
|
||||
res.push(updateActiveScriptsItems());
|
||||
res.push(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
|
||||
return res;
|
||||
} else {
|
||||
//Get income for a particular script
|
||||
// Get income for a particular script
|
||||
var server = getServer(ip);
|
||||
if (server == null) {
|
||||
workerScript.scriptRef.log("getScriptIncome() failed. Invalid IP or hostnamed passed in: " + ip);
|
||||
@@ -2459,7 +2490,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
return total;
|
||||
} else {
|
||||
//Get income for a particular script
|
||||
// Get income for a particular script
|
||||
var server = getServer(ip);
|
||||
if (server == null) {
|
||||
workerScript.scriptRef.log("getScriptExpGain() failed. Invalid IP or hostnamed passed in: " + ip);
|
||||
@@ -3174,7 +3205,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.scriptRef.log("ERROR: Invalid job passed into applyToCompany: " + field + ". applyToCompany() failed");
|
||||
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)) {
|
||||
workerScript.scriptRef.log(res);
|
||||
return false;
|
||||
@@ -3266,7 +3297,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//Make a copy of Player.factionInvitations
|
||||
// Make a copy of Player.factionInvitations
|
||||
return Player.factionInvitations.slice();
|
||||
},
|
||||
joinFaction : function(name) {
|
||||
@@ -3295,7 +3326,7 @@ function NetscriptFunctions(workerScript) {
|
||||
var fac = Factions[name];
|
||||
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) {
|
||||
if (Player.factionInvitations[i] == name || Factions[Player.factionInvitations[i]].isBanned) {
|
||||
Player.factionInvitations.splice(i, 1);
|
||||
@@ -3351,7 +3382,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
|
||||
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",
|
||||
"Bachman & Associates", "Blade Industries", "NWO", "Clarke Incorporated",
|
||||
"OmniTek Incorporated", "Four Sigma", "KuaiGong International",
|
||||
@@ -4663,7 +4694,7 @@ function NetscriptFunctions(workerScript) {
|
||||
updateDynamicRam("joinBladeburnerDivision", CONSTANTS.ScriptBladeburnerApiBaseRamCost);
|
||||
if ((Player.bitNodeN === 7 || hasBladeburner2079SF)) {
|
||||
if (Player.bladeburner instanceof Bladeburner) {
|
||||
return true; //Already member
|
||||
return true; // Already member
|
||||
} else if (Player.strength >= 100 && Player.defense >= 100 &&
|
||||
Player.dexterity >= 100 && Player.agility >= 100) {
|
||||
Player.bladeburner = new Bladeburner({new:true});
|
||||
@@ -5125,9 +5156,17 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
return Player.sleeves[sleeveNumber].tryBuyAugmentation(Player, aug);
|
||||
}
|
||||
} // End sleeve
|
||||
} //End return
|
||||
} //End NetscriptFunction()
|
||||
}, // End sleeve
|
||||
heart: {
|
||||
// Easter egg function
|
||||
break : function() {
|
||||
if (workerScript.checkingRam) { return 0; }
|
||||
|
||||
return Player.karma;
|
||||
}
|
||||
}
|
||||
} // End return
|
||||
} // End NetscriptFunction()
|
||||
|
||||
export {NetscriptFunctions, initSingularitySFFlags, hasSingularitySF, hasBn11SF,
|
||||
hasWallStreetSF, wallStreetSFLvl, hasCorporationSF, hasAISF, hasBladeburnerSF};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Player} from "./Player";
|
||||
import {Gang} from "./Gang";
|
||||
import {makeRuntimeRejectMsg} from "./NetscriptEvaluator";
|
||||
import { Player } from "./Player";
|
||||
import { Gang } from "./Gang";
|
||||
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
||||
|
||||
export function unknownGangApiExceptionMessage(functionName, err) {
|
||||
return `gang.${functionName}() failed with exception: ` + err;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {makeRuntimeRejectMsg} from "./NetscriptEvaluator";
|
||||
import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
||||
|
||||
// Makes a blob that contains the code of a given script.
|
||||
export function makeScriptBlob(code) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Settings} from "./Settings/Settings";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
|
||||
function NetscriptPort() {
|
||||
this.data = [];
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
import {addActiveScriptsItem,
|
||||
deleteActiveScriptsItem,
|
||||
updateActiveScriptsItems} from "./ActiveScriptsUI";
|
||||
import {CONSTANTS} from "./Constants";
|
||||
import {Engine} from "./engine";
|
||||
import {Interpreter} from "./JSInterpreter";
|
||||
import {Environment} from "./NetscriptEnvironment";
|
||||
import {evaluate, isScriptErrorMessage,
|
||||
makeRuntimeRejectMsg,
|
||||
killNetscriptDelay} from "./NetscriptEvaluator";
|
||||
import {NetscriptFunctions} from "./NetscriptFunctions";
|
||||
import {executeJSScript} from "./NetscriptJSEvaluator";
|
||||
import {NetscriptPort} from "./NetscriptPort";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import {Settings} from "./Settings/Settings";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import {
|
||||
addActiveScriptsItem,
|
||||
deleteActiveScriptsItem,
|
||||
updateActiveScriptsItems
|
||||
} from "./ActiveScriptsUI";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { Interpreter } from "./JSInterpreter";
|
||||
import { Environment } from "./NetscriptEnvironment";
|
||||
import {
|
||||
evaluate,
|
||||
isScriptErrorMessage,
|
||||
makeRuntimeRejectMsg,
|
||||
killNetscriptDelay
|
||||
} from "./NetscriptEvaluator";
|
||||
import { NetscriptFunctions } from "./NetscriptFunctions";
|
||||
import { executeJSScript } from "./NetscriptJSEvaluator";
|
||||
import { NetscriptPort } from "./NetscriptPort";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import {generate} from 'escodegen';
|
||||
import { generate } from "escodegen";
|
||||
|
||||
import { parse, Node } from "../utils/acorn";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { compareArrays } from "../utils/helpers/compareArrays";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||
import { isString } from "../utils/StringHelperFunctions";
|
||||
|
||||
import {parse, Node} from "../utils/acorn";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
import {compareArrays} from "../utils/helpers/compareArrays";
|
||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
||||
import {isString} from "../utils/StringHelperFunctions";
|
||||
|
||||
const walk = require("acorn/dist/walk");
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugment
|
||||
import { Company } from "../Company/Company";
|
||||
import { CompanyPosition } from "../Company/CompanyPosition";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { HashManager } from "../Hacknet/HashManager";
|
||||
import { HacknetNode } from "../Hacknet/HacknetNode";
|
||||
import { LocationName } from "../Locations/data/LocationNames";
|
||||
@@ -114,6 +115,7 @@ export interface IPlayer {
|
||||
applyForWaiterJob(sing?: boolean): boolean | void;
|
||||
canAccessBladeburner(): boolean;
|
||||
canAccessCorporation(): boolean;
|
||||
canAccessGang(): boolean;
|
||||
canAccessResleeving(): boolean;
|
||||
canAfford(cost: number): boolean;
|
||||
gainHackingExp(exp: number): void;
|
||||
@@ -124,6 +126,7 @@ export interface IPlayer {
|
||||
gainCharismaExp(exp: number): void;
|
||||
gainMoney(money: number): void;
|
||||
getCurrentServer(): Server;
|
||||
getGangName(): string;
|
||||
getHomeComputer(): Server;
|
||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
|
||||
getUpgradeHomeRamCost(): number;
|
||||
@@ -151,6 +154,10 @@ export interface IPlayer {
|
||||
money: number,
|
||||
time: number,
|
||||
singParams: any): void;
|
||||
startFactionFieldWork(faction: Faction): void;
|
||||
startFactionHackWork(faction: Faction): void;
|
||||
startFactionSecurityWork(faction: Faction): void;
|
||||
startGang(facName: string, isHacking: boolean): void;
|
||||
startWork(companyName: string): void;
|
||||
startWorkPartTime(companyName: string): void;
|
||||
travel(to: CityName): boolean;
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
||||
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
|
||||
import * as corporationMethods from "./PlayerObjectCorporationMethods";
|
||||
import * as gangMethods from "./PlayerObjectGangMethods";
|
||||
import * as generalMethods from "./PlayerObjectGeneralMethods";
|
||||
import * as serverMethods from "./PlayerObjectServerMethods";
|
||||
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON } from "../../../utils/JSONReviver";
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON
|
||||
} from "../../../utils/JSONReviver";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
export function PlayerObject() {
|
||||
//Skills and stats
|
||||
@@ -199,7 +202,15 @@ export function PlayerObject() {
|
||||
this.scriptProdSinceLastAug = 0;
|
||||
};
|
||||
|
||||
Object.assign(PlayerObject.prototype, generalMethods, serverMethods, bladeburnerMethods, corporationMethods);
|
||||
// Apply player methods to the prototype using Object.assign()
|
||||
Object.assign(
|
||||
PlayerObject.prototype,
|
||||
generalMethods,
|
||||
serverMethods,
|
||||
bladeburnerMethods,
|
||||
corporationMethods,
|
||||
gangMethods
|
||||
);
|
||||
|
||||
PlayerObject.prototype.toJSON = function() {
|
||||
return Generic_toJSON("PlayerObject", this);
|
||||
|
||||
34
src/PersonObjects/Player/PlayerObjectGangMethods.js
Normal file
34
src/PersonObjects/Player/PlayerObjectGangMethods.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Gang } from "../../Gang";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
// Amount of negative karma needed to manage a gang in BitNodes other than 2
|
||||
const GangKarmaRequirement = -54000;
|
||||
|
||||
export function canAccessGang() {
|
||||
if (this.bitNodeN === 2) { return true; }
|
||||
|
||||
if (SourceFileFlags[2] <= 0) { return false; }
|
||||
|
||||
return (this.karma <= GangKarmaRequirement);
|
||||
}
|
||||
|
||||
export function getGangName() {
|
||||
return this.gang.facName;
|
||||
}
|
||||
|
||||
export function inGang() {
|
||||
if (this.gang == null || this.gang == undefined) { return false; }
|
||||
|
||||
return (this.gang instanceof Gang);
|
||||
}
|
||||
|
||||
export function startGang(factionName, hacking) {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
|
||||
const fac = Factions[factionName];
|
||||
if (fac == null) {
|
||||
throw new Error(`Invalid faction name when creating gang: ${factionName}`);
|
||||
}
|
||||
fac.playerReputation = 0;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import {Engine} from "../../engine";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
import {Gang, resetGangs} from "../../Gang";
|
||||
import { resetGangs } from "../../Gang";
|
||||
import { hasHacknetServers } from "../../Hacknet/HacknetHelpers";
|
||||
import { HashManager } from "../../Hacknet/HashManager";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
@@ -150,8 +150,9 @@ export function prestigeAugmentation() {
|
||||
this.moneySourceA.reset();
|
||||
|
||||
this.hacknetNodes.length = 0;
|
||||
this.hashManager.prestige(this);
|
||||
|
||||
//Re-calculate skills and reset HP
|
||||
// Re-calculate skills and reset HP
|
||||
this.updateSkillLevels();
|
||||
this.hp = this.max_hp;
|
||||
}
|
||||
@@ -239,18 +240,19 @@ export function prestigeSourceFile() {
|
||||
this.lastUpdate = new Date().getTime();
|
||||
|
||||
this.hacknetNodes.length = 0;
|
||||
this.hashManager.prestige(this);
|
||||
|
||||
//Gang
|
||||
// Gang
|
||||
this.gang = null;
|
||||
resetGangs();
|
||||
|
||||
//Reset Stock market
|
||||
// Reset Stock market
|
||||
this.hasWseAccount = false;
|
||||
this.hasTixApiAccess = false;
|
||||
this.has4SData = false;
|
||||
this.has4SDataTixApi = false;
|
||||
|
||||
//BitNode 3: Corporatocracy
|
||||
// BitNode 3: Corporatocracy
|
||||
this.corporation = 0;
|
||||
|
||||
// Statistics trackers
|
||||
@@ -2174,18 +2176,6 @@ export function checkForFactionInvitations() {
|
||||
return invitedFactions;
|
||||
}
|
||||
|
||||
|
||||
/*************** Gang ****************/
|
||||
//Returns true if Player is in a gang and false otherwise
|
||||
export function inGang() {
|
||||
if (this.gang == null || this.gang == undefined) {return false;}
|
||||
return (this.gang instanceof Gang);
|
||||
}
|
||||
|
||||
export function startGang(factionName, hacking) {
|
||||
this.gang = new Gang(factionName, hacking);
|
||||
}
|
||||
|
||||
/************* BitNodes **************/
|
||||
export function setBitNodeNumber(n) {
|
||||
this.bitNodeN = n;
|
||||
|
||||
@@ -10,7 +10,7 @@ export let Player = new PlayerObject();
|
||||
export function loadPlayer(saveString) {
|
||||
Player = JSON.parse(saveString, Reviver);
|
||||
|
||||
//Parse Decimal.js objects
|
||||
// Parse Decimal.js objects
|
||||
Player.money = new Decimal(Player.money);
|
||||
|
||||
if (Player.corporation instanceof Corporation) {
|
||||
|
||||
181
src/Prestige.js
181
src/Prestige.js
@@ -1,57 +1,70 @@
|
||||
import {deleteActiveScriptsItem} from "./ActiveScriptsUI";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import { augmentationExists,
|
||||
initAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||
import {Bladeburner} from "./Bladeburner";
|
||||
import {writeCinematicText} from "./CinematicText";
|
||||
import {Companies, initCompanies} from "./Company/Companies";
|
||||
import { resetIndustryResearchTrees } from "./Corporation/IndustryData";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import {Engine} from "./engine";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { Factions,
|
||||
initFactions } from "./Faction/Factions";
|
||||
import { joinFaction } from "./Faction/FactionHelpers";
|
||||
import {deleteGangDisplayContent} from "./Gang";
|
||||
import { Message } from "./Message/Message";
|
||||
import { initMessages,
|
||||
Messages } from "./Message/MessageHelpers";
|
||||
import {initSingularitySFFlags, hasWallStreetSF}from "./NetscriptFunctions";
|
||||
import {WorkerScript, workerScripts,
|
||||
prestigeWorkerScripts} from "./NetscriptWorker";
|
||||
import {Player} from "./Player";
|
||||
import { deleteActiveScriptsItem } from "./ActiveScriptsUI";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import {
|
||||
augmentationExists,
|
||||
initAugmentations
|
||||
} from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { writeCinematicText } from "./CinematicText";
|
||||
import { Companies, initCompanies } from "./Company/Companies";
|
||||
import { resetIndustryResearchTrees } from "./Corporation/IndustryData";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { Engine } from "./engine";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { Factions, initFactions } from "./Faction/Factions";
|
||||
import { joinFaction } from "./Faction/FactionHelpers";
|
||||
import { deleteGangDisplayContent } from "./Gang";
|
||||
import { Message } from "./Message/Message";
|
||||
import { initMessages, Messages } from "./Message/MessageHelpers";
|
||||
import { initSingularitySFFlags, hasWallStreetSF } from "./NetscriptFunctions";
|
||||
import {
|
||||
WorkerScript,
|
||||
workerScripts,
|
||||
prestigeWorkerScripts
|
||||
} from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
|
||||
import { AllServers,
|
||||
AddToAllServers,
|
||||
initForeignServers,
|
||||
prestigeAllServers } from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server"
|
||||
import { prestigeHomeComputer } from "./Server/ServerHelpers";
|
||||
import { SourceFileFlags,
|
||||
updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { SpecialServerIps,
|
||||
SpecialServerIpsMap,
|
||||
prestigeSpecialServerIps,
|
||||
SpecialServerNames} from "./Server/SpecialServerIps";
|
||||
import {initStockMarket, initSymbolToStockMap,
|
||||
stockMarketContentCreated,
|
||||
setStockMarketContentCreated} from "./StockMarket/StockMarket";
|
||||
import {Terminal, postNetburnerText} from "./Terminal";
|
||||
import {
|
||||
AllServers,
|
||||
AddToAllServers,
|
||||
initForeignServers,
|
||||
prestigeAllServers
|
||||
} from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import { prestigeHomeComputer } from "./Server/ServerHelpers";
|
||||
import {
|
||||
SourceFileFlags,
|
||||
updateSourceFileFlags
|
||||
} from "./SourceFile/SourceFileFlags";
|
||||
import {
|
||||
SpecialServerIps,
|
||||
SpecialServerIpsMap,
|
||||
prestigeSpecialServerIps,
|
||||
SpecialServerNames
|
||||
} from "./Server/SpecialServerIps";
|
||||
import {
|
||||
initStockMarket,
|
||||
initSymbolToStockMap,
|
||||
stockMarketContentCreated,
|
||||
setStockMarketContentCreated
|
||||
} from "./StockMarket/StockMarket";
|
||||
import { Terminal, postNetburnerText } from "./Terminal";
|
||||
|
||||
import {Page, routing} from "./ui/navigationTracking";
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
import {removeElementById} from "../utils/uiHelpers/removeElementById";
|
||||
import {createElement} from "../utils/uiHelpers/createElement";
|
||||
import {createPopup} from "../utils/uiHelpers/createPopup";
|
||||
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
|
||||
let BitNode8StartingMoney = 250e6;
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
//Prestige by purchasing augmentation
|
||||
const BitNode8StartingMoney = 250e6;
|
||||
|
||||
// Prestige by purchasing augmentation
|
||||
function prestigeAugmentation() {
|
||||
// Set Navigation to Terminal screen, for any logic that depends on it
|
||||
routing.navigateTo(Page.Terminal);
|
||||
@@ -68,17 +81,17 @@ function prestigeAugmentation() {
|
||||
$("#terminal tr:not(:last)").remove();
|
||||
postNetburnerText();
|
||||
|
||||
//Delete all Worker Scripts objects
|
||||
// Delete all Worker Scripts objects
|
||||
prestigeWorkerScripts();
|
||||
|
||||
var homeComp = Player.getHomeComputer();
|
||||
//Delete all servers except home computer
|
||||
// Delete all servers except home computer
|
||||
prestigeAllServers();
|
||||
|
||||
//Delete Special Server IPs
|
||||
prestigeSpecialServerIps(); //Must be done before initForeignServers()
|
||||
// Delete Special Server IPs
|
||||
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);
|
||||
prestigeHomeComputer(homeComp);
|
||||
|
||||
@@ -93,59 +106,59 @@ function prestigeAugmentation() {
|
||||
homeComp.programs.push(Programs.BruteSSHProgram.name);
|
||||
}
|
||||
|
||||
//Re-create foreign servers
|
||||
// Re-create foreign servers
|
||||
initForeignServers(Player.getHomeComputer());
|
||||
|
||||
//Gain favor for Companies
|
||||
// Gain favor for Companies
|
||||
for (var member in Companies) {
|
||||
if (Companies.hasOwnProperty(member)) {
|
||||
Companies[member].gainFavor();
|
||||
}
|
||||
}
|
||||
|
||||
//Gain favor for factions
|
||||
// Gain favor for factions
|
||||
for (var member in Factions) {
|
||||
if (Factions.hasOwnProperty(member)) {
|
||||
Factions[member].gainFavor();
|
||||
}
|
||||
}
|
||||
|
||||
//Stop a Terminal action if there is onerror
|
||||
// Stop a Terminal action if there is onerror
|
||||
if (Engine._actionInProgress) {
|
||||
Engine._actionInProgress = false;
|
||||
Terminal.finishAction(true);
|
||||
}
|
||||
|
||||
//Re-initialize things - This will update any changes
|
||||
initFactions(); //Factions must be initialized before augmentations
|
||||
initAugmentations(); //Calls reapplyAllAugmentations() and resets Player multipliers
|
||||
// Re-initialize things - This will update any changes
|
||||
initFactions(); // Factions must be initialized before augmentations
|
||||
initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
|
||||
Player.reapplyAllSourceFiles();
|
||||
initCompanies();
|
||||
|
||||
//Messages
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
//Gang, in BitNode 2
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
var faction = Factions[Player.gang.facName];
|
||||
// Gang
|
||||
if (Player.inGang()) {
|
||||
const faction = Factions[Player.gang.facName];
|
||||
if (faction instanceof Faction) {
|
||||
joinFaction(faction);
|
||||
}
|
||||
}
|
||||
|
||||
//Cancel Bladeburner action
|
||||
// Cancel Bladeburner action
|
||||
if (Player.bladeburner instanceof Bladeburner) {
|
||||
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 || hasWallStreetSF) {
|
||||
Player.hasWseAccount = true;
|
||||
Player.hasTixApiAccess = true;
|
||||
}
|
||||
|
||||
//Reset Stock market
|
||||
// Reset Stock market
|
||||
if (Player.hasWseAccount) {
|
||||
initStockMarket();
|
||||
initSymbolToStockMap();
|
||||
@@ -156,13 +169,13 @@ function prestigeAugmentation() {
|
||||
stockMarketList.removeChild(stockMarketList.firstChild);
|
||||
}
|
||||
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)
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
|
||||
//Red Pill
|
||||
// Red Pill
|
||||
if (augmentationExists(AugmentationNames.TheRedPill) &&
|
||||
Augmentations[AugmentationNames.TheRedPill].owned) {
|
||||
var WorldDaemon = AllServers[SpecialServerIps[SpecialServerNames.WorldDaemon]];
|
||||
@@ -175,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() {
|
||||
initBitNodeMultipliers(Player);
|
||||
updateSourceFileFlags(Player);
|
||||
|
||||
Player.prestigeSourceFile();
|
||||
prestigeWorkerScripts(); //Delete all Worker Scripts objects
|
||||
prestigeWorkerScripts(); // Delete all Worker Scripts objects
|
||||
|
||||
var homeComp = Player.getHomeComputer();
|
||||
|
||||
//Delete all servers except home computer
|
||||
prestigeAllServers(); //Must be done before initForeignServers()
|
||||
// Delete all servers except home computer
|
||||
prestigeAllServers(); // Must be done before initForeignServers()
|
||||
|
||||
//Delete Special Server IPs
|
||||
// Delete Special Server IPs
|
||||
prestigeSpecialServerIps();
|
||||
|
||||
//Reset home computer (only the programs) and add to AllServers
|
||||
// Reset home computer (only the programs) and add to AllServers
|
||||
AddToAllServers(homeComp);
|
||||
prestigeHomeComputer(homeComp);
|
||||
|
||||
//Re-create foreign servers
|
||||
// Re-create foreign servers
|
||||
initForeignServers(Player.getHomeComputer());
|
||||
|
||||
if (SourceFileFlags[9] >= 2) {
|
||||
@@ -240,11 +253,11 @@ function prestigeSourceFile() {
|
||||
Player.reapplyAllSourceFiles();
|
||||
initCompanies();
|
||||
|
||||
//Clear terminal
|
||||
// Clear terminal
|
||||
$("#terminal tr:not(:last)").remove();
|
||||
postNetburnerText();
|
||||
|
||||
//Messages
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
@@ -252,17 +265,17 @@ function prestigeSourceFile() {
|
||||
Terminal.resetTerminalInput();
|
||||
Engine.loadTerminalContent();
|
||||
|
||||
//Reinitialize Bit Node flags
|
||||
// Reinitialize Bit Node flags
|
||||
initSingularitySFFlags();
|
||||
|
||||
//BitNode 3: Corporatocracy
|
||||
// BitNode 3: Corporatocracy
|
||||
if (Player.bitNodeN === 3) {
|
||||
homeComp.messages.push("corporation-management-handbook.lit");
|
||||
dialogBoxCreate("You received a copy of the Corporation Management Handbook on your home computer. " +
|
||||
"Read it if you need help getting started with Corporations!");
|
||||
}
|
||||
|
||||
//BitNode 6: Bladeburner
|
||||
// BitNode 6: Bladeburner
|
||||
if (Player.bitNodeN === 6) {
|
||||
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.",
|
||||
@@ -306,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 || hasWallStreetSF) {
|
||||
Player.hasWseAccount = true;
|
||||
@@ -350,7 +363,7 @@ function prestigeSourceFile() {
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
|
||||
//Gain int exp
|
||||
// Gain int exp
|
||||
Player.gainIntelligenceExp(5);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
import { BitNodes } from "./BitNode/BitNode";
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeSourceFile } from "./Prestige";
|
||||
import { SourceFiles,
|
||||
SourceFile } from "./SourceFile";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
import { Terminal } from "./Terminal";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
/**
|
||||
* Implementation for what happens when you destroy a BitNode
|
||||
*/
|
||||
import { BitNodes } from "./BitNode/BitNode";
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeSourceFile } from "./Prestige";
|
||||
import { SourceFiles, SourceFile } from "./SourceFile";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
import { Terminal } from "./Terminal";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import {yesNoBoxCreate, yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import {
|
||||
yesNoBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxClose
|
||||
} from "../utils/YesNoBox";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
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) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var container = document.getElementById("red-pill-content");
|
||||
@@ -96,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) {
|
||||
var sourceFileKey = "SourceFile"+ bitNodeNumber.toString();
|
||||
var sourceFile = SourceFiles[sourceFileKey];
|
||||
@@ -106,7 +110,7 @@ function giveSourceFile(bitNodeNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if player already has this source file
|
||||
// Check if player already has this source file
|
||||
var alreadyOwned = false;
|
||||
var ownedSourceFile = null;
|
||||
for (var i = 0; i < Player.sourceFiles.length; ++i) {
|
||||
@@ -129,7 +133,7 @@ function giveSourceFile(bitNodeNumber) {
|
||||
} else {
|
||||
var playerSrcFile = new PlayerOwnedSourceFile(bitNodeNumber, 1);
|
||||
Player.sourceFiles.push(playerSrcFile);
|
||||
if (bitNodeNumber === 5) { //Artificial Intelligence
|
||||
if (bitNodeNumber === 5) { // Artificial Intelligence
|
||||
Player.intelligence = 1;
|
||||
}
|
||||
dialogBoxCreate("You received a Source-File for destroying a Bit Node!<br><br>" +
|
||||
@@ -138,11 +142,11 @@ function giveSourceFile(bitNodeNumber) {
|
||||
}
|
||||
|
||||
function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
||||
//Clear the screen
|
||||
// Clear the screen
|
||||
var container = document.getElementById("red-pill-content");
|
||||
removeChildrenFromElement(container);
|
||||
|
||||
//Create the Bit Verse
|
||||
// Create the Bit Verse
|
||||
var bitVerseImage = document.createElement("pre");
|
||||
var bitNodes = [];
|
||||
for (var i = 1; i <= 12; ++i) {
|
||||
@@ -207,7 +211,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
||||
|
||||
container.appendChild(bitVerseImage);
|
||||
|
||||
//Bit node event listeners
|
||||
// Bit node event listeners
|
||||
for (var i = 1; i <= 12; ++i) {
|
||||
(function(i) {
|
||||
var elemId = "bitnode-" + i.toString();
|
||||
@@ -229,10 +233,10 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
||||
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("Our species fought back, but it was futile. The Enders had technology far beyond our own...");
|
||||
}).then(function() {
|
||||
@@ -281,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) {
|
||||
var bitNodeStr = "BitNode" + n.toString();
|
||||
var bitNode = BitNodes[bitNodeStr];
|
||||
@@ -300,19 +304,19 @@ function createBitNodeYesNoEventListeners(newBitNode, destroyedBitNode, flume=fa
|
||||
if (!flume) {
|
||||
giveSourceFile(destroyedBitNode);
|
||||
} else {
|
||||
//If player used flume, subtract 5 int exp. The prestigeSourceFile()
|
||||
//function below grants 5 int exp, so this allows sets net gain to 0
|
||||
// If player used flume, subtract 5 int exp. The prestigeSourceFile()
|
||||
// function below grants 5 int exp, so this allows sets net gain to 0
|
||||
Player.gainIntelligenceExp(-5);
|
||||
}
|
||||
redPillFlag = false;
|
||||
var container = document.getElementById("red-pill-content");
|
||||
removeChildrenFromElement(container);
|
||||
|
||||
//Set new Bit Node
|
||||
// Set new Bit Node
|
||||
Player.bitNodeN = newBitNode;
|
||||
console.log("Entering Bit Node " + Player.bitNodeN);
|
||||
|
||||
//Reenable terminal
|
||||
// Reenable terminal
|
||||
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
||||
$("#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"/>';
|
||||
|
||||
@@ -1,41 +1,52 @@
|
||||
import {loadAliases, loadGlobalAliases,
|
||||
Aliases, GlobalAliases} from "./Alias";
|
||||
import {Companies, loadCompanies} from "./Company/Companies";
|
||||
import {CompanyPosition} from "./Company/CompanyPosition";
|
||||
import {CONSTANTS} from "./Constants";
|
||||
import {Engine} from "./engine";
|
||||
import { Factions,
|
||||
loadFactions } from "./Faction/Factions";
|
||||
import { processPassiveFactionRepGain } from "./Faction/FactionHelpers";
|
||||
import { loadFconf } from "./Fconf/Fconf";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import {loadAllGangs, AllGangs} from "./Gang";
|
||||
import { hasHacknetServers,
|
||||
processHacknetEarnings } from "./Hacknet/HacknetHelpers";
|
||||
import {
|
||||
loadAliases,
|
||||
loadGlobalAliases,
|
||||
Aliases,
|
||||
GlobalAliases
|
||||
} from "./Alias";
|
||||
import { Companies, loadCompanies } from "./Company/Companies";
|
||||
import { CompanyPosition } from "./Company/CompanyPosition";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { Factions, loadFactions } from "./Faction/Factions";
|
||||
import { processPassiveFactionRepGain } from "./Faction/FactionHelpers";
|
||||
import { loadFconf } from "./Fconf/Fconf";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import { loadAllGangs, AllGangs } from "./Gang";
|
||||
import {
|
||||
hasHacknetServers,
|
||||
processHacknetEarnings
|
||||
} from "./Hacknet/HacknetHelpers";
|
||||
import { loadMessages, initMessages, Messages } from "./Message/MessageHelpers";
|
||||
import {Player, loadPlayer} from "./Player";
|
||||
import { loadAllRunningScripts } from "./Script/ScriptHelpers";
|
||||
import { AllServers,
|
||||
loadAllServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { loadSpecialServerIps,
|
||||
SpecialServerIps } from "./Server/SpecialServerIps";
|
||||
import {loadStockMarket, StockMarket} from "./StockMarket/StockMarket";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { Player, loadPlayer } from "./Player";
|
||||
import { loadAllRunningScripts } from "./Script/ScriptHelpers";
|
||||
import { AllServers, loadAllServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import {
|
||||
loadSpecialServerIps,
|
||||
SpecialServerIps
|
||||
} from "./Server/SpecialServerIps";
|
||||
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
|
||||
|
||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||
import {gameOptionsBoxClose} from "../utils/GameOptions";
|
||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
||||
import {Reviver, Generic_toJSON,
|
||||
Generic_fromJSON} from "../utils/JSONReviver";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
import {createElement} from "../utils/uiHelpers/createElement";
|
||||
import {createPopup} from "../utils/uiHelpers/createPopup";
|
||||
import {createStatusText} from "./ui/createStatusText";
|
||||
import {numeralWrapper} from "./ui/numeralFormat";
|
||||
import {removeElementById} from "../utils/uiHelpers/removeElementById";
|
||||
import { createStatusText } from "./ui/createStatusText";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { gameOptionsBoxClose } from "../utils/GameOptions";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import {
|
||||
Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON
|
||||
} from "../utils/JSONReviver";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
/* SaveObject.js
|
||||
* Defines the object used to save/load games
|
||||
@@ -61,7 +72,7 @@ function BitburnerSaveObject() {
|
||||
BitburnerSaveObject.prototype.getSaveString = function() {
|
||||
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);
|
||||
for (var ip in TempAllServers) {
|
||||
var server = TempAllServers[ip];
|
||||
@@ -84,7 +95,7 @@ BitburnerSaveObject.prototype.getSaveString = function() {
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.FconfSettingsSave = JSON.stringify(FconfSettings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||
}
|
||||
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
||||
@@ -95,7 +106,7 @@ BitburnerSaveObject.prototype.getSaveString = function() {
|
||||
BitburnerSaveObject.prototype.saveGame = function(db) {
|
||||
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 request = objectStore.put(saveString, "save");
|
||||
|
||||
@@ -104,12 +115,11 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
|
||||
}
|
||||
|
||||
request.onsuccess = function(e) {
|
||||
//console.log("Saved game to IndexedDB!");
|
||||
// TODO anything here?
|
||||
}
|
||||
|
||||
try {
|
||||
window.localStorage.setItem("bitburnerSave", saveString);
|
||||
//console.log("Saved game to LocalStorage!");
|
||||
} catch(e) {
|
||||
if (e.code == 22) {
|
||||
createStatusText("Save failed for localStorage! Check console(F12)");
|
||||
@@ -249,7 +259,7 @@ function loadGame(saveString) {
|
||||
evaluateVersionCompatibility(ver);
|
||||
|
||||
if (window.location.href.toLowerCase().includes("bitburner-beta")) {
|
||||
//Beta branch, always show changes
|
||||
// Beta branch, always show changes
|
||||
createBetaUpdateText();
|
||||
} else if (ver != CONSTANTS.Version) {
|
||||
createNewUpdateText();
|
||||
@@ -260,7 +270,7 @@ function loadGame(saveString) {
|
||||
} else {
|
||||
createNewUpdateText();
|
||||
}
|
||||
if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(saveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
@@ -285,8 +295,8 @@ function loadImportedGame(saveObj, saveString) {
|
||||
var tempAllGangs = null;
|
||||
let tempCorporationResearchTrees = null;
|
||||
|
||||
//Check to see if the imported save file can be parsed. If any
|
||||
//errors are caught it will fail
|
||||
// Check to see if the imported save file can be parsed. If any
|
||||
// errors are caught it will fail
|
||||
try {
|
||||
var decodedSaveString = decodeURIComponent(escape(atob(saveString)));
|
||||
tempSaveObj = new BitburnerSaveObject();
|
||||
@@ -294,7 +304,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
|
||||
tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver);
|
||||
|
||||
//Parse Decimal.js objects
|
||||
// Parse Decimal.js objects
|
||||
tempPlayer.money = new Decimal(tempPlayer.money);
|
||||
|
||||
tempAllServers = JSON.parse(tempSaveObj.AllServersSave, Reviver);
|
||||
@@ -350,7 +360,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (tempPlayer.bitNodeN == 2 && tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
||||
if (tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(tempSaveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
@@ -363,7 +373,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
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)));
|
||||
saveObj = JSON.parse(saveString, Reviver);
|
||||
|
||||
@@ -439,7 +449,7 @@ function loadImportedGame(saveObj, saveString) {
|
||||
} else {
|
||||
createNewUpdateText();
|
||||
}
|
||||
if (Player.bitNodeN == 2 && Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(saveObj.AllGangsSave);
|
||||
} catch(e) {
|
||||
@@ -461,18 +471,18 @@ function loadImportedGame(saveObj, saveString) {
|
||||
createPopup(popupId, [txt, gotitBtn]);
|
||||
gameOptionsBoxClose();
|
||||
|
||||
//Re-start game
|
||||
// Re-start game
|
||||
console.log("Importing game");
|
||||
Engine.setDisplayElements(); //Sets variables for important DOM elements
|
||||
Engine.init(); //Initialize buttons, work, etc.
|
||||
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
||||
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();
|
||||
var lastUpdate = Player.lastUpdate;
|
||||
var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed);
|
||||
|
||||
/* Process offline progress */
|
||||
var offlineProductionFromScripts = loadAllRunningScripts(); //This also takes care of offline production for those scripts
|
||||
// Process offline progress
|
||||
var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
|
||||
if (Player.isWorking) {
|
||||
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
|
||||
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
||||
@@ -490,16 +500,16 @@ function loadImportedGame(saveObj, saveString) {
|
||||
}
|
||||
}
|
||||
|
||||
//Hacknet Nodes offline progress
|
||||
// Hacknet Nodes offline progress
|
||||
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
||||
const hacknetProdInfo = hasHacknetServers() ?
|
||||
`${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` :
|
||||
`${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`;
|
||||
|
||||
//Passive faction rep gain offline
|
||||
// Passive faction rep gain offline
|
||||
processPassiveFactionRepGain(numCyclesOffline);
|
||||
|
||||
//Update total playtime
|
||||
// Update total playtime
|
||||
var time = numCyclesOffline * Engine._idleSpeed;
|
||||
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
|
||||
if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;}
|
||||
@@ -508,14 +518,14 @@ function loadImportedGame(saveObj, saveString) {
|
||||
Player.playtimeSinceLastAug += time;
|
||||
Player.playtimeSinceLastBitnode += time;
|
||||
|
||||
//Re-apply augmentations
|
||||
// Re-apply augmentations
|
||||
Player.reapplyAllAugmentations();
|
||||
|
||||
//Clear terminal
|
||||
// Clear terminal
|
||||
$("#terminal tr:not(:last)").remove();
|
||||
|
||||
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);
|
||||
dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` +
|
||||
"generated <span class='money-gold'>" +
|
||||
@@ -536,7 +546,7 @@ BitburnerSaveObject.prototype.exportGame = function() {
|
||||
this.StockMarketSave = JSON.stringify(StockMarket);
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
this.AllGangsSave = JSON.stringify(AllGangs);
|
||||
}
|
||||
|
||||
@@ -571,12 +581,12 @@ BitburnerSaveObject.prototype.importGame = function() {
|
||||
}
|
||||
|
||||
BitburnerSaveObject.prototype.deleteGame = function(db) {
|
||||
//Delete from local storage
|
||||
// Delete from local storage
|
||||
if (window.localStorage.getItem("bitburnerSave")) {
|
||||
window.localStorage.removeItem("bitburnerSave");
|
||||
}
|
||||
|
||||
//Delete from indexedDB
|
||||
// Delete from indexedDB
|
||||
var request = db.transaction(["savestring"], "readwrite").objectStore("savestring").delete("save");
|
||||
request.onsuccess = function(e) {
|
||||
console.log("Successfully deleted save from indexedDb");
|
||||
@@ -613,8 +623,6 @@ BitburnerSaveObject.fromJSON = function(value) {
|
||||
|
||||
Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject;
|
||||
|
||||
//Import game
|
||||
|
||||
function openImportFileHandler(evt) {
|
||||
var file = evt.target.files[0];
|
||||
if (!file) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Player } from "./Player";
|
||||
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="") {
|
||||
var bitnodeKey = "BitNode" + number;
|
||||
var bitnode = BitNodes[bitnodeKey];
|
||||
@@ -25,8 +24,9 @@ function initSourceFiles() {
|
||||
"Level 1: 16%<br>" +
|
||||
"Level 2: 24%<br>" +
|
||||
"Level 3: 28%");
|
||||
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " +
|
||||
"multipliers by:<br><br>" +
|
||||
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File allows you to form gangs in other BitNodes " +
|
||||
"once your karma decreases to a certain value. It also increases the player's " +
|
||||
"crime success rate, crime money, and charisma multipliers by:<br><br>" +
|
||||
"Level 1: 24%<br>" +
|
||||
"Level 2: 36%<br>" +
|
||||
"Level 3: 42%");
|
||||
@@ -80,7 +80,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)");
|
||||
}
|
||||
|
||||
//Takes in a PlayerOwnedSourceFile as the "srcFile" argument
|
||||
// Takes in a PlayerOwnedSourceFile as the "srcFile" argument
|
||||
function applySourceFile(srcFile) {
|
||||
var srcFileKey = "SourceFile" + srcFile.n;
|
||||
var sourceFileObject = SourceFiles[srcFileKey];
|
||||
|
||||
303
src/Terminal.js
303
src/Terminal.js
@@ -8,77 +8,85 @@ import {
|
||||
removeLeadingSlash,
|
||||
removeTrailingSlash
|
||||
} from "./Terminal/DirectoryHelpers";
|
||||
import { determineAllPossibilitiesForTabCompletion } from "./Terminal/determineAllPossibilitiesForTabCompletion";
|
||||
import { TerminalHelpText, HelpTexts } from "./Terminal/HelpText";
|
||||
import { tabCompletion } from "./Terminal/tabCompletion";
|
||||
|
||||
import {
|
||||
determineAllPossibilitiesForTabCompletion
|
||||
} from "./Terminal/determineAllPossibilitiesForTabCompletion";
|
||||
|
||||
Aliases,
|
||||
GlobalAliases,
|
||||
parseAliasDeclaration,
|
||||
printAliases,
|
||||
removeAlias,
|
||||
substituteAliases
|
||||
} from "./Alias";
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import {
|
||||
TerminalHelpText,
|
||||
HelpTexts
|
||||
} from "./Terminal/HelpText";
|
||||
|
||||
CodingContract,
|
||||
CodingContractResult,
|
||||
CodingContractRewardType
|
||||
} from "./CodingContracts";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import {
|
||||
tabCompletion
|
||||
} from "./Terminal/tabCompletion";
|
||||
|
||||
import { Aliases,
|
||||
GlobalAliases,
|
||||
parseAliasDeclaration,
|
||||
printAliases,
|
||||
removeAlias,
|
||||
substituteAliases } from "./Alias";
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import {CodingContract, CodingContractResult,
|
||||
CodingContractRewardType} from "./CodingContracts";
|
||||
import {CONSTANTS} from "./Constants";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { executeDarkwebTerminalCommand,
|
||||
checkIfConnectedToDarkweb } from "./DarkWeb/DarkWeb";
|
||||
import { DarkWebItems } from "./DarkWeb/DarkWebItems";
|
||||
import {Engine} from "./engine";
|
||||
import { parseFconfSettings,
|
||||
createFconf } from "./Fconf/Fconf";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import {calculateHackingChance,
|
||||
calculateHackingExpGain,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingTime,
|
||||
calculateGrowTime,
|
||||
calculateWeakenTime} from "./Hacking";
|
||||
import { HacknetServer } from "./Hacknet/HacknetServer";
|
||||
import {iTutorialNextStep, iTutorialSteps,
|
||||
ITutorial} from "./InteractiveTutorial";
|
||||
import {showLiterature} from "./Literature";
|
||||
import { Message } from "./Message/Message";
|
||||
import { showMessage } from "./Message/MessageHelpers";
|
||||
import {killWorkerScript, addWorkerScript} from "./NetscriptWorker";
|
||||
import {Player} from "./Player";
|
||||
import {hackWorldDaemon} from "./RedPill";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import { GetServerByHostname,
|
||||
getServer,
|
||||
getServerOnNetwork } from "./Server/ServerHelpers";
|
||||
import {Settings} from "./Settings/Settings";
|
||||
import { SpecialServerIps,
|
||||
SpecialServerNames } from "./Server/SpecialServerIps";
|
||||
import {getTextFile} from "./TextFile";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import {Page, routing} from "./ui/navigationTracking";
|
||||
import {numeralWrapper} from "./ui/numeralFormat";
|
||||
import {KEY} from "../utils/helpers/keyCodes";
|
||||
import {addOffset} from "../utils/helpers/addOffset";
|
||||
import {isString} from "../utils/helpers/isString";
|
||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||
import {getTimestamp} from "../utils/helpers/getTimestamp";
|
||||
import {logBoxCreate} from "../utils/LogBox";
|
||||
import {yesNoBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox";
|
||||
executeDarkwebTerminalCommand,
|
||||
checkIfConnectedToDarkweb
|
||||
} from "./DarkWeb/DarkWeb";
|
||||
import { DarkWebItems } from "./DarkWeb/DarkWebItems";
|
||||
import { Engine } from "./engine";
|
||||
import { parseFconfSettings, createFconf } from "./Fconf/Fconf";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import {
|
||||
calculateHackingChance,
|
||||
calculateHackingExpGain,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingTime,
|
||||
calculateGrowTime,
|
||||
calculateWeakenTime
|
||||
} from "./Hacking";
|
||||
import { HacknetServer } from "./Hacknet/HacknetServer";
|
||||
import {
|
||||
iTutorialNextStep,
|
||||
iTutorialSteps,
|
||||
ITutorial
|
||||
} from "./InteractiveTutorial";
|
||||
import { showLiterature } from "./Literature";
|
||||
import { Message } from "./Message/Message";
|
||||
import { showMessage } from "./Message/MessageHelpers";
|
||||
import { killWorkerScript, addWorkerScript } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { hackWorldDaemon } from "./RedPill";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import {
|
||||
GetServerByHostname,
|
||||
getServer,
|
||||
getServerOnNetwork
|
||||
} from "./Server/ServerHelpers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import {
|
||||
SpecialServerIps,
|
||||
SpecialServerNames
|
||||
} from "./Server/SpecialServerIps";
|
||||
import { getTextFile } from "./TextFile";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
import { addOffset } from "../utils/helpers/addOffset";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { getTimestamp } from "../utils/helpers/getTimestamp";
|
||||
import { logBoxCreate } from "../utils/LogBox";
|
||||
import {
|
||||
yesNoBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxClose
|
||||
} from "../utils/YesNoBox";
|
||||
import {
|
||||
post,
|
||||
postContent,
|
||||
@@ -87,9 +95,10 @@ import {
|
||||
hackProgressPost
|
||||
} from "./ui/postToTerminal";
|
||||
|
||||
import autosize from 'autosize';
|
||||
import * as JSZip from 'jszip';
|
||||
import * as FileSaver from 'file-saver';
|
||||
import autosize from "autosize";
|
||||
import * as JSZip from "jszip";
|
||||
import * as FileSaver from "file-saver";
|
||||
|
||||
|
||||
function postNetburnerText() {
|
||||
post("Bitburner v" + CONSTANTS.Version);
|
||||
@@ -103,13 +112,13 @@ function isNumber(str) {
|
||||
|
||||
// Defines key commands in terminal
|
||||
$(document).keydown(function(event) {
|
||||
//Terminal
|
||||
// Terminal
|
||||
if (routing.isOn(Page.Terminal)) {
|
||||
var terminalInput = document.getElementById("terminal-input-text-box");
|
||||
if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();}
|
||||
|
||||
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 dir = Terminal.currDir;
|
||||
post(
|
||||
@@ -120,35 +129,35 @@ $(document).keydown(function(event) {
|
||||
);
|
||||
|
||||
if (command.length > 0) {
|
||||
Terminal.resetTerminalInput(); //Clear input first
|
||||
Terminal.resetTerminalInput(); // Clear input first
|
||||
Terminal.executeCommands(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.keyCode === KEY.C && event.ctrlKey) {
|
||||
if (Engine._actionInProgress) {
|
||||
//Cancel action
|
||||
// Cancel action
|
||||
post("Cancelling...");
|
||||
Engine._actionInProgress = false;
|
||||
Terminal.finishAction(true);
|
||||
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
|
||||
//Dont prevent default so it still copies
|
||||
Terminal.resetTerminalInput(); //Clear Terminal
|
||||
// Dont prevent default so it still copies
|
||||
Terminal.resetTerminalInput(); // Clear Terminal
|
||||
}
|
||||
}
|
||||
|
||||
if (event.keyCode === KEY.L && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
Terminal.executeCommand("clear"); //Clear screen
|
||||
Terminal.executeCommand("clear"); // Clear screen
|
||||
}
|
||||
|
||||
//Ctrl p same as up arrow
|
||||
//Ctrl n same as down arrow
|
||||
// Ctrl p same as up arrow
|
||||
// Ctrl n same as down arrow
|
||||
|
||||
if (event.keyCode === KEY.UPARROW ||
|
||||
(FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.P && event.ctrlKey)) {
|
||||
if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();}
|
||||
//Cycle through past commands
|
||||
// Cycle through past commands
|
||||
if (terminalInput == null) {return;}
|
||||
var i = Terminal.commandHistoryIndex;
|
||||
var len = Terminal.commandHistory.length;
|
||||
@@ -169,7 +178,7 @@ $(document).keydown(function(event) {
|
||||
if (event.keyCode === KEY.DOWNARROW ||
|
||||
(FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.M && event.ctrlKey)) {
|
||||
if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();}
|
||||
//Cycle through past commands
|
||||
// Cycle through past commands
|
||||
if (terminalInput == null) {return;}
|
||||
var i = Terminal.commandHistoryIndex;
|
||||
var len = Terminal.commandHistory.length;
|
||||
@@ -179,7 +188,7 @@ $(document).keydown(function(event) {
|
||||
Terminal.commandHistoryIndex = len;
|
||||
}
|
||||
|
||||
//Latest command, put nothing
|
||||
// Latest command, put nothing
|
||||
if (i == len || i == len-1) {
|
||||
Terminal.commandHistoryIndex = len;
|
||||
terminalInput.value = "";
|
||||
@@ -193,7 +202,7 @@ $(document).keydown(function(event) {
|
||||
if (event.keyCode === KEY.TAB) {
|
||||
event.preventDefault();
|
||||
|
||||
//Autocomplete
|
||||
// Autocomplete
|
||||
if (terminalInput == null) {return;}
|
||||
var input = terminalInput.value;
|
||||
if (input == "") {return;}
|
||||
@@ -231,7 +240,7 @@ $(document).keydown(function(event) {
|
||||
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 (event.keyCode === KEY.A && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
@@ -269,17 +278,16 @@ $(document).keydown(function(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
//TODO AFTER THIS:
|
||||
|
||||
//alt + d deletes word after cursor
|
||||
//^w deletes word before cursor
|
||||
//^k clears line after cursor
|
||||
//^u clears line before cursor
|
||||
// TODO AFTER THIS:
|
||||
// alt + d deletes word after cursor
|
||||
// ^w deletes word before cursor
|
||||
// ^k clears line after cursor
|
||||
// ^u clears line before cursor
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Keep terminal in focus
|
||||
// Keep terminal in focus
|
||||
let terminalCtrlPressed = false, shiftKeyPressed = false;
|
||||
$(document).ready(function() {
|
||||
if (routing.isOn(Page.Terminal)) {
|
||||
@@ -294,7 +302,7 @@ $(document).keydown(function(e) {
|
||||
} else if (e.shiftKey) {
|
||||
shiftKeyPressed = true;
|
||||
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
|
||||
//Don't focus
|
||||
// Don't focus
|
||||
} else {
|
||||
var inputTextBox = document.getElementById("terminal-input-text-box");
|
||||
if (inputTextBox != null) {inputTextBox.focus();}
|
||||
@@ -340,7 +348,7 @@ let Terminal = {
|
||||
`<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"/>';
|
||||
|
||||
//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"));
|
||||
} else {
|
||||
document.getElementById("terminal-input-td").innerHTML =
|
||||
@@ -368,7 +376,7 @@ let Terminal = {
|
||||
terminalInput.value = inputText.substr(0, start-1) + inputText.substr(start);
|
||||
}
|
||||
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) {
|
||||
if (inputText.charAt(delStart) === " ") {
|
||||
terminalInput.value = inputText.substr(0, delStart) + inputText.substr(start);
|
||||
@@ -376,7 +384,7 @@ let Terminal = {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
if (inputText.charAt(delStart) === " ") {
|
||||
terminalInput.value = inputText.substr(0, start) + inputText.substr(delStart);
|
||||
@@ -384,9 +392,9 @@ let Terminal = {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "clearafter": //Deletes everything after cursor
|
||||
case "clearafter": // Deletes everything after cursor
|
||||
break;
|
||||
case "clearbefore:": //Deleetes everything before cursor
|
||||
case "clearbefore:": // Deleetes everything before cursor
|
||||
break;
|
||||
}
|
||||
} catch(e) {
|
||||
@@ -447,7 +455,7 @@ let Terminal = {
|
||||
startHack: function() {
|
||||
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.startAction();
|
||||
},
|
||||
@@ -465,7 +473,7 @@ let Terminal = {
|
||||
hackProgressPost("Time left:");
|
||||
hackProgressBarPost("[");
|
||||
|
||||
//Disable terminal
|
||||
// Disable terminal
|
||||
document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>';
|
||||
$('input[class=terminal-input]').prop('disabled', true);
|
||||
},
|
||||
@@ -478,17 +486,17 @@ let Terminal = {
|
||||
}
|
||||
},
|
||||
|
||||
//Complete the hack/analyze command
|
||||
// Complete the hack/analyze command
|
||||
finishHack: function(cancelled = false) {
|
||||
if (cancelled == false) {
|
||||
var server = Player.getCurrentServer();
|
||||
|
||||
//Calculate whether hack was successful
|
||||
// Calculate whether hack was successful
|
||||
var hackChance = calculateHackingChance(server);
|
||||
var rand = Math.random();
|
||||
var expGainedOnSuccess = calculateHackingExpGain(server);
|
||||
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
||||
if (rand < hackChance) { //Success!
|
||||
if (rand < hackChance) { // Success!
|
||||
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
||||
if (Player.bitNodeN == null) {
|
||||
@@ -501,7 +509,7 @@ let Terminal = {
|
||||
var moneyGained = calculatePercentMoneyHacked(server);
|
||||
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
||||
|
||||
if (moneyGained <= 0) {moneyGained = 0;} //Safety check
|
||||
if (moneyGained <= 0) {moneyGained = 0;} // Safety check
|
||||
|
||||
server.moneyAvailable -= moneyGained;
|
||||
Player.gainMoney(moneyGained);
|
||||
@@ -512,14 +520,14 @@ let Terminal = {
|
||||
server.fortify(CONSTANTS.ServerFortifyAmount);
|
||||
|
||||
post("Hack successful! Gained " + numeralWrapper.format(moneyGained, '($0,0.00)') + " and " + numeralWrapper.format(expGainedOnSuccess, '0.0000') + " hacking EXP");
|
||||
} else { //Failure
|
||||
//Player only gains 25% exp for failure? TODO Can change this later to balance
|
||||
} else { // Failure
|
||||
// Player only gains 25% exp for failure? TODO Can change this later to balance
|
||||
Player.gainHackingExp(expGainedOnFailure)
|
||||
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").attr('id', "old-hack-progress");
|
||||
Terminal.resetTerminalInput();
|
||||
@@ -587,7 +595,7 @@ let Terminal = {
|
||||
executeCommands : function(commands) {
|
||||
// Sanitize input
|
||||
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
|
||||
if (Terminal.commandHistory[Terminal.commandHistory.length-1] != commands) {
|
||||
@@ -635,7 +643,7 @@ let Terminal = {
|
||||
if (endQuote === command.length-1) {
|
||||
start = i = endQuote+1;
|
||||
} else {
|
||||
start = i = endQuote+2; //Skip the space
|
||||
start = i = endQuote+2; // Skip the space
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -654,7 +662,7 @@ let Terminal = {
|
||||
if (endQuote === command.length-1) {
|
||||
start = i = endQuote+1;
|
||||
} else {
|
||||
start = i = endQuote+2; //Skip the space
|
||||
start = i = endQuote+2; // Skip the space
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -696,15 +704,15 @@ let Terminal = {
|
||||
},
|
||||
|
||||
executeCommand : function(command) {
|
||||
//Process any aliases
|
||||
// Process any aliases
|
||||
command = substituteAliases(command);
|
||||
|
||||
//Allow usage of ./
|
||||
// Allow usage of ./
|
||||
if (command.startsWith("./")) {
|
||||
command = "run " + command.slice(2);
|
||||
}
|
||||
|
||||
//Only split the first space
|
||||
// Only split the first space
|
||||
var commandArray = Terminal.parseCommandArguments(command);
|
||||
if (commandArray.length == 0) { return; }
|
||||
|
||||
@@ -806,7 +814,7 @@ let Terminal = {
|
||||
case iTutorialSteps.ActiveScriptsToTerminal:
|
||||
if (commandArray.length == 2 &&
|
||||
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());
|
||||
if (runningScript == null) {
|
||||
post("Error: No such script exists");
|
||||
@@ -932,7 +940,7 @@ let Terminal = {
|
||||
postError("Incorrect number of arguments. Usage: check [script] [arg1] [arg2]...");
|
||||
} else {
|
||||
const scriptName = Terminal.getFilepath(commandArray[1]);
|
||||
//Can only tail script files
|
||||
// Can only tail script files
|
||||
if (!isScriptFilename(scriptName)) {
|
||||
postError("tail can only be called on .script files (filename must end with .script)");
|
||||
return;
|
||||
@@ -968,7 +976,7 @@ let Terminal = {
|
||||
postNetburnerText();
|
||||
break;
|
||||
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) {
|
||||
postError("Incorrect usage of connect command. Usage: connect [ip/hostname]");
|
||||
return;
|
||||
@@ -994,7 +1002,7 @@ let Terminal = {
|
||||
}
|
||||
const fn = commandArray[1];
|
||||
if (fn === "*" || fn === "*.script" || fn === "*.txt") {
|
||||
//Download all scripts as a zip
|
||||
// Download all scripts as a zip
|
||||
var zip = new JSZip();
|
||||
if (fn === "*" || fn === "*.script") {
|
||||
for (var i = 0; i < s.scripts.length; ++i) {
|
||||
@@ -1072,8 +1080,8 @@ let Terminal = {
|
||||
postError("Incorrect usage of hack command. Usage: hack");
|
||||
return;
|
||||
}
|
||||
//Hack the current PC (usually for money)
|
||||
//You can't hack your home pc or servers you purchased
|
||||
// Hack the current PC (usually for money)
|
||||
// You can't hack your home pc or servers you purchased
|
||||
if (s.purchasedByPlayer) {
|
||||
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 ) {
|
||||
@@ -1253,7 +1261,7 @@ let Terminal = {
|
||||
return;
|
||||
}
|
||||
|
||||
//Check programs
|
||||
// Check programs
|
||||
let delTarget = Terminal.getFilepath(commandArray[1]);
|
||||
|
||||
const status = s.removeFile(delTarget);
|
||||
@@ -1263,19 +1271,19 @@ let Terminal = {
|
||||
break;
|
||||
}
|
||||
case "run":
|
||||
//Run a program or a script
|
||||
// Run a program or a script
|
||||
if (commandArray.length < 2) {
|
||||
postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
|
||||
} else {
|
||||
var executableName = commandArray[1];
|
||||
|
||||
//Secret Music player!
|
||||
// Secret Music player!
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if its a script or just a program/executable
|
||||
// Check if its a script or just a program/executable
|
||||
if (isScriptFilename(executableName)) {
|
||||
Terminal.runScript(commandArray);
|
||||
} else if (executableName.endsWith(".cct")) {
|
||||
@@ -1425,20 +1433,20 @@ let Terminal = {
|
||||
post("Script Threads RAM Usage");
|
||||
|
||||
let currRunningScripts = s.runningScripts;
|
||||
//Iterate through scripts on current server
|
||||
// Iterate through scripts on current server
|
||||
for (let i = 0; i < currRunningScripts.length; i++) {
|
||||
let script = currRunningScripts[i];
|
||||
|
||||
//Calculate name padding
|
||||
let numSpacesScript = 32 - script.filename.length; //26 -> width of name column
|
||||
// Calculate name padding
|
||||
let numSpacesScript = 32 - script.filename.length; // 26 -> width of name column
|
||||
if (numSpacesScript < 0) {numSpacesScript = 0;}
|
||||
let spacesScript = Array(numSpacesScript+1).join(" ");
|
||||
|
||||
//Calculate thread padding
|
||||
let numSpacesThread = 16 - (script.threads + "").length; //16 -> width of thread column
|
||||
// Calculate thread padding
|
||||
let numSpacesThread = 16 - (script.threads + "").length; // 16 -> width of thread column
|
||||
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";
|
||||
|
||||
var entry = [script.filename, spacesScript, script.threads, spacesThread, ramUsage];
|
||||
@@ -1466,7 +1474,7 @@ let Terminal = {
|
||||
}
|
||||
|
||||
let url = commandArray[1];
|
||||
let target = comanndArray[2];
|
||||
let target = commandArray[2];
|
||||
if (!isScriptFilename(target) && !target.endsWith(".txt")) {
|
||||
return post(`wget failed: Invalid target file. Target file must be script or text file`);
|
||||
}
|
||||
@@ -1506,7 +1514,7 @@ let Terminal = {
|
||||
post("Connected to " + serv.hostname);
|
||||
Terminal.currDir = "/";
|
||||
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();
|
||||
},
|
||||
@@ -1597,7 +1605,7 @@ let Terminal = {
|
||||
prefix = null;
|
||||
}
|
||||
|
||||
//Display all programs and scripts
|
||||
// Display all programs and scripts
|
||||
let allFiles = [];
|
||||
let folders = [];
|
||||
|
||||
@@ -1733,18 +1741,18 @@ let Terminal = {
|
||||
const currServ = Player.getCurrentServer();
|
||||
post("Hostname IP Root Access");
|
||||
for (let i = 0; i < currServ.serversOnNetwork.length; i++) {
|
||||
//Add hostname
|
||||
// Add hostname
|
||||
let entry = getServerOnNetwork(currServ, i);
|
||||
if (entry == null) { continue; }
|
||||
entry = entry.hostname;
|
||||
|
||||
//Calculate padding and add IP
|
||||
// Calculate padding and add IP
|
||||
let numSpaces = 21 - entry.length;
|
||||
let spaces = Array(numSpaces+1).join(" ");
|
||||
entry += spaces;
|
||||
entry += getServerOnNetwork(currServ, i).ip;
|
||||
|
||||
//Calculate padding and add root access info
|
||||
// Calculate padding and add root access info
|
||||
let hasRoot;
|
||||
if (getServerOnNetwork(currServ, i).hasAdminRights) {
|
||||
hasRoot = 'Y';
|
||||
@@ -1760,7 +1768,7 @@ let Terminal = {
|
||||
},
|
||||
|
||||
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(" ");
|
||||
|
||||
@@ -1791,7 +1799,7 @@ let Terminal = {
|
||||
stack.push(getServerOnNetwork(s, i));
|
||||
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("-");
|
||||
if (Player.hasProgram(Programs.AutoLink.name)) {
|
||||
post("<strong>" + titleDashes + "> <a class='scan-analyze-link'>" + s.hostname + "</a></strong>", false);
|
||||
@@ -1800,7 +1808,6 @@ let Terminal = {
|
||||
}
|
||||
|
||||
var dashes = titleDashes + "--";
|
||||
//var dashes = Array(d * 2 + 1).join("-");
|
||||
var c = "NO";
|
||||
if (s.hasAdminRights) {c = "YES";}
|
||||
post(`${dashes}Root Access: ${c}${!isHacknet ? ", Required hacking skill: " + s.requiredHackingSkill : ""}`);
|
||||
@@ -1817,7 +1824,7 @@ let Terminal = {
|
||||
if (Terminal.analyzeFlag || Terminal.hackFlag) {return;}
|
||||
Terminal.connectToServer(hostname);
|
||||
}
|
||||
}());//Immediate invocation
|
||||
}());// Immediate invocation
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1841,7 +1848,7 @@ let Terminal = {
|
||||
const ip = destServer.ip;
|
||||
const currServ = Player.getCurrentServer();
|
||||
|
||||
//Scp for lit files
|
||||
// Scp for lit files
|
||||
if (scriptname.endsWith(".lit")) {
|
||||
var found = false;
|
||||
for (var i = 0; i < currServ.messages.length; ++i) {
|
||||
@@ -1856,14 +1863,14 @@ let Terminal = {
|
||||
for (var i = 0; i < destServer.messages.length; ++i) {
|
||||
if (destServer.messages[i] === scriptname) {
|
||||
post(scriptname + " copied over to " + destServer.hostname);
|
||||
return; //Already exists
|
||||
return; // Already exists
|
||||
}
|
||||
}
|
||||
destServer.messages.push(scriptname);
|
||||
return post(scriptname + " copied over to " + destServer.hostname);
|
||||
}
|
||||
|
||||
//Scp for txt files
|
||||
// Scp for txt files
|
||||
if (scriptname.endsWith(".txt")) {
|
||||
var found = false, txtFile;
|
||||
for (var i = 0; i < currServ.textFiles.length; ++i) {
|
||||
@@ -1919,8 +1926,8 @@ let Terminal = {
|
||||
}
|
||||
},
|
||||
|
||||
//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
|
||||
// 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
|
||||
runProgram: function(commandArray) {
|
||||
if (commandArray.length < 2) { return; }
|
||||
|
||||
@@ -1935,7 +1942,7 @@ let Terminal = {
|
||||
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) {
|
||||
if (commandArray.length < 2) { return; }
|
||||
|
||||
@@ -2229,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) {
|
||||
post("ERROR: This script is already running. Cannot run multiple instances");
|
||||
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++) {
|
||||
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 ramUsage = script.ramUsage * numThreads;
|
||||
var ramAvailable = server.maxRam - server.ramUsed;
|
||||
@@ -2251,7 +2258,7 @@ let Terminal = {
|
||||
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
|
||||
return;
|
||||
} else {
|
||||
//Able to run script
|
||||
// Able to run script
|
||||
post("Running script with " + numThreads + " thread(s) and args: " + arrayToString(args) + ".");
|
||||
post("May take a few seconds to start up the process...");
|
||||
var runningScriptObj = new RunningScript(script, args);
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||
import {
|
||||
Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver
|
||||
} from "../utils/JSONReviver";
|
||||
|
||||
|
||||
/**
|
||||
* Represents a plain text file that is typically stored on a server.
|
||||
|
||||
500
src/engine.jsx
500
src/engine.jsx
@@ -1,104 +1,129 @@
|
||||
import {formatNumber,
|
||||
convertTimeMsToTimeElapsedString,
|
||||
replaceAt} from "../utils/StringHelperFunctions";
|
||||
import {loxBoxCreate, logBoxUpdateText,
|
||||
logBoxOpened} from "../utils/LogBox";
|
||||
import {updateActiveScriptsItems} from "./ActiveScriptsUI";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import { installAugmentations,
|
||||
initAugmentations,
|
||||
displayAugmentationsContent,
|
||||
PlayerOwnedAugmentation } from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import {
|
||||
formatNumber,
|
||||
convertTimeMsToTimeElapsedString,
|
||||
replaceAt
|
||||
} from "../utils/StringHelperFunctions";
|
||||
import { loxBoxCreate, logBoxUpdateText, logBoxOpened } from "../utils/LogBox";
|
||||
import { updateActiveScriptsItems } from "./ActiveScriptsUI";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import {
|
||||
installAugmentations,
|
||||
initAugmentations,
|
||||
displayAugmentationsContent,
|
||||
PlayerOwnedAugmentation
|
||||
} from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
|
||||
import {BitNodes, initBitNodes,
|
||||
initBitNodeMultipliers} from "./BitNode/BitNode";
|
||||
import {Bladeburner} from "./Bladeburner";
|
||||
import { CharacterOverviewComponent } from "./ui/React/CharacterOverview";
|
||||
import {cinematicTextFlag} from "./CinematicText";
|
||||
import {generateRandomContract} from "./CodingContractGenerator";
|
||||
import {CompanyPositions} from "./Company/CompanyPositions";
|
||||
import {initCompanies} from "./Company/Companies";
|
||||
import { Corporation } from "./Corporation/Corporation";
|
||||
import {CONSTANTS} from "./Constants";
|
||||
import {createDevMenu, closeDevMenu} from "./DevMenu";
|
||||
import { Factions, initFactions } from "./Faction/Factions";
|
||||
import { displayFactionContent, joinFaction,
|
||||
processPassiveFactionRepGain,
|
||||
inviteToFaction } from "./Faction/FactionHelpers";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import { hasHacknetServers,
|
||||
renderHacknetNodesUI,
|
||||
clearHacknetNodesUI,
|
||||
processHacknetEarnings } from "./Hacknet/HacknetHelpers";
|
||||
import {iTutorialStart} from "./InteractiveTutorial";
|
||||
import {initLiterature} from "./Literature";
|
||||
import { LocationName } from "./Locations/data/LocationNames";
|
||||
import { LocationRoot } from "./Locations/ui/Root";
|
||||
import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers";
|
||||
import {inMission, currMission} from "./Missions";
|
||||
import {initSingularitySFFlags,
|
||||
hasSingularitySF, hasCorporationSF} from "./NetscriptFunctions";
|
||||
import {updateOnlineScriptTimes,
|
||||
runScriptsLoop} from "./NetscriptWorker";
|
||||
import {Player} from "./Player";
|
||||
import {prestigeAugmentation,
|
||||
prestigeSourceFile} from "./Prestige";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { displayCreateProgramContent,
|
||||
getNumAvailableCreateProgram,
|
||||
initCreateProgramButtons } from "./Programs/ProgramHelpers";
|
||||
import {redPillFlag, hackWorldDaemon} from "./RedPill";
|
||||
import {saveObject, loadGame} from "./SaveObject";
|
||||
import { getCurrentEditor,
|
||||
loadAllRunningScripts,
|
||||
scriptEditorInit,
|
||||
updateScriptEditorContent } from "./Script/ScriptHelpers";
|
||||
import { AllServers,
|
||||
initForeignServers } from "./Server/AllServers";
|
||||
import {
|
||||
BitNodes,
|
||||
initBitNodes,
|
||||
initBitNodeMultipliers
|
||||
} from "./BitNode/BitNode";
|
||||
import { Bladeburner } from "./Bladeburner";
|
||||
import { CharacterOverviewComponent } from "./ui/React/CharacterOverview";
|
||||
import { cinematicTextFlag } from "./CinematicText";
|
||||
import { generateRandomContract } from "./CodingContractGenerator";
|
||||
import { CompanyPositions } from "./Company/CompanyPositions";
|
||||
import { initCompanies } from "./Company/Companies";
|
||||
import { Corporation } from "./Corporation/Corporation";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { createDevMenu, closeDevMenu } from "./DevMenu";
|
||||
import { Factions, initFactions } from "./Faction/Factions";
|
||||
import {
|
||||
displayFactionContent,
|
||||
joinFaction,
|
||||
processPassiveFactionRepGain,
|
||||
inviteToFaction
|
||||
} from "./Faction/FactionHelpers";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import {
|
||||
hasHacknetServers,
|
||||
renderHacknetNodesUI,
|
||||
clearHacknetNodesUI,
|
||||
processHacknetEarnings
|
||||
} from "./Hacknet/HacknetHelpers";
|
||||
import { iTutorialStart } from "./InteractiveTutorial";
|
||||
import { initLiterature } from "./Literature";
|
||||
import { LocationName } from "./Locations/data/LocationNames";
|
||||
import { LocationRoot } from "./Locations/ui/Root";
|
||||
import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers";
|
||||
import { inMission, currMission } from "./Missions";
|
||||
import {
|
||||
initSingularitySFFlags,
|
||||
hasSingularitySF,
|
||||
hasCorporationSF
|
||||
} from "./NetscriptFunctions";
|
||||
import { updateOnlineScriptTimes, runScriptsLoop } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeAugmentation, prestigeSourceFile } from "./Prestige";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import {
|
||||
displayCreateProgramContent,
|
||||
getNumAvailableCreateProgram,
|
||||
initCreateProgramButtons
|
||||
} from "./Programs/ProgramHelpers";
|
||||
import { redPillFlag, hackWorldDaemon } from "./RedPill";
|
||||
import { saveObject, loadGame } from "./SaveObject";
|
||||
import {
|
||||
getCurrentEditor,
|
||||
loadAllRunningScripts,
|
||||
scriptEditorInit,
|
||||
updateScriptEditorContent
|
||||
} from "./Script/ScriptHelpers";
|
||||
import { AllServers, initForeignServers } from "./Server/AllServers";
|
||||
|
||||
import { Server } from "./Server/Server";
|
||||
import {Settings} from "./Settings/Settings";
|
||||
import { initSourceFiles, SourceFiles } from "./SourceFile";
|
||||
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import {SpecialServerIps, initSpecialServerIps} from "./Server/SpecialServerIps";
|
||||
import {StockMarket, StockSymbols,
|
||||
SymbolToStockMap, initStockSymbols,
|
||||
initSymbolToStockMap, stockMarketCycle,
|
||||
processStockPrices,
|
||||
displayStockMarketContent} from "./StockMarket/StockMarket";
|
||||
import {Terminal, postNetburnerText} from "./Terminal";
|
||||
import { Server } from "./Server/Server";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { initSourceFiles, SourceFiles } from "./SourceFile";
|
||||
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import {
|
||||
SpecialServerIps,
|
||||
initSpecialServerIps
|
||||
} from "./Server/SpecialServerIps";
|
||||
import {
|
||||
StockMarket,
|
||||
StockSymbols,
|
||||
SymbolToStockMap,
|
||||
initStockSymbols,
|
||||
initSymbolToStockMap,
|
||||
stockMarketCycle,
|
||||
processStockPrices,
|
||||
displayStockMarketContent
|
||||
} from "./StockMarket/StockMarket";
|
||||
import { Terminal, postNetburnerText } from "./Terminal";
|
||||
|
||||
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
||||
import { clearSleevesPage,
|
||||
createSleevesPage,
|
||||
updateSleevesPage } from "./PersonObjects/Sleeve/SleeveUI";
|
||||
import { clearResleevesPage,
|
||||
createResleevesPage } from "./PersonObjects/Resleeving/ResleevingUI";
|
||||
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
||||
import {
|
||||
clearSleevesPage,
|
||||
createSleevesPage,
|
||||
updateSleevesPage
|
||||
} from "./PersonObjects/Sleeve/SleeveUI";
|
||||
import {
|
||||
clearResleevesPage,
|
||||
createResleevesPage
|
||||
} from "./PersonObjects/Resleeving/ResleevingUI";
|
||||
|
||||
import { createStatusText } from "./ui/createStatusText";
|
||||
import { displayCharacterInfo } from "./ui/displayCharacterInfo";
|
||||
import {Page, routing} from "./ui/navigationTracking";
|
||||
import {numeralWrapper} from "./ui/numeralFormat";
|
||||
import {setSettingsLabels} from "./ui/setSettingsLabels";
|
||||
import { initializeMainMenuHeaders } from "./ui/MainMenu/Headers";
|
||||
import { initializeMainMenuLinks,
|
||||
MainMenuLinks } from "./ui/MainMenu/Links";
|
||||
import { createStatusText } from "./ui/createStatusText";
|
||||
import { displayCharacterInfo } from "./ui/displayCharacterInfo";
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { setSettingsLabels } from "./ui/setSettingsLabels";
|
||||
import { initializeMainMenuHeaders } from "./ui/MainMenu/Headers";
|
||||
import { initializeMainMenuLinks, MainMenuLinks } from "./ui/MainMenu/Links";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { gameOptionsBoxClose, gameOptionsBoxOpen } from "../utils/GameOptions";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
|
||||
import { dialogBoxCreate} from "../utils/DialogBox";
|
||||
import { gameOptionsBoxClose,
|
||||
gameOptionsBoxOpen } from "../utils/GameOptions";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
|
||||
import {KEY} from "../utils/helpers/keyCodes";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
// These should really be imported with the module that is presenting that UI, but because they very much depend on the
|
||||
// cascade order, we'll pull them all in here.
|
||||
@@ -130,7 +155,8 @@ import "../css/grid.min.css";
|
||||
import "../css/dev-menu.css";
|
||||
|
||||
|
||||
/* Shortcuts to navigate through the game
|
||||
/**
|
||||
* Shortcuts to navigate through the game
|
||||
* Alt-t - Terminal
|
||||
* Alt-c - Character
|
||||
* Alt-e - Script editor
|
||||
@@ -184,7 +210,7 @@ $(document).keydown(function(e) {
|
||||
e.preventDefault();
|
||||
Engine.loadCreateProgramContent();
|
||||
} else if (e.keyCode === KEY.F && e.altKey) {
|
||||
//Overriden by Fconf
|
||||
// Overriden by Fconf
|
||||
if (routing.isOn(Page.Terminal) && FconfSettings.ENABLE_BASH_HOTKEYS) {
|
||||
return;
|
||||
}
|
||||
@@ -209,24 +235,25 @@ const Engine = {
|
||||
version: "",
|
||||
Debug: true,
|
||||
|
||||
//Clickable objects
|
||||
// Clickable objects
|
||||
Clickables: {
|
||||
//Main menu buttons
|
||||
// Main menu buttons
|
||||
saveMainMenuButton: null,
|
||||
deleteMainMenuButton: null,
|
||||
},
|
||||
|
||||
//Display objects
|
||||
// Display objects
|
||||
// TODO-Refactor this into its own component
|
||||
Display: {
|
||||
//Progress bar
|
||||
// Progress bar
|
||||
progress: null,
|
||||
|
||||
//Display for status text (such as "Saved" or "Loaded")
|
||||
// Display for status text (such as "Saved" or "Loaded")
|
||||
statusText: null,
|
||||
|
||||
hacking_skill: null,
|
||||
|
||||
//Main menu content
|
||||
// Main menu content
|
||||
terminalContent: null,
|
||||
characterContent: null,
|
||||
scriptEditorContent: null,
|
||||
@@ -235,7 +262,6 @@ const Engine = {
|
||||
createProgramContent: null,
|
||||
factionsContent: null,
|
||||
factionContent: null,
|
||||
factionAugmentationsContent: null,
|
||||
augmentationsContent: null,
|
||||
tutorialContent: null,
|
||||
infiltrationContent: null,
|
||||
@@ -246,15 +272,14 @@ const Engine = {
|
||||
cinematicTextContent: null,
|
||||
missionContent: null,
|
||||
|
||||
//Character info
|
||||
// Character info
|
||||
characterInfo: null,
|
||||
},
|
||||
|
||||
//Time variables (milliseconds unix epoch time)
|
||||
// Time variables (milliseconds unix epoch time)
|
||||
_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() {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.terminalContent.style.display = "block";
|
||||
@@ -400,7 +425,6 @@ const Engine = {
|
||||
loadWorkInProgressContent: function() {
|
||||
Engine.hideAllContent();
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
//mainMenu.style.visibility = "hidden";
|
||||
mainMenu.style.visibility = "hidden";
|
||||
Engine.Display.workInProgressContent.style.display = "block";
|
||||
routing.navigateTo(Page.WorkInProgress);
|
||||
@@ -505,8 +529,8 @@ const Engine = {
|
||||
clearHacknetNodesUI();
|
||||
Engine.Display.createProgramContent.style.display = "none";
|
||||
Engine.Display.factionsContent.style.display = "none";
|
||||
ReactDOM.unmountComponentAtNode(Engine.Display.factionContent);
|
||||
Engine.Display.factionContent.style.display = "none";
|
||||
Engine.Display.factionAugmentationsContent.style.display = "none";
|
||||
Engine.Display.augmentationsContent.style.display = "none";
|
||||
Engine.Display.tutorialContent.style.display = "none";
|
||||
Engine.Display.locationContent.style.display = "none";
|
||||
@@ -577,15 +601,16 @@ const Engine = {
|
||||
}
|
||||
},
|
||||
|
||||
/* Display character info */
|
||||
/// Display character info
|
||||
updateCharacterInfo: function() {
|
||||
displayCharacterInfo(Engine.Display.characterInfo, Player);
|
||||
},
|
||||
|
||||
// TODO Refactor this into Faction implementation
|
||||
displayFactionsInfo: function() {
|
||||
removeChildrenFromElement(Engine.Display.factionsContent);
|
||||
|
||||
//Factions
|
||||
// Factions
|
||||
Engine.Display.factionsContent.appendChild(createElement("h1", {
|
||||
innerText:"Factions"
|
||||
}));
|
||||
@@ -595,7 +620,7 @@ const Engine = {
|
||||
var factionsList = createElement("ul");
|
||||
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) {
|
||||
(function () {
|
||||
var factionName = Player.factions[i];
|
||||
@@ -610,12 +635,12 @@ const Engine = {
|
||||
}
|
||||
}));
|
||||
factionsList.appendChild(createElement("br"));
|
||||
}()); //Immediate invocation
|
||||
}()); // Immediate invocation
|
||||
}
|
||||
Engine.Display.factionsContent.appendChild(factionsList);
|
||||
Engine.Display.factionsContent.appendChild(createElement("br"));
|
||||
|
||||
//Invited Factions
|
||||
// Invited Factions
|
||||
Engine.Display.factionsContent.appendChild(createElement("h1", {
|
||||
innerText:"Outstanding Faction Invitations"
|
||||
}));
|
||||
@@ -627,7 +652,7 @@ const Engine = {
|
||||
}));
|
||||
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) {
|
||||
(function () {
|
||||
var factionName = Player.factionInvitations[i];
|
||||
@@ -660,18 +685,18 @@ const Engine = {
|
||||
Engine.Display.factionsContent.appendChild(invitationsList);
|
||||
},
|
||||
|
||||
/* Main Event Loop */
|
||||
// Main Game Loop
|
||||
idleTimer: function() {
|
||||
//Get time difference
|
||||
// Get time difference
|
||||
var _thisUpdate = new Date().getTime();
|
||||
var diff = _thisUpdate - Engine._lastUpdate;
|
||||
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);
|
||||
|
||||
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;
|
||||
Player.lastUpdate = _thisUpdate - offset;
|
||||
Engine.updateGame(diff);
|
||||
@@ -689,7 +714,7 @@ const Engine = {
|
||||
Player.playtimeSinceLastAug += time;
|
||||
Player.playtimeSinceLastBitnode += time;
|
||||
|
||||
//Start Manual hack
|
||||
// Start Manual hack
|
||||
if (Terminal.actionStarted === true) {
|
||||
Engine._totalActionTime = Terminal.actionTime;
|
||||
Engine._actionTimeLeft = Terminal.actionTime;
|
||||
@@ -700,7 +725,7 @@ const Engine = {
|
||||
Terminal.actionStarted = false;
|
||||
}
|
||||
|
||||
//Working
|
||||
// Working
|
||||
if (Player.isWorking) {
|
||||
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
||||
Player.workForFaction(numCycles);
|
||||
@@ -722,20 +747,19 @@ const Engine = {
|
||||
processStockPrices(numCycles);
|
||||
}
|
||||
|
||||
//Gang, if applicable
|
||||
if (Player.bitNodeN == 2 && Player.inGang()) {
|
||||
// Gang, if applicable
|
||||
if (Player.inGang()) {
|
||||
Player.gang.process(numCycles, Player);
|
||||
}
|
||||
|
||||
//Mission
|
||||
// Mission
|
||||
if (inMission && currMission) {
|
||||
currMission.process(numCycles);
|
||||
}
|
||||
|
||||
//Corporation
|
||||
// Corporation
|
||||
if (Player.corporation instanceof Corporation) {
|
||||
//Stores cycles in a "buffer". Processed separately using Engine Counters
|
||||
//This is to avoid constant DOM redraws when Corporation is catching up
|
||||
// Stores cycles in a "buffer". Processed separately using Engine Counters
|
||||
Player.corporation.storeCycles(numCycles);
|
||||
}
|
||||
|
||||
@@ -757,38 +781,41 @@ const Engine = {
|
||||
}
|
||||
}
|
||||
|
||||
//Counters
|
||||
// Counters
|
||||
Engine.decrementAllCounters(numCycles);
|
||||
Engine.checkCounters();
|
||||
|
||||
//Manual hacks
|
||||
// Manual hacks
|
||||
if (Engine._actionInProgress == true) {
|
||||
Engine.updateHackProgress(numCycles);
|
||||
}
|
||||
|
||||
//Update the running time of all active scripts
|
||||
// Update the running time of all active scripts
|
||||
updateOnlineScriptTimes(numCycles);
|
||||
|
||||
//Hacknet Nodes
|
||||
// Hacknet Nodes
|
||||
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: {
|
||||
autoSaveCounter: 300, //Autosave every minute
|
||||
updateSkillLevelsCounter: 10, //Only update skill levels every 2 seconds. Might improve performance
|
||||
autoSaveCounter: 300,
|
||||
updateSkillLevelsCounter: 10,
|
||||
updateDisplays: 3,
|
||||
updateDisplaysMed: 9,
|
||||
updateDisplaysLong: 15,
|
||||
updateActiveScriptsDisplay: 5,
|
||||
createProgramNotifications: 10, //Checks whether any programs can be created and notifies
|
||||
checkFactionInvitations: 100, //Check whether you qualify for any faction invitations
|
||||
createProgramNotifications: 10,
|
||||
checkFactionInvitations: 100,
|
||||
passiveFactionGrowth: 600,
|
||||
messages: 150,
|
||||
sCr: 1500,
|
||||
mechanicProcess: 5, //Processes certain mechanics (Corporation, Bladeburner)
|
||||
contractGeneration: 3000 //Generate Coding Contracts
|
||||
mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
|
||||
contractGeneration: 3000, // Generate Coding Contracts
|
||||
},
|
||||
|
||||
decrementAllCounters: function(numCycles = 1) {
|
||||
@@ -799,8 +826,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() {
|
||||
if (Engine.Counters.autoSaveCounter <= 0) {
|
||||
if (Settings.AutosaveInterval == null) {
|
||||
@@ -820,7 +849,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
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();
|
||||
if (routing.isOn(Page.ActiveScripts)) {
|
||||
Engine.Counters.updateActiveScriptsDisplay = 5;
|
||||
@@ -900,7 +929,7 @@ const Engine = {
|
||||
if (Engine.Counters.messages <= 0) {
|
||||
checkForMessagesToSend();
|
||||
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 {
|
||||
Engine.Counters.messages = 150;
|
||||
}
|
||||
@@ -937,7 +966,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,
|
||||
_actionTimeLeft: 0,
|
||||
_actionTimeStr: "Time left: ",
|
||||
@@ -946,34 +976,36 @@ const Engine = {
|
||||
_actionInProgress: false,
|
||||
updateHackProgress: function(numCycles = 1) {
|
||||
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);
|
||||
|
||||
//Calculate percent filled
|
||||
// Calculate percent filled
|
||||
var percent = Math.round((1 - Engine._actionTimeLeft / Engine._totalActionTime) * 100);
|
||||
|
||||
//Update progress bar
|
||||
// Update progress bar
|
||||
while (Engine._actionProgressBarCount * 2 <= percent) {
|
||||
Engine._actionProgressStr = replaceAt(Engine._actionProgressStr, Engine._actionProgressBarCount, "|");
|
||||
Engine._actionProgressBarCount += 1;
|
||||
}
|
||||
|
||||
//Update hack time remaining
|
||||
// Update hack time remaining
|
||||
Engine._actionTimeStr = "Time left: " + Math.max(0, Math.round(Engine._actionTimeLeft)).toString() + "s";
|
||||
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, " " );
|
||||
|
||||
//Once percent is 100, the hack is completed
|
||||
// Once percent is 100, the hack is completed
|
||||
if (percent >= 100) {
|
||||
Engine._actionInProgress = false;
|
||||
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) {
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
elems[i].style.maxHeight = null;
|
||||
@@ -982,8 +1014,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) {
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
|
||||
@@ -991,10 +1025,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
|
||||
//elems is an array of DOM elements for main menu tabs (li)
|
||||
//links is an array of DOM elements for main menu links (a)
|
||||
/**
|
||||
* Used in game when clicking on a main menu header (NOT used for initialization)
|
||||
* @param open {boolean} Whether header is being opened or closed
|
||||
* @param elems {HTMLElement[]} li Elements under header
|
||||
* @param links {HTMLElement[]} a elements under header
|
||||
*/
|
||||
toggleMainMenuHeader: function(open, elems, links) {
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
if (open) {
|
||||
@@ -1020,35 +1056,34 @@ const Engine = {
|
||||
},
|
||||
|
||||
load: function(saveString) {
|
||||
//Initialize main menu accordion panels to all start as "open"
|
||||
var terminal = document.getElementById("terminal-tab");
|
||||
var createScript = document.getElementById("create-script-tab");
|
||||
var activeScripts = document.getElementById("active-scripts-tab");
|
||||
var createProgram = document.getElementById("create-program-tab");
|
||||
var stats = document.getElementById("stats-tab");
|
||||
var factions = document.getElementById("factions-tab");
|
||||
var augmentations = document.getElementById("augmentations-tab");
|
||||
var hacknetnodes = document.getElementById("hacknet-nodes-tab");
|
||||
var city = document.getElementById("city-tab");
|
||||
var travel = document.getElementById("travel-tab");
|
||||
var job = document.getElementById("job-tab");
|
||||
var stockmarket = document.getElementById("stock-market-tab");
|
||||
var bladeburner = document.getElementById("bladeburner-tab");
|
||||
var corp = document.getElementById("corporation-tab");
|
||||
var gang = document.getElementById("gang-tab");
|
||||
var tutorial = document.getElementById("tutorial-tab");
|
||||
var options = document.getElementById("options-tab");
|
||||
var dev = document.getElementById("dev-tab");
|
||||
// Initialize main menu accordion panels to all start as "open"
|
||||
const terminal = document.getElementById("terminal-tab");
|
||||
const createScript = document.getElementById("create-script-tab");
|
||||
const activeScripts = document.getElementById("active-scripts-tab");
|
||||
const createProgram = document.getElementById("create-program-tab");
|
||||
const stats = document.getElementById("stats-tab");
|
||||
const factions = document.getElementById("factions-tab");
|
||||
const augmentations = document.getElementById("augmentations-tab");
|
||||
const hacknetnodes = document.getElementById("hacknet-nodes-tab");
|
||||
const city = document.getElementById("city-tab");
|
||||
const travel = document.getElementById("travel-tab");
|
||||
const job = document.getElementById("job-tab");
|
||||
const stockmarket = document.getElementById("stock-market-tab");
|
||||
const bladeburner = document.getElementById("bladeburner-tab");
|
||||
const corp = document.getElementById("corporation-tab");
|
||||
const gang = document.getElementById("gang-tab");
|
||||
const tutorial = document.getElementById("tutorial-tab");
|
||||
const options = document.getElementById("options-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)) {
|
||||
console.log("Loaded game from save");
|
||||
initBitNodes();
|
||||
initBitNodeMultipliers(Player);
|
||||
initSourceFiles();
|
||||
Engine.setDisplayElements(); //Sets variables for important DOM elements
|
||||
Engine.init(); //Initialize buttons, work, etc.
|
||||
initAugmentations(); //Also calls Player.reapplyAllAugmentations()
|
||||
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
||||
Engine.init(); // Initialize buttons, work, etc.
|
||||
initAugmentations(); // Also calls Player.reapplyAllAugmentations()
|
||||
Player.reapplyAllSourceFiles();
|
||||
initStockSymbols();
|
||||
if (Player.hasWseAccount) {
|
||||
@@ -1058,13 +1093,13 @@ const Engine = {
|
||||
initSingularitySFFlags();
|
||||
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();
|
||||
var lastUpdate = Player.lastUpdate;
|
||||
var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed);
|
||||
|
||||
/* Process offline progress */
|
||||
var offlineProductionFromScripts = loadAllRunningScripts(); //This also takes care of offline production for those scripts
|
||||
// Process offline progress
|
||||
var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
|
||||
if (Player.isWorking) {
|
||||
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
|
||||
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
||||
@@ -1082,13 +1117,13 @@ const Engine = {
|
||||
}
|
||||
}
|
||||
|
||||
//Hacknet Nodes offline progress
|
||||
// Hacknet Nodes offline progress
|
||||
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
||||
const hacknetProdInfo = hasHacknetServers() ?
|
||||
`${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` :
|
||||
`${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`;
|
||||
|
||||
//Passive faction rep gain offline
|
||||
// Passive faction rep gain offline
|
||||
processPassiveFactionRepGain(numCyclesOffline);
|
||||
|
||||
// Stock Market offline progress
|
||||
@@ -1097,7 +1132,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Gang progress for BitNode 2
|
||||
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
|
||||
if (Player.inGang()) {
|
||||
Player.gang.process(numCyclesOffline, Player);
|
||||
}
|
||||
|
||||
@@ -1125,7 +1160,7 @@ const Engine = {
|
||||
}
|
||||
}
|
||||
|
||||
//Update total playtime
|
||||
// Update total playtime
|
||||
var time = numCyclesOffline * Engine._idleSpeed;
|
||||
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
|
||||
if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;}
|
||||
@@ -1135,14 +1170,14 @@ const Engine = {
|
||||
Player.playtimeSinceLastBitnode += time;
|
||||
|
||||
Player.lastUpdate = Engine._lastUpdate;
|
||||
Engine.start(); //Run main game loop and Scripts loop
|
||||
Engine.start(); // Run main game loop and Scripts loop
|
||||
removeLoadingScreen();
|
||||
const timeOfflineString = convertTimeMsToTimeElapsedString(time);
|
||||
dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` +
|
||||
"generated <span class='money-gold'>" +
|
||||
numeralWrapper.formatMoney(offlineProductionFromScripts) + "</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,
|
||||
hacknetnodes, city, tutorial, options, dev];
|
||||
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
|
||||
@@ -1166,14 +1201,14 @@ const Engine = {
|
||||
|
||||
Engine.closeMainMenuHeader(visibleMenuTabs);
|
||||
} else {
|
||||
//No save found, start new game
|
||||
// No save found, start new game
|
||||
console.log("Initializing new game");
|
||||
initBitNodes();
|
||||
initBitNodeMultipliers(Player);
|
||||
initSourceFiles();
|
||||
initSpecialServerIps();
|
||||
Engine.setDisplayElements(); //Sets variables for important DOM elements
|
||||
Engine.start(); //Run main game loop and Scripts loop
|
||||
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
||||
Engine.start(); // Run main game loop and Scripts loop
|
||||
Player.init();
|
||||
initForeignServers(Player.getHomeComputer());
|
||||
initCompanies();
|
||||
@@ -1184,18 +1219,17 @@ const Engine = {
|
||||
initLiterature();
|
||||
initSingularitySFFlags();
|
||||
|
||||
//Open main menu accordions for new game
|
||||
//Main menu accordions
|
||||
var hackingHdr = document.getElementById("hacking-menu-header");
|
||||
// Open main menu accordions for new game
|
||||
const hackingHdr = document.getElementById("hacking-menu-header");
|
||||
hackingHdr.classList.toggle("opened");
|
||||
var characterHdr = document.getElementById("character-menu-header");
|
||||
const characterHdr = document.getElementById("character-menu-header");
|
||||
characterHdr.classList.toggle("opened");
|
||||
var worldHdr = document.getElementById("world-menu-header");
|
||||
const worldHdr = document.getElementById("world-menu-header");
|
||||
worldHdr.classList.toggle("opened");
|
||||
var helpHdr = document.getElementById("help-menu-header");
|
||||
const helpHdr = document.getElementById("help-menu-header");
|
||||
helpHdr.classList.toggle("opened");
|
||||
|
||||
//Hide tabs that wont be revealed until later
|
||||
// Hide tabs that wont be revealed until later
|
||||
factions.style.display = "none";
|
||||
augmentations.style.display = "none";
|
||||
job.style.display = "none";
|
||||
@@ -1213,18 +1247,18 @@ const Engine = {
|
||||
tutorial, options]
|
||||
);
|
||||
|
||||
//Start interactive tutorial
|
||||
// Start interactive tutorial
|
||||
iTutorialStart();
|
||||
removeLoadingScreen();
|
||||
}
|
||||
//Initialize labels on game settings
|
||||
// Initialize labels on game settings
|
||||
setSettingsLabels();
|
||||
scriptEditorInit();
|
||||
Terminal.resetTerminalInput();
|
||||
},
|
||||
|
||||
setDisplayElements: function() {
|
||||
//Content elements
|
||||
// Content elements
|
||||
Engine.Display.terminalContent = document.getElementById("terminal-container");
|
||||
routing.navigateTo(Page.Terminal);
|
||||
|
||||
@@ -1246,13 +1280,9 @@ const Engine = {
|
||||
Engine.Display.factionsContent = document.getElementById("factions-container");
|
||||
Engine.Display.factionsContent.style.display = "none";
|
||||
|
||||
|
||||
Engine.Display.factionContent = document.getElementById("faction-container");
|
||||
Engine.Display.factionContent.style.display = "none";
|
||||
|
||||
Engine.Display.factionAugmentationsContent = document.getElementById("faction-augmentations-container");
|
||||
Engine.Display.factionAugmentationsContent.style.display = "none";
|
||||
|
||||
Engine.Display.augmentationsContent = document.getElementById("augmentations-container");
|
||||
Engine.Display.augmentationsContent.style.display = "none";
|
||||
|
||||
@@ -1269,22 +1299,22 @@ const Engine = {
|
||||
Engine.Display.missionContent = document.getElementById("mission-container");
|
||||
Engine.Display.missionContent.style.display = "none";
|
||||
|
||||
//Character info
|
||||
// Character info
|
||||
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.style.display = "none";
|
||||
|
||||
//Work In Progress
|
||||
// Work In Progress
|
||||
Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container");
|
||||
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.style.display = "none";
|
||||
|
||||
//Cinematic Text
|
||||
// Cinematic Text
|
||||
Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container");
|
||||
Engine.Display.cinematicTextContent.style.display = "none";
|
||||
|
||||
@@ -1298,9 +1328,9 @@ const Engine = {
|
||||
}
|
||||
},
|
||||
|
||||
/* Initialization */
|
||||
// Initialization
|
||||
init: function() {
|
||||
//Import game link
|
||||
// Import game link
|
||||
document.getElementById("import-game-link").onclick = function() {
|
||||
saveObject.importGame();
|
||||
};
|
||||
@@ -1409,10 +1439,10 @@ const Engine = {
|
||||
return false;
|
||||
});
|
||||
|
||||
//Active scripts list
|
||||
// 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.addEventListener("click", function() {
|
||||
saveObject.saveGame(indexedDb);
|
||||
@@ -1430,7 +1460,7 @@ const Engine = {
|
||||
return false;
|
||||
});
|
||||
|
||||
//Character Overview buttons
|
||||
// Character Overview buttons
|
||||
document.getElementById("character-overview-save-button").addEventListener("click", function() {
|
||||
saveObject.saveGame(indexedDb);
|
||||
return false;
|
||||
@@ -1441,13 +1471,13 @@ const Engine = {
|
||||
return false;
|
||||
});
|
||||
|
||||
//Create Program buttons
|
||||
// Create Program buttons
|
||||
initCreateProgramButtons();
|
||||
|
||||
//Message at the top of terminal
|
||||
// Message at the top of terminal
|
||||
postNetburnerText();
|
||||
|
||||
//Player was working cancel button
|
||||
// Player was working cancel button
|
||||
if (Player.isWorking) {
|
||||
var cancelButton = document.getElementById("work-in-progress-cancel-button");
|
||||
cancelButton.addEventListener("click", function() {
|
||||
@@ -1469,10 +1499,10 @@ const Engine = {
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
//character overview screen
|
||||
// Character overview screen
|
||||
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("stats-menu-link").removeAttribute("class");
|
||||
document.getElementById("create-script-menu-link").removeAttribute("class");
|
||||
@@ -1518,7 +1548,7 @@ const Engine = {
|
||||
}
|
||||
});
|
||||
|
||||
//DEBUG Delete active Scripts on home
|
||||
// DEBUG Delete active Scripts on home
|
||||
document.getElementById("debug-delete-scripts-link").addEventListener("click", function() {
|
||||
console.log("Deleting running scripts on home computer");
|
||||
Player.getHomeComputer().runningScripts = [];
|
||||
@@ -1527,7 +1557,7 @@ const Engine = {
|
||||
return false;
|
||||
});
|
||||
|
||||
//DEBUG Soft Reset
|
||||
// DEBUG Soft Reset
|
||||
document.getElementById("debug-soft-reset").addEventListener("click", function() {
|
||||
dialogBoxCreate("Soft Reset!");
|
||||
prestigeAugmentation();
|
||||
@@ -1537,10 +1567,10 @@ const Engine = {
|
||||
},
|
||||
|
||||
start: function() {
|
||||
//Run main loop
|
||||
// Run main loop
|
||||
Engine.idleTimer();
|
||||
|
||||
//Scripts
|
||||
// Script-processing loop
|
||||
runScriptsLoop();
|
||||
}
|
||||
};
|
||||
@@ -1548,18 +1578,20 @@ const Engine = {
|
||||
var indexedDb, indexedDbRequest;
|
||||
window.onload = function() {
|
||||
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
|
||||
//key for the Object store is called save
|
||||
/**
|
||||
* DB is called bitburnerSave
|
||||
* Object store is called savestring
|
||||
* key for the Object store is called save
|
||||
*/
|
||||
indexedDbRequest = window.indexedDB.open("bitburnerSave", 1);
|
||||
|
||||
indexedDbRequest.onerror = function(e) {
|
||||
console.log("Error opening indexedDB: ");
|
||||
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) {
|
||||
@@ -1570,11 +1602,11 @@ window.onload = function() {
|
||||
var request = objectStore.get("save");
|
||||
request.onerror = function(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) {
|
||||
Engine.load(request.result); //Is this right?
|
||||
Engine.load(request.result);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
|
||||
<div id="script-editor-filename-wrapper">
|
||||
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
|
||||
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
|
||||
<input id="script-editor-filename" type="text" maxlength="100" tabindex="1" />
|
||||
</div>
|
||||
|
||||
<div id="ace-editor"></div>
|
||||
@@ -223,8 +223,6 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
<!-- Single Faction info (when you select a faction from the Factions menu) -->
|
||||
<div id="faction-container" class="generic-menupage-container"></div>
|
||||
|
||||
<div id="faction-augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
<!-- Augmentations -->
|
||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||
|
||||
|
||||
74
src/ui/React/AutoupdatingParagraph.tsx
Normal file
74
src/ui/React/AutoupdatingParagraph.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Basic paragraph (p Element) that automatically re-renders itself every X seconds
|
||||
*
|
||||
* NOT recommended for usage - only if you really have to
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
interface IProps {
|
||||
intervalTime?: number;
|
||||
style?: object;
|
||||
text: string;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
i: number;
|
||||
}
|
||||
|
||||
type IInnerHTMLMarkup = {
|
||||
__html: string;
|
||||
}
|
||||
|
||||
export class AutoupdatingParagraph extends React.Component<IProps, IState> {
|
||||
/**
|
||||
* Timer ID for auto-updating implementation (returned value from setInterval())
|
||||
*/
|
||||
interval: number = 0;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
i: 0,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const time = this.props.intervalTime ? this.props.intervalTime : 1000;
|
||||
this.interval = setInterval(() => this.tick(), time);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.setState(prevState => ({
|
||||
i: prevState.i + 1
|
||||
}));
|
||||
}
|
||||
|
||||
render() {
|
||||
const hasTooltip = this.props.tooltip != null && this.props.tooltip !== "";
|
||||
|
||||
const className = "tooltip";
|
||||
|
||||
// Tooltip will be set using inner HTML
|
||||
let tooltipMarkup: IInnerHTMLMarkup | null;
|
||||
if (hasTooltip) {
|
||||
tooltipMarkup = {
|
||||
__html: this.props.tooltip!
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<p className={className} style={this.props.style}>
|
||||
{this.props.text}
|
||||
{
|
||||
hasTooltip &&
|
||||
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
|
||||
}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ export interface IParagraphWithTooltipProps {
|
||||
export class ParagraphWithTooltip extends React.Component<IParagraphWithTooltipProps, any> {
|
||||
render() {
|
||||
return (
|
||||
<p className={"tooltip"}>
|
||||
<p className={"tooltip"} style={this.props.style}>
|
||||
{this.props.text}
|
||||
<span className={"tooltiptext"}>
|
||||
{this.props.tooltip}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/* Pop up Dialog Box */
|
||||
/**
|
||||
* Create and display a pop-up dialog box.
|
||||
* This dialog box does not allow for any interaction and should close when clicking
|
||||
* outside of it
|
||||
*/
|
||||
let dialogBoxes = [];
|
||||
|
||||
//Close dialog box when clicking outside
|
||||
// Close dialog box when clicking outside
|
||||
$(document).click(function(event) {
|
||||
if (dialogBoxOpened && dialogBoxes.length >= 1) {
|
||||
if (!$(event.target).closest(dialogBoxes[0]).length){
|
||||
@@ -17,7 +21,7 @@ $(document).click(function(event) {
|
||||
});
|
||||
|
||||
|
||||
//Dialog box close buttons
|
||||
// Dialog box close buttons
|
||||
$(document).on('click', '.dialog-box-close-button', function( event ) {
|
||||
if (dialogBoxOpened && dialogBoxes.length >= 1) {
|
||||
dialogBoxes[0].remove();
|
||||
@@ -30,9 +34,10 @@ $(document).on('click', '.dialog-box-close-button', function( event ) {
|
||||
}
|
||||
});
|
||||
|
||||
var dialogBoxOpened = false;
|
||||
let dialogBoxOpened = false;
|
||||
|
||||
function dialogBoxCreate(txt, preformatted=false) {
|
||||
console.log(`dialogBoxCreate() called`)
|
||||
var container = document.createElement("div");
|
||||
container.setAttribute("class", "dialog-box-container");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user