Convert Locations and Faction implementations to TypeScript. Also restructed directory. Implemented Sleeve, but untested

This commit is contained in:
danielyxie 2018-12-07 02:54:26 -08:00
parent 8fcb1706cc
commit 48c694c9c1
29 changed files with 171104 additions and 487 deletions

58892
dist/engine.bundle.js vendored

File diff suppressed because one or more lines are too long

111064
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bitburner</title>
<title>Bitburner - development</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
@ -112,7 +112,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="30" tabindex="1" />
</div>
<div id="javascript-editor"></div>
@ -162,7 +162,7 @@
<fieldset>
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"/>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr" />
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset>
</div> <!-- End script editor options panel -->
@ -173,7 +173,7 @@
<table id="terminal">
<tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" />
</td>
</tr>
</table>
@ -190,7 +190,7 @@
provides information about each script's production. The scripts are categorized by the hostname of the servers on which
they are running. </p>
<p id="active-scripts-total-prod">Total online production of
Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br/>
Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br />
Total online production since last Aug installation: <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span>
(<span class="money-gold"><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span>)</p>
<ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;">
@ -204,19 +204,19 @@
The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced.
<br/><br/>
<br /><br />
Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its
resources to the Hacknet network. This allows you to take a small percentage of profits
from hacks performed on the network. Essentially, you are renting out your Node's computing power.
<br/><br/>
<br /><br />
Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded
in order to increase its computing power and thereby increase the profit you earn from it.
</p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br/>
<br />
<div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br/>
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br />
<span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span>
</p>
<span id="hacknet-nodes-multipliers">
@ -474,7 +474,8 @@
<!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container">
<a id="tutorial-getting-started-link" class="a-link-button" href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
<a id="tutorial-getting-started-link" class="a-link-button"
href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
<a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a>
<a id="tutorial-hacking-link" class="a-link-button"> Hacking </a>
<a id="tutorial-scripts-link" class="a-link-button"> Scripts </a>
@ -483,7 +484,8 @@
<a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a>
<a id="tutorial-factions-link" class="a-link-button"> Factions </a>
<a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a>
<a id="tutorial-shortcuts-link" class="a-link-button" href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
<a id="tutorial-shortcuts-link" class="a-link-button"
href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
<a id="tutorial-back-button" class="a-link-button"> Back </a>
<p id="tutorial-text"> </p>
@ -574,7 +576,7 @@
<p id="location-slums-description">
You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and
other shadowy entities. The city's government and police have neglected this area for years...
<br/><br/><br/>
<br /><br /><br />
In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always
successful. Your chance at successfully committing a crime is determined by your stats.
</p>
@ -621,7 +623,7 @@
<div id="stock-market-container" class="generic-menupage-container">
<p>
Welcome to the World Stock Exchange (WSE)! <br/><br/>
Welcome to the World Stock Exchange (WSE)! <br /><br />
To begin trading, you must first purchase an account. WSE accounts will persist
after you 'reset' by installing Augmentations.
@ -634,7 +636,7 @@
TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE.
Purchasing access to the TIX API lets you write code to create your own algorithmic/automated
trading strategies.
<br/><br/>
<br /><br />
If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations.
</p>
@ -644,7 +646,7 @@
<p>
Four Sigma's (4S) Market Data Feed provides information about stocks
that will help your trading strategies.
<br/><br/>
<br /><br />
If you purchase access to 4S Market Data and/or the 4S TIX API, you will
retain that access even after you 'reset' by installing Augmentations.
</p>
@ -662,7 +664,7 @@
<a id="stock-market-mode" class="a-link-button tooltip"></a>
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
<br/><br/>
<br /><br />
<input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/>
<a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a>
<ul id="stock-market-list" style="list-style:none;">
@ -692,7 +694,7 @@
<div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"> </p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30"/>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<button id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </button>
<button id="yes-no-text-input-box-no" class="popup-box-button"> No </button>
</div>
@ -704,7 +706,7 @@
<p id="faction-invitation-box-text"> </p>
<p id="faction-invitation-box-message"> </p>
<p id="faction-invitation-box-warning">
Would you like to join? <br/> <br/>
Would you like to join? <br /> <br />
Warning: Joining this faction may prevent you from joining other factions during this run!
</p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
@ -717,8 +719,8 @@
<div id="infiltration-box-content" class="popup-box-content">
<p id="infiltration-box-text"> </p>
<button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br/><br/>
<select id="infiltration-faction-select"> </select> <br/>
<button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br /><br />
<select id="infiltration-faction-select"> </select> <br />
<button id="infiltration-box-faction" class="a-link-button"> Give to Faction for Reputation </button>
</div>
@ -804,7 +806,7 @@
<div id="game-options-content" class="game-options-box">
<button id="game-options-close-button">&times;</button>
<h1> Game Options </h1>
<br/>
<br />
<div id="game-options-left-panel">
<!-- Netscript execution time -->
<fieldset>
@ -816,7 +818,7 @@
</span>
</label>
<input type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/>
<input type ="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25" />
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -830,7 +832,7 @@
</span>
</label>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -844,7 +846,7 @@
</span>
</label>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -856,7 +858,7 @@
</span>
</label>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset>
@ -968,7 +970,7 @@
<a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a>
<a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a>
<a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a>
<input type="file" id="import-game-file-selector" name="file"/>
<input type="file" id="import-game-file-selector" name="file" />
<a id="import-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Import Game </a>
<a id="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;">
(DEBUG) Delete Active Scripts

@ -1,26 +1,27 @@
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
import {Factions, factionExists} from "./Faction";
import {hasBladeburnerSF} from "./NetscriptFunctions";
import {addWorkerScript} from "./NetscriptWorker";
import {Player} from "./Player";
import {prestigeAugmentation} from "./Prestige";
import {saveObject} from "./SaveObject";
import {Script, RunningScript} from "./Script";
import {Server} from "./Server";
import {OwnedAugmentationsOrderSetting} from "./SettingEnums";
import {Settings} from "./Settings";
import { BitNodeMultipliers } from "./BitNodeMultipliers";
import { CONSTANTS } from "./Constants";
import { Engine } from "./engine";
import { Factions,
factionExists } from "./Faction/Factions";
import { hasBladeburnerSF } from "./NetscriptFunctions";
import { addWorkerScript } from "./NetscriptWorker";
import { Player } from "./Player";
import { prestigeAugmentation } from "./Prestige";
import { saveObject } from "./SaveObject";
import { Script , RunningScript} from "./Script";
import { Server } from "./Server";
import { OwnedAugmentationsOrderSetting } from "./SettingEnums";
import { Settings } from "./Settings";
import {SourceFiles} from "./SourceFile";
import {dialogBoxCreate} from "../utils/DialogBox";
import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver";
import {clearObject} from "../utils/helpers/clearObject";
import {createElement} from "../utils/uiHelpers/createElement";
import {isString} from "../utils/helpers/isString";
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
import { SourceFiles } from "./SourceFile";
import { dialogBoxCreate } from "../utils/DialogBox";
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
import { Reviver, Generic_toJSON,
Generic_fromJSON } from "../utils/JSONReviver";
import { clearObject } from "../utils/helpers/clearObject";
import { createElement } from "../utils/uiHelpers/createElement";
import { isString } from "../utils/helpers/isString";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
//Augmentations
function Augmentation(params) {
@ -1569,13 +1570,13 @@ function initAugmentations() {
//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();
Factions["Tetrads"].addAllAugmentations();
Factions["The Syndicate"].addAllAugmentations();
Factions["The Dark Army"].addAllAugmentations();
Factions["Speakers for the Dead"].addAllAugmentations();
Factions["NiteSec"].addAllAugmentations();
Factions["The Black Hand"].addAllAugmentations();
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

@ -1,32 +1,33 @@
import {Augmentations, AugmentationNames} from "./Augmentations";
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
import {Faction, Factions, factionExists,
joinFaction, displayFactionContent} from "./Faction";
import {Locations} from "./Locations";
import {Player} from "./Player";
import {hackWorldDaemon, redPillFlag} from "./RedPill";
import {numeralWrapper} from "./ui/numeralFormat";
import {KEY} from "../utils/helpers/keyCodes";
import { Augmentations , AugmentationNames } from "./Augmentations";
import { BitNodeMultipliers } from "./BitNodeMultipliers";
import { CONSTANTS } from "./Constants";
import { Engine } from "./engine";
import { Faction } from "./Faction/Faction";
import { Factions, factionExists } from "./Faction/Factions";
import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers";
import { Locations } from "./Locations";
import { Player } from "./Player";
import { hackWorldDaemon, redPillFlag } from "./RedPill";
import { numeralWrapper } from "./ui/numeralFormat";
import { KEY } from "../utils/helpers/keyCodes";
import {createProgressBarText} from "../utils/helpers/createProgressBarText";
import {dialogBoxCreate} from "../utils/DialogBox";
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver";
import {addOffset} from "../utils/helpers/addOffset";
import {appendLineBreaks} from "../utils/uiHelpers/appendLineBreaks";
import {clearObject} from "../utils/helpers/clearObject";
import {createElement} from "../utils/uiHelpers/createElement";
import {createPopup} from "../utils/uiHelpers/createPopup";
import {Page, routing} from "./ui/navigationTracking";
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {formatNumber} from "../utils/StringHelperFunctions";
import {getRandomInt} from "../utils/helpers/getRandomInt";
import {getTimestamp} from "../utils/helpers/getTimestamp";
import {removeElement} from "../utils/uiHelpers/removeElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById";
import { createProgressBarText } from "../utils/helpers/createProgressBarText";
import { dialogBoxCreate } from "../utils/DialogBox";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
import { Reviver, Generic_toJSON,
Generic_fromJSON } from "../utils/JSONReviver";
import { addOffset } from "../utils/helpers/addOffset";
import { appendLineBreaks } from "../utils/uiHelpers/appendLineBreaks";
import { clearObject } from "../utils/helpers/clearObject";
import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup";
import { Page, routing } from "./ui/navigationTracking";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { formatNumber } from "../utils/StringHelperFunctions";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { getTimestamp } from "../utils/helpers/getTimestamp";
import { removeElement } from "../utils/uiHelpers/removeElement";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
var CityNames = ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"];
@ -2105,7 +2106,7 @@ Bladeburner.prototype.createBlackOpsContent = function() {
"Each Black Op must be unlocked successively by completing " +
"the one before it.<br><br>" +
"<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete " +
"all of the Black Ops.</b><br><br>" +
"all of the Black Ops.</b><br><br>" +
"Like normal operations, you may use a team for Black Ops. Failing " +
"a black op will incur heavy HP and rank losses.";

@ -1,12 +1,12 @@
import {CodingContract,
CodingContractRewardType,
CodingContractTypes} from "./CodingContracts";
import {Factions} from "./Faction";
import {Player} from "./Player";
import {GetServerByHostname,
AllServers} from "./Server";
import { CodingContract,
CodingContractRewardType,
CodingContractTypes } from "./CodingContracts";
import { Factions } from "./Faction/Factions";
import { Player } from "./Player";
import { GetServerByHostname,
AllServers } from "./Server";
import {getRandomInt} from "../utils/helpers/getRandomInt";
import { getRandomInt } from "../utils/helpers/getRandomInt";
export function generateRandomContract() {
// First select a random problem type

@ -125,7 +125,7 @@ export class Company {
}
/**
* Serialize the current file to a JSON save state.
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("Company", this);

@ -1,29 +1,34 @@
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {Factions} from "./Faction";
import {showLiterature} from "./Literature";
import {Locations} from "./Locations";
import {Player} from "./Player";
import { BitNodeMultipliers } from "./BitNodeMultipliers";
import { Factions } from "./Faction/Factions";
import { showLiterature } from "./Literature";
import { Locations } from "./Locations";
import { Player } from "./Player";
import Decimal from "decimal.js";
import {numeralWrapper} from "./ui/numeralFormat";
import { numeralWrapper } from "./ui/numeralFormat";
import {dialogBoxCreate} from "../utils/DialogBox";
import {clearSelector} from "../utils/uiHelpers/clearSelector";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver";
import {createElement} from "../utils/uiHelpers/createElement";
import {createPopup} from "../utils/uiHelpers/createPopup";
import {Page, routing} from "./ui/navigationTracking";
import {formatNumber, generateRandomString} from "../utils/StringHelperFunctions";
import {getRandomInt} from "../utils/helpers/getRandomInt";
import {isString} from "../utils/helpers/isString";
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxGetInput, yesNoBoxClose,
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
import { dialogBoxCreate } from "../utils/DialogBox";
import { clearSelector } from "../utils/uiHelpers/clearSelector";
import { Reviver, Generic_toJSON,
Generic_fromJSON } from "../utils/JSONReviver";
import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup";
import { Page, routing } from "./ui/navigationTracking";
import { formatNumber, generateRandomString } from "../utils/StringHelperFunctions";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { isString } from "../utils/helpers/isString";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
import { yesNoBoxCreate,
yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton,
yesNoBoxGetNoButton,
yesNoTxtInpBoxGetYesButton,
yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxGetInput,
yesNoBoxClose,
yesNoTxtInpBoxClose,
yesNoBoxOpen } from "../utils/YesNoBox";
/* State */
var companyStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];

@ -1,19 +1,19 @@
import {AugmentationNames} from "./Augmentations";
import {generateRandomContract} from "./CodingContractGenerator";
import {Programs} from "./CreateProgram";
import {Factions} from "./Faction";
import {Player} from "./Player";
import {AllServers} from "./Server";
import {hackWorldDaemon} from "./RedPill";
import {StockMarket,
SymbolToStockMap} from "./StockMarket";
import {Stock} from "./Stock";
import {Terminal} from "./Terminal";
import {numeralWrapper} from "./ui/numeralFormat";
import {dialogBoxCreate} from "../utils/DialogBox";
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {createElement} from "../utils/uiHelpers/createElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById";
import { AugmentationNames } from "./Augmentations";
import { generateRandomContract } from "./CodingContractGenerator";
import { Programs } from "./CreateProgram";
import { Factions } from "./Faction/Factions";
import { Player } from "./Player";
import { AllServers } from "./Server";
import { hackWorldDaemon } from "./RedPill";
import { StockMarket,
SymbolToStockMap } from "./StockMarket";
import { Stock } from "./Stock";
import { Terminal } from "./Terminal";
import { numeralWrapper } from "./ui/numeralFormat";
import { dialogBoxCreate } from "../utils/DialogBox";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { createElement } from "../utils/uiHelpers/createElement";
import { removeElementById } from "../utils/uiHelpers/removeElementById";
const devMenuContainerId = "dev-menu-container";

118
src/Faction/Faction.ts Normal file

@ -0,0 +1,118 @@
import { CONSTANTS } from "../Constants";
import { FactionInfo,
FactionInfos } from "./FactionInfo";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
export class Faction {
/**
* Initiatizes a Faction object from a JSON save state.
*/
static fromJSON(value: any): Faction {
return Generic_fromJSON(Faction, value.data);
}
/**
* Flag signalling whether the player has already received an invitation
* to this faction
*/
alreadyInvited: boolean = false;
/**
* Holds names of all augmentations that this Faction offers
*/
augmentations: string[] = [];
/**
* Amount of favor the player has with this faction.
*/
favor: number = 0;
/**
* Flag signalling whether player has been banned from this faction
*/
isBanned: boolean = false;
/**
* Flag signalling whether player is a member of this faction
*/
isMember: boolean = false;
/**
* Name of faction
*/
name: string = "";
/**
* Amount of reputation player has with this faction
*/
playerReputation: number = 0;
/**
* Reputation from the last "prestige" that was not converted to favor.
* This reputation rolls over and is used for the next favor calculation
*/
rolloverRep: number = 0;
constructor(name: string="") {
this.name = name;
}
getInfo(): FactionInfo {
const info = FactionInfos[this.name];
if (info == null) {
throw new Error(`Missing faction from FactionInfos: ${this.name} this probably means the faction got corrupted somehow`);
}
return info;
}
gainFavor(): void {
if (this.favor == null) { this.favor = 0; }
if (this.rolloverRep == null) { this.rolloverRep = 0; }
const res = this.getFavorGain();
if (res.length !== 2) {
console.error("Invalid result from getFavorGain() function");
return;
}
this.favor += res[0];
this.rolloverRep = res[1];
}
//Returns an array with [How much favor would be gained, how much rep would be left over]
getFavorGain(): number[] {
if (this.favor == null) { this.favor = 0; }
if (this.rolloverRep == null) { this.rolloverRep = 0; }
var favorGain = 0, rep = this.playerReputation + this.rolloverRep;
let reqdRep = CONSTANTS.FactionReputationToFavorBase *
Math.pow(CONSTANTS.FactionReputationToFavorMult, this.favor);
while(rep > 0) {
if (rep >= reqdRep) {
++favorGain;
rep -= reqdRep;
} else {
break;
}
reqdRep *= CONSTANTS.FactionReputationToFavorMult;
}
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.
*/
toJSON(): any {
return Generic_toJSON("Faction", this);
}
}
Reviver.constructors.Faction = Faction;

@ -1,139 +1,26 @@
import {Augmentations, AugmentationNames,
PlayerOwnedAugmentation} from "./Augmentations";
import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
PlayerOwnedAugmentation} from "../Augmentations";
import {BitNodeMultipliers} from "../BitNodeMultipliers";
import {CONSTANTS} from "../Constants";
import {Engine} from "../engine";
import {FactionInfos} from "./FactionInfo";
import {Locations} from "./Location";
import {HackingMission, setInMission} from "./Missions";
import {Player} from "./Player";
import {PurchaseAugmentationsOrderSetting} from "./SettingEnums";
import {Settings} from "./Settings";
import {Locations} from "../Location";
import {HackingMission, setInMission} from "../Missions";
import {Player} from "../Player";
import {PurchaseAugmentationsOrderSetting} from "../SettingEnums";
import {Settings} from "../Settings";
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 {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";
Generic_fromJSON} from "../../utils/JSONReviver";
import {formatNumber} from "../../utils/StringHelperFunctions";
import {yesNoBoxCreate, yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox";
function Faction(name="") {
this.name = name;
this.augmentations = []; //Name of augmentation only
//Player-related properties for faction
this.isMember = false; //Whether player is member
this.isBanned = false; //Whether or not player is banned from joining this faction
this.playerReputation = 0; //"Reputation" within faction
this.alreadyInvited = false;
//Faction favor
this.favor = 0;
this.rolloverRep = 0;
};
Faction.prototype.getInfo = function() {
const info = FactionInfos[this.name];
if(info == null) {
throw new Error("Missing faction from FactionInfos: " + this.name+" this probably means the faction got corrupted somehow");
}
return info;
}
Faction.prototype.gainFavor = function() {
if (this.favor == null || this.favor == undefined) {this.favor = 0;}
if (this.rolloverRep == null || this.rolloverRep == undefined) {this.rolloverRep = 0;}
var res = this.getFavorGain();
if (res.length != 2) {
console.log("Error: invalid result from getFavorGain() function");
return;
}
this.favor += res[0];
this.rolloverRep = res[1];
}
//Returns an array with [How much favor would be gained, how much rep would be left over]
Faction.prototype.getFavorGain = function() {
if (this.favor == null || this.favor == undefined) {this.favor = 0;}
if (this.rolloverRep == null || this.rolloverRep == undefined) {this.rolloverRep = 0;}
var favorGain = 0, rep = this.playerReputation + this.rolloverRep;
var reqdRep = CONSTANTS.FactionReputationToFavorBase *
Math.pow(CONSTANTS.FactionReputationToFavorMult, this.favor);
while(rep > 0) {
if (rep >= reqdRep) {
++favorGain;
rep -= reqdRep;
} else {
break;
}
reqdRep *= CONSTANTS.FactionReputationToFavorMult;
}
return [favorGain, rep];
}
//Adds all Augmentations to this faction.
Faction.prototype.addAllAugmentations = function() {
this.augmentations.length = 0;
for (var name in Augmentations) {
if (Augmentations.hasOwnProperty(name)) {
this.augmentations.push(name);
}
}
}
Faction.prototype.toJSON = function() {
return Generic_toJSON("Faction", this);
}
Faction.fromJSON = function(value) {
return Generic_fromJSON(Faction, value.data);
}
Reviver.constructors.Faction = Faction;
//Map of factions indexed by faction name
let Factions = {}
function loadFactions(saveString) {
Factions = JSON.parse(saveString, Reviver);
}
function AddToFactions(faction) {
var name = faction.name;
Factions[name] = faction;
}
function factionExists(name) {
return Factions.hasOwnProperty(name);
}
//TODO Augmentation price and rep requirement mult are 1 for everything right now,
// This might change in the future for balance
function initFactions() {
for(const name in FactionInfos) {
resetFaction(new Faction(name));
}
}
//Resets a faction during (re-)initialization. Saves the favor in the new
//Faction object and deletes the old Faction Object from "Factions". Then
//reinserts the new Faction object
function resetFaction(newFactionObject) {
if (!(newFactionObject instanceof Faction)) {
throw new Error("Invalid argument 'newFactionObject' passed into resetFaction()");
}
var factionName = newFactionObject.name;
if (factionExists(factionName)) {
newFactionObject.favor = Factions[factionName].favor;
delete Factions[factionName];
}
AddToFactions(newFactionObject);
}
yesNoBoxGetNoButton, yesNoBoxClose} from "../../utils/YesNoBox";
function inviteToFaction(faction) {
if (Settings.SuppressFactionInvites) {
@ -783,6 +670,6 @@ function processPassiveFactionRepGain(numCycles) {
}
}
export {getNextNeurofluxLevel, Factions, initFactions, inviteToFaction,
export {getNextNeurofluxLevel, inviteToFaction,
joinFaction, displayFactionContent, processPassiveFactionRepGain,
loadFactions, Faction, purchaseAugmentation, factionExists};
purchaseAugmentation};

@ -1,9 +1,9 @@
import { IMap } from "./types";
import { IMap } from "../types";
/**
* Contains the "information" property for all the Factions, which is just a description of each faction
*/
class FactionInfo {
export class FactionInfo {
/**
* The multiplier to apply to augmentation base purchase price.
*/

@ -0,0 +1,6 @@
export enum FactionWorkType {
Field,
Hacking,
None,
Security,
}

47
src/Faction/Factions.ts Normal file

@ -0,0 +1,47 @@
/**
* Initialization and manipulation of the Factions object, which stores data
* about all Factions in the game
*/
import { Faction } from "./Faction";
import { FactionInfos } from "./FactionInfo";
import { IMap } from "../types";
import { Reviver } from "../../utils/JSONReviver";
export let Factions: IMap<Faction> = {};
export function loadFactions(saveString: string): void {
Factions = JSON.parse(saveString, Reviver);
}
export function AddToFactions(faction: Faction) {
const name: string = faction.name;
Factions[name] = faction;
}
export function factionExists(name: string): boolean {
return Factions.hasOwnProperty(name);
}
export function initFactions(bitNode: number=1) {
for (const name in FactionInfos) {
resetFaction(new Faction(name));
}
}
//Resets a faction during (re-)initialization. Saves the favor in the new
//Faction object and deletes the old Faction Object from "Factions". Then
//reinserts the new Faction object
export function resetFaction(newFactionObject: Faction) {
if (!(newFactionObject instanceof Faction)) {
throw new Error("Invalid argument 'newFactionObject' passed into resetFaction()");
}
const factionName: string = newFactionObject.name;
if (factionExists(factionName)) {
newFactionObject.favor = Factions[factionName].favor;
delete Factions[factionName];
}
AddToFactions(newFactionObject);
}

1
src/Faction/README.md Normal file

@ -0,0 +1 @@
Implementation of Faction-related mechanics

@ -3,32 +3,39 @@ Also 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, Factions,
displayFactionContent} from "./Faction";
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";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxGetInput, yesNoBoxClose,
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
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";
import { yesNoBoxCreate,
yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton,
yesNoBoxGetNoButton,
yesNoTxtInpBoxGetYesButton,
yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxGetInput,
yesNoBoxClose,
yesNoTxtInpBoxClose,
yesNoBoxOpen } from "../utils/YesNoBox";
// Constants
const GangRespectToReputationRatio = 5; // Respect is divided by this to get rep gain

14
src/Locations/Cities.ts Normal file

@ -0,0 +1,14 @@
import { IMap } from "../types";
/**
* Display Location Content when visiting somewhere in the World
*/
// tslint:disable-next-line:variable-name
export const Cities: IMap<string> = {
Aevum: "Aevum",
Chongqing: "Chongqing",
Ishima: "Ishima",
NewTokyo: "New Tokyo",
Sector12: "Sector-12",
Volhaven: "Volhaven",
};

@ -1,14 +1,14 @@
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
import {displayFactionContent} from "./Faction";
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";
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'
let inMission = false; //Flag to denote whether a mission is running
let currMission = null;

@ -22,9 +22,13 @@ import {calculateHackingChance,
calculateGrowTime,
calculateWeakenTime} from "./Hacking";
import {AllGangs} from "./Gang";
import {Factions, Faction, joinFaction,
factionExists, purchaseAugmentation} from "./Faction";
import {getCostOfNextHacknetNode, purchaseHacknet} from "./HacknetNode";
import { Faction } from "./Faction/Faction";
import { Factions,
factionExists } from "./Faction/Factions";
import { joinFaction,
purchaseAugmentation } from "./Faction/FactionHelpers";
import { getCostOfNextHacknetNode,
purchaseHacknet } from "./HacknetNode";
import {Locations} from "./Locations";
import {Message, Messages} from "./Message";
import {inMission} from "./Missions";

268
src/PersonObjects/Person.ts Normal file

@ -0,0 +1,268 @@
// Base class representing a person-like object
import { BitNodeMultipliers } from "../BitNodeMultipliers";
import { Cities } from "../Locations/Cities";
import { CONSTANTS } from "../Constants";
// Interface for an object that represents the player (PlayerObject)
// Used because at the time of implementation, the PlayerObject
// cant be converted to TypeScript.
//
// Only contains the needed properties for Sleeve implementation
export interface IPlayer {
companyName: string;
factions: string[];
money: any;
gainHackingExp(exp: number): void;
gainStrengthExp(exp: number): void;
gainDefenseExp(exp: number): void;
gainDexterityExp(exp: number): void;
gainAgilityExp(exp: number): void;
gainCharismaExp(exp: number): void;
gainMoney(money: number): void;
loseMoney(money: number): void;
}
// Interface for a Crime object
// Used because at the time of implementation, the Crime object has not been converted
// to Typescript
export interface ICrime {
name: string;
type: string;
time: number;
money: number;
difficulty: number;
karma: number;
hacking_success_weight: number;
strength_success_weight: number;
defense_success_weight: number;
dexterity_success_weight: number;
agility_success_weight: number;
charisma_success_weight: number;
hacking_exp: number;
strength_exp: number;
defense_exp: number;
dexterity_exp: number;
agility_exp: number;
charisma_exp: number;
intelligence_exp: number;
kills: number;
}
// Interface for Faction object
// Used because at the time of implementation, the Faction object has not been
// converted to TypeScript
export interface IFaction {
name: string;
playerReputation: number;
}
// Interface that defines a generic object used to track experience/money
// earnings for tasks
export interface ITaskTracker {
hack: number;
str: number;
def: number;
dex: number;
agi: number;
cha: number;
money: number;
}
export function createTaskTracker(): ITaskTracker {
return {
hack: 0,
str: 0,
def: 0,
dex: 0,
agi: 0,
cha: 0,
money: 0,
}
}
export abstract class Person {
/**
* Stats
*/
hacking_skill: number;
strength: number;
defense: number;
dexterity: number;
agility: number;
charisma: number;
hp: number;
max_hp: number;
/**
* Multipliers
*/
hacking_exp: number;
strength_exp: number;
defense_exp: number;
dexterity_exp: number;
agility_exp: number;
charisma_exp: number;
intelligence_exp: number;
hacking_mult: number;
strength_mult: number;
defense_mult: number;
dexterity_mult: number;
agility_mult: number;
charisma_mult: number;
hacking_exp_mult: number;
strength_exp_mult: number;
defense_exp_mult: number;
dexterity_exp_mult: number;
agility_exp_mult: number;
charisma_exp_mult: number;
company_rep_mult: number;
faction_rep_mult: number;
crime_money_mult: number;
crime_success_mult: number;
work_money_mult: number;
/**
* City that the person is in
*/
city: string;
constructor() {
this.hacking_skill = 1;
this.strength = 1;
this.defense = 1;
this.dexterity = 1;
this.agility = 1;
this.charisma = 1;
this.hp = 10;
this.max_hp = 10;
// Multipliers
this.hacking_exp = 0;
this.strength_exp = 0;
this.defense_exp = 0;
this.dexterity_exp = 0;
this.agility_exp = 0;
this.charisma_exp = 0;
this.intelligence_exp = 0;
this.hacking_mult = 1;
this.strength_mult = 1;
this.defense_mult = 1;
this.dexterity_mult = 1;
this.agility_mult = 1;
this.charisma_mult = 1;
this.hacking_exp_mult = 1;
this.strength_exp_mult = 1;
this.defense_exp_mult = 1;
this.dexterity_exp_mult = 1;
this.agility_exp_mult = 1;
this.charisma_exp_mult = 1;
this.company_rep_mult = 1;
this.faction_rep_mult = 1;
this.crime_money_mult = 1;
this.crime_success_mult = 1;
this.work_money_mult = 1;
this.city = Cities.Sector12;
}
/**
* Given an experience amount and stat multiplier, calculates the
* stat level. Stat-agnostic (same formula for every stat)
*/
calculateStat(exp: number, mult: number=1): number {
return Math.max(Math.floor(mult*(32 * Math.log(exp + 534.5) - 200)), 1);
}
/**
* Calculate and return the amount of faction reputation earned per cycle
* when doing Field Work for a faction
*/
getFactionFieldWorkRepGain(): number {
const t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
this.strength / CONSTANTS.MaxSkillLevel +
this.defense / CONSTANTS.MaxSkillLevel +
this.dexterity / CONSTANTS.MaxSkillLevel +
this.agility / CONSTANTS.MaxSkillLevel +
this.charisma / CONSTANTS.MaxSkillLevel) / 5.5;
return t * this.faction_rep_mult;
}
/**
* Calculate and return the amount of faction reputation earned per cycle
* when doing Hacking Work for a faction
*/
getFactionHackingWorkRepGain(): number {
return this.hacking_skill / CONSTANTS.MaxSkillLevel * this.faction_rep_mult;
}
/**
* Calculate and return the amount of faction reputation earned per cycle
* when doing Security Work for a faction
*/
getFactionSecurityWorkRepGain(): number {
const t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
this.strength / CONSTANTS.MaxSkillLevel +
this.defense / CONSTANTS.MaxSkillLevel +
this.dexterity / CONSTANTS.MaxSkillLevel +
this.agility / CONSTANTS.MaxSkillLevel) / 4.5;
return t * this.faction_rep_mult;
}
/**
* Reset all multipliers to 1
*/
resetMultipliers(): void {
this.hacking_mult = 1;
this.strength_mult = 1;
this.defense_mult = 1;
this.dexterity_mult = 1;
this.agility_mult = 1;
this.charisma_mult = 1;
this.hacking_exp_mult = 1;
this.strength_exp_mult = 1;
this.defense_exp_mult = 1;
this.dexterity_exp_mult = 1;
this.agility_exp_mult = 1;
this.charisma_exp_mult = 1;
this.company_rep_mult = 1;
this.faction_rep_mult = 1;
this.crime_money_mult = 1;
this.crime_success_mult = 1;
this.work_money_mult = 1;
}
/**
* Update all stat levels
*/
updateStatLevels(): void {
this.hacking_skill = Math.max(1, Math.floor(this.calculateStat(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
this.strength = Math.max(1, Math.floor(this.calculateStat(this.strength_exp, this.strength_mult)));
this.defense = Math.max(1, Math.floor(this.calculateStat(this.defense_exp, this.defense_mult)));
this.dexterity = Math.max(1, Math.floor(this.calculateStat(this.dexterity_exp, this.dexterity_mult)));
this.agility = Math.max(1, Math.floor(this.calculateStat(this.agility_exp, this.agility_mult)));
this.charisma = Math.max(1, Math.floor(this.calculateStat(this.charisma_exp, this.charisma_mult)));
const ratio: number = this.hp / this.max_hp;
this.max_hp = Math.floor(10 + this.defense / 10);
this.hp = Math.round(this.max_hp * ratio);
}
}

@ -0,0 +1,2 @@
Implementation of all Person-type objects, including but not limited to
the "PlayerObject" and Sleeves.

@ -0,0 +1,598 @@
/**
* Sleeves are clones of the player that can be used to perform
* different tasks synchronously.
*
* Each sleeve is its own individual, meaning it has its own stats/exp
*
* Sleeves are unlocked in BitNode-10.
*/
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
import { Person,
IPlayer,
ICrime,
IFaction,
ITaskTracker,
createTaskTracker } from "../Person";
import { BitNodeMultipliers } from "../../BitNodeMultipliers";
import { Cities } from "../../Locations/Cities";
import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company";
import { CONSTANTS } from "../../Constants";
import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
import { Locations } from "../../Locations";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
export class Sleeve extends Person {
/**
* Initiatizes a Sleeve object from a JSON save state.
*/
static fromJSON(value: any): Sleeve {
return Generic_fromJSON(Sleeve, value.data);
}
/**
* Enum value for current task
*/
currentTask: SleeveTaskType = SleeveTaskType.Idle;
/**
* Description of current task. Used only for logging purposes
*/
currentTaskDescription: string = "";
/**
* For what company/faction the current task is assigned to.
* Only applicable when working for faction or company, obviously
*/
currentTaskLocation: string = "";
/**
* Maximum amount of time (in milliseconds) that can be spent on current task.
*/
currentTaskMaxTime: number = 0;
/**
* Milliseconds spent on current task
*/
currentTaskTime: number = 0;
/**
* Keeps track of experience earned for other sleeves
*/
earningsForSleeves: ITaskTracker = createTaskTracker();
/**
* Keeps track of experience + money earned for player
*/
earningsForPlayer: ITaskTracker = createTaskTracker();
/**
* Keeps track of experienced earned in the current task/action
*/
earningsForTask: ITaskTracker = createTaskTracker();
/**
* Keeps track of what type of work sleeve is doing for faction, if applicable
*/
factionWorkType: FactionWorkType = FactionWorkType.None;
/**
* Records experience gain rate for the current task
*/
gainRatesForTask: ITaskTracker = createTaskTracker();
/**
* Keeps track of events/notifications for this sleeve
*/
logs: string[] = [];
/**
* Clone retains memory% of exp upon prestige. If exp would be lower than previously
* kept exp, nothing happens
*/
memory: number = 0;
/**
* Sleeve shock. Number between 1 and 100
* Trauma/shock that comes with being in a sleeve. Experience earned
* is multipled by shock%. This gets applied before synchronization
*/
shock: number = 1;
/**
* Stored number of game "loop" cycles
*/
storedCycles: number = 0;
/**
* Synchronization. Number between 0 and 100
* When experience is earned by sleeve, both the player and the sleeve get
* sync% of the experience earned. Other sleeves get sync^2% of exp
*/
sync: number = 1;
constructor() {
super();
/*
this.currentTask = SleeveTaskType.Idle;
this.currentTaskDescription = "";
this.currentTaskTime = 0;
this.currentTaskMaxTime = 0;
this.earningsForSleeves = createTaskTracker();
this.earningsForPlayer = createTaskTracker();
this.earningsForTask = createTaskTracker();
this.gainRatesForTask = createTaskTracker();
this.logs = [];
this.memory = 0;
this.shock = 1;
this.storedCycles = 0;
this.sync = 1;
*/
}
/**
* Commit crimes
*/
commitCrime(p: IPlayer, crime: ICrime): void {
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
} else {
this.resetTaskStatus();
}
this.gainRatesForTask.hack = crime.hacking_exp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.str = crime.strength_exp * this.strength_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.def = crime.defense_exp * this.defense_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
this.currentTaskMaxTime = crime.time;
this.currentTask = SleeveTaskType.Crime;
}
/**
* Called to stop the current task
*/
finishTask(): void {
if (this.currentTask === SleeveTaskType.Crime) {
} else {
}
this.resetTaskStatus();
}
/**
* Earn experience for any stats (supports multiple)
* This function also handles experience propogating to Player and other sleeves
*/
gainExperience(p: IPlayer, exp: ITaskTracker, numCycles: number=1): ITaskTracker {
// Experience is first multiplied by shock. Then 'synchronization'
// is accounted for
const multFac = (this.shock / 100) * (this.sync / 100) * numCycles;
const pHackExp = exp.hack * multFac;
const pStrExp = exp.str * multFac;
const pDefExp = exp.def * multFac;
const pDexExp = exp.dex * multFac;
const pAgiExp = exp.agi * multFac;
const pChaExp = exp.cha * multFac;
// Experience is gained by both this sleeve and player
if (pHackExp > 0) {
this.hacking_exp += pHackExp;
p.gainHackingExp(pHackExp);
this.earningsForPlayer.hack += pHackExp;
this.earningsForTask.hack += pHackExp;
}
if (pStrExp > 0) {
this.strength_exp += pStrExp;
p.gainStrengthExp(pStrExp);
this.earningsForPlayer.str += pStrExp;
this.earningsForTask.str += pStrExp;
}
if (pDefExp > 0) {
this.defense_exp += pDefExp;
p.gainDefenseExp(pDefExp);
this.earningsForPlayer.def += pDefExp;
this.earningsForTask.dex += pDefExp;
}
if (pDexExp > 0) {
this.dexterity_exp += pDexExp;
p.gainDexterityExp(pDexExp);
this.earningsForPlayer.dex += pDexExp;
this.earningsForTask.dex += pDexExp;
}
if (pAgiExp > 0) {
this.agility_exp += pAgiExp;
p.gainAgilityExp(pAgiExp);
this.earningsForPlayer.agi += pAgiExp;
this.earningsForTask.agi += pAgiExp;
}
if (pChaExp > 0) {
this.charisma_exp += pChaExp;
p.gainCharismaExp(pChaExp);
this.earningsForPlayer.cha += pChaExp;
this.earningsForTask.cha += pChaExp;
}
// Record earnings for other sleeves
this.earningsForSleeves.hack += (pHackExp * (this.sync / 100));
this.earningsForSleeves.str += (pStrExp * (this.sync / 100));
this.earningsForSleeves.def += (pDefExp * (this.sync / 100));
this.earningsForSleeves.dex += (pDexExp * (this.sync / 100));
this.earningsForSleeves.agi += (pAgiExp * (this.sync / 100));
this.earningsForSleeves.cha += (pChaExp * (this.sync / 100));
// Return the experience to be gained by other sleeves
return {
hack: pHackExp * (this.sync / 100),
str: pStrExp * (this.sync / 100),
def: pDefExp * (this.sync / 100),
dex: pDexExp * (this.sync / 100),
agi: pAgiExp * (this.sync / 100),
cha: pChaExp * (this.sync / 100),
money: 0,
}
}
/**
* Earn money for player
*/
gainMoney(p: IPlayer, task: ITaskTracker, numCycles: number=1): void {
p.gainMoney(task.money * numCycles);
}
/**
* Gets reputation gain for the current task
* Only applicable when working for company or faction
*/
getRepGain(): number {
if (this.currentTask === SleeveTaskType.Faction) {
switch (this.factionWorkType) {
case FactionWorkType.Hacking:
return this.getFactionHackingWorkRepGain();
case FactionWorkType.Field:
return this.getFactionFieldWorkRepGain();
case FactionWorkType.Security:
return this.getFactionSecurityWorkRepGain();
default:
console.warn(`Invalid Sleeve.factionWorkType property in Sleeve.getRepGain(): ${this.factionWorkType}`);
return 0;
}
} else if (this.currentTask === SleeveTaskType.Company) {
return 0;
} else {
console.warn(`Sleeve.getRepGain() called for invalid task type: ${this.currentTask}`);
return 0;
}
}
log(entry: string): void {
const MaxLogSize: number = 50;
this.logs.push(entry);
if (this.logs.length > MaxLogSize) {
this.logs.shift();
}
}
/**
* Process loop
* Returns an object containing the amount of experience that should be
* transferred to all other sleeves
*/
process(p: IPlayer, numCycles: number=1): ITaskTracker | null {
// Only process once every second (5 cycles)
const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle;
this.storedCycles += numCycles;
if (this.storedCycles < CyclesPerSecond) { return null; }
// Shock gradually goes towards 100
this.shock = Math.max(100, this.shock + (0.0001 * this.storedCycles));
if (this.currentTask === SleeveTaskType.Idle) { return null; }
let time = this.storedCycles * CONSTANTS.MilliPerCycle;
let cyclesUsed = this.storedCycles;
if (this.currentTaskTime + time > this.currentTaskMaxTime) {
time = this.currentTaskMaxTime - this.currentTaskTime;
cyclesUsed = Math.floor(time / CONSTANTS.MilliPerCycle);
if (time < 0 || cyclesUsed < 0) {
console.warn(`Sleeve.process() calculated negative cycle usage`);
time = 0;
cyclesUsed = 0;
}
}
this.currentTaskTime += time;
let retValue: ITaskTracker = createTaskTracker();
switch (this.currentTask) {
case SleeveTaskType.Class:
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
break;
case SleeveTaskType.Faction:
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
// TODO REP for both this and company
const fac = Factions[this.currentTaskLocation];
if (!(fac instanceof Faction)) {
console.error(`Invalid faction for Sleeve task: ${this.currentTaskLocation}`);
break;
}
break;
case SleeveTaskType.Company:
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
break;
case SleeveTaskType.Recovery:
this.shock = Math.max(100, this.shock + (0.001 * this.storedCycles));
break;
case SleeveTaskType.Sync:
this.sync = Math.max(100, this.sync + (0.001 * this.storedCycles));
break;
default:
break;
}
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
this.finishTask();
}
this.storedCycles -= cyclesUsed;
// TODO Finish this
return retValue;
}
/**
* Resets all parameters used to keep information about the current task
*/
resetTaskStatus(): void {
this.earningsForTask = createTaskTracker();
this.gainRatesForTask = createTaskTracker();
this.currentTask = SleeveTaskType.Idle;
this.currentTaskTime = 0;
this.currentTaskMaxTime = 0;
this.factionWorkType = FactionWorkType.None;
}
/**
* Take a course at a university
*/
takeUniversityCourse(p: IPlayer, universityName: string, className: string): boolean {
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
} else {
this.resetTaskStatus();
}
// Set exp/money multipliers based on which university.
// Also check that the sleeve is in the right city
let costMult: number = 1;
let expMult: number = 1;
switch (universityName.toLowerCase()) {
case Locations.AevumSummitUniversity.toLowerCase():
if (this.city !== Cities.Aevum) { return false; }
costMult = 4;
expMult = 3;
break;
case Locations.Sector12RothmanUniversity.toLowerCase():
if (this.city !== Cities.Sector12) { return false; }
costMult = 3;
expMult = 2;
break;
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
if (this.city !== Cities.Volhaven) { return false; }
costMult = 5;
expMult = 4;
break;
default:
return false;
}
// Number of game cycles in a second
const cps: number = 1000 / CONSTANTS.MilliPerCycle;
// Set experience/money gains based on class
// TODO Refactor University Courses into its own class or something
const baseStudyComputerScienceExp: number = 0.5;
const baseDataStructuresExp: number = 1;
const baseNetworksExp: number = 2;
const baseAlgorithmsExp: number = 4;
const baseManagementExp: number = 2;
const baseLeadershipExp: number = 4;
switch (className.toLowerCase()) {
case "study computer science":
this.gainRatesForTask.hack = (baseStudyComputerScienceExp * expMult * this.hacking_exp_mult);
break;
case "data structures":
this.gainRatesForTask.hack = (baseDataStructuresExp * expMult * this.hacking_exp_mult);
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassDataStructuresBaseCost * costMult);
break;
case "networks":
this.gainRatesForTask.hack = (baseNetworksExp * expMult * this.hacking_exp_mult);
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassNetworksBaseCost * costMult);
break;
case "algorithms":
this.gainRatesForTask.hack = (baseAlgorithmsExp * expMult * this.hacking_exp_mult);
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassAlgorithmsBaseCost * costMult);
break;
case "management":
this.gainRatesForTask.cha = (baseManagementExp * expMult * this.charisma_exp_mult);
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassManagementBaseCost * costMult);
break;
case "leadership":
this.gainRatesForTask.cha = (baseLeadershipExp * expMult * this.charisma_exp_mult);
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassLeadershipBaseCost * costMult);
break;
default:
return false;
}
this.currentTask = SleeveTaskType.Class;
return true;
}
/**
* Travel to another City. Costs money from player
*/
travel(p: IPlayer, newCity: string): boolean {
if (Cities[newCity] == null) {
console.error(`Invalid city ${newCity} passed into Sleeve.travel()`);
return false;
}
p.loseMoney(CONSTANTS.TravelCost);
this.city = newCity;
return true;
}
/**
* Work for a company
*/
workForCompany(p: IPlayer): boolean {
return true;
}
/**
* Work for one of the player's factions
*/
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
return false;
}
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
} else {
this.resetTaskStatus();
}
// Set type of work (hacking/field/security), and the experience gains
const sanitizedWorkType: string = workType.toLowerCase();
if (sanitizedWorkType.includes("hack")) {
this.factionWorkType = FactionWorkType.Hacking;
this.gainRatesForTask.hack = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
} else if (sanitizedWorkType.includes("field")) {
this.factionWorkType = FactionWorkType.Field;
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.str = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.def = .1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.dex = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.agi = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.cha = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
} else if (sanitizedWorkType.includes("security")) {
this.factionWorkType = FactionWorkType.Security;
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.str = .15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.def = .15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.dex = .15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.gainRatesForTask.agi = .15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
} else {
return false;
}
this.currentTaskLocation = factionName;
this.currentTask = SleeveTaskType.Faction;
return true;
}
/**
* Begin a gym workout task
*/
workoutAtGym(p: IPlayer, gymName: string, stat: string): boolean {
if (this.currentTask !== SleeveTaskType.Idle) {
this.finishTask();
} else {
this.resetTaskStatus();
}
// Set exp/money multipliers based on which university.
// Also check that the sleeve is in the right city
let costMult: number = 1;
let expMult: number = 1;
switch (gymName.toLowerCase()) {
case Locations.AevumCrushFitnessGym.toLowerCase():
if (this.city != Cities.Aevum) { return false; }
costMult = 3;
expMult = 2;
break;
case Locations.AevumSnapFitnessGym.toLowerCase():
if (this.city != Cities.Aevum) { return false; }
costMult = 10;
expMult = 5;
break;
case Locations.Sector12IronGym.toLowerCase():
if (this.city != Cities.Sector12) { return false; }
costMult = 1;
expMult = 1;
break;
case Locations.Sector12PowerhouseGym.toLowerCase():
if (this.city != Cities.Sector12) { return false; }
costMult = 20;
expMult = 10;
break;
case Locations.VolhavenMilleniumFitnessGym:
if (this.city != Cities.Volhaven) { return false; }
costMult = 7;
expMult = 4;
break;
default:
return false;
}
// Number of game cycles in a second
const cps = 1000 / CONSTANTS.MilliPerCycle;
// Set experience/money gains based on class
// TODO Refactor University Courses into its own class or something
const baseGymExp: number = 1;
const sanitizedStat: string = stat.toLowerCase();
// Set cost
this.gainRatesForTask.money = -1 * (CONSTANTS.ClassGymBaseCost * costMult);
// Set stat gain rate
if (sanitizedStat.includes("str")) {
this.gainRatesForTask.str = (baseGymExp * expMult);
} else if (sanitizedStat.includes("def")) {
this.gainRatesForTask.def = (baseGymExp * expMult);
} else if (sanitizedStat.includes("dex")) {
this.gainRatesForTask.dex = (baseGymExp * expMult);
} else if (sanitizedStat.includes("agi")) {
this.gainRatesForTask.agi = (baseGymExp * expMult);
} else {
return false;
}
this.currentTask = SleeveTaskType.Class;
return true;
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("Sleeve", this);
}
}
Reviver.constructors.Sleeve = Sleeve;

@ -0,0 +1,12 @@
/**
* Enum for different types of tasks that a Sleeve can perform
*/
export enum SleeveTaskType {
Class,
Company,
Crime,
Faction,
Idle,
Recovery,
Sync,
}

@ -14,8 +14,9 @@ import {Corporation} from "./CompanyManagement";
import {Programs} from "./CreateProgram";
import {determineCrimeSuccess, Crimes} from "./Crimes";
import {Engine} from "./engine";
import {Factions, Faction,
displayFactionContent} from "./Faction";
import { Faction } from "./Faction/Faction";
import { Factions } from "./Faction/Factions";
import { displayFactionContent } from "./Faction/FactionHelpers";
import {Gang, resetGangs} from "./Gang";
import {Locations} from "./Locations";
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
@ -41,10 +42,10 @@ function PlayerObject() {
//Combat stats
this.hp = 10;
this.max_hp = 10;
this.strength = 1; //Damage dealt
this.defense = 1; //Damage received
this.dexterity = 1; //Accuracy
this.agility = 1; //Dodge %
this.strength = 1;
this.defense = 1;
this.dexterity = 1;
this.agility = 1;
//Labor stats
this.charisma = 1;
@ -594,7 +595,7 @@ PlayerObject.prototype.gainIntelligenceExp = function(exp) {
//Given a string expression like "str" or "strength", returns the given stat
PlayerObject.prototype.queryStatFromString = function(str) {
var tempStr = str.toLowerCase();
const tempStr = str.toLowerCase();
if (tempStr.includes("hack")) {return Player.hacking_skill;}
if (tempStr.includes("str")) {return Player.strength;}
if (tempStr.includes("def")) {return Player.defense;}

@ -7,8 +7,10 @@ import {writeCinematicText} from "./CinematicText";
import {Companies, initCompanies} from "./Company/Companies";
import {Programs} from "./CreateProgram";
import {Engine} from "./engine";
import {Factions, Faction, initFactions,
joinFaction} from "./Faction";
import { Faction } from "./Faction/Faction";
import { Factions,
initFactions } from "./Faction/Factions";
import { joinFaction } from "./Faction/FactionHelpers";
import {deleteGangDisplayContent} from "./Gang";
import {Locations} from "./Location";
import {initMessages, Messages, Message} from "./Message";

@ -4,8 +4,9 @@ import {Companies, loadCompanies} from "./Company/Companies";
import {CompanyPosition} from "./Company/CompanyPosition";
import {CONSTANTS} from "./Constants";
import {Engine} from "./engine";
import {loadFactions, Factions,
processPassiveFactionRepGain} from "./Faction";
import { Factions,
loadFactions } from "./Faction/Factions";
import { processPassiveFactionRepGain } from "./Faction/FactionHelpers";
import {FconfSettings, loadFconf} from "./Fconf";
import {loadAllGangs, AllGangs} from "./Gang";
import {processAllHacknetNodeEarnings} from "./HacknetNode";

@ -34,9 +34,10 @@ import {displayCreateProgramContent,
initCreateProgramButtons,
Programs} from "./CreateProgram";
import {createDevMenu, closeDevMenu} from "./DevMenu";
import {displayFactionContent, joinFaction,
processPassiveFactionRepGain, Factions,
inviteToFaction, initFactions} from "./Faction";
import { Factions, initFactions } from "./Faction/Factions";
import { displayFactionContent, joinFaction,
processPassiveFactionRepGain,
inviteToFaction } from "./Faction/FactionHelpers";
import {FconfSettings} from "./Fconf";
import {displayLocationContent,
initLocationButtons} from "./Location";

@ -1,4 +1,4 @@
import {joinFaction} from "../src/Faction";
import {joinFaction} from "../src/Faction/FactionHelpers";
import {Engine} from "../src/engine";
import {Player} from "../src/Player";
import {clearEventListeners} from "./uiHelpers/clearEventListeners";

@ -1,10 +1,11 @@
import {BitNodeMultipliers} from "../src/BitNodeMultipliers";
import {CONSTANTS} from "../src/Constants";
import {Factions, Faction} from "../src/Faction";
import {Player} from "../src/Player";
import {dialogBoxCreate} from "./DialogBox";
import {clearEventListeners} from "./uiHelpers/clearEventListeners";
import {formatNumber} from "./StringHelperFunctions";
import { BitNodeMultipliers } from "../src/BitNodeMultipliers";
import { CONSTANTS } from "../src/Constants";
import { Faction } from "../src/Faction/Faction";
import { Factions } from "../src/Faction/Factions";
import { Player } from "../src/Player";
import { dialogBoxCreate } from "./DialogBox";
import { clearEventListeners } from "./uiHelpers/clearEventListeners";
import { formatNumber } from "./StringHelperFunctions";
//Keep track of last faction
var lastFac = "";