fix sleeve memory bug

This commit is contained in:
Olivier Gagnon 2021-09-08 23:47:34 -04:00
parent bada8a5f39
commit 2a13db39c7
360 changed files with 5424 additions and 15764 deletions

@ -1,4 +1,5 @@
{
"trailingComma": "all",
"tabWidth": 2
"tabWidth": 2,
"printWidth": 120
}

@ -1,7 +1,3 @@
module.exports = {
presets: [
"@babel/preset-react",
"@babel/preset-env",
"@babel/preset-typescript",
],
presets: ["@babel/preset-react", "@babel/preset-env", "@babel/preset-typescript"],
};

@ -1,5 +1,5 @@
$fontFamily: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas",
"Courier New", Courier, monospace, "Times New Roman";
$fontFamily: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas", "Courier New", Courier, monospace,
"Times New Roman";
$defaultFontSize: 16px;
/* COLORS */

@ -21,8 +21,7 @@
white-space: nowrap;
&.hacknet-node {
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1),
0 0 16px rgba(0, 0, 0, 0.1);
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
margin: 6px;

@ -17,8 +17,7 @@ describe("netscript", () => {
cy.findByRole("textbox").type("nano script.js{enter}");
// monaco can take a bit
cy.findByRole("code", { timeout: 15_000 }).type("{selectall}{del}")
.type(`export const main = async (ns) => {{}
cy.findByRole("code", { timeout: 15_000 }).type("{selectall}{del}").type(`export const main = async (ns) => {{}
while(true) {{}
await ns.hack("n00dles");`);
@ -39,8 +38,7 @@ describe("netscript", () => {
cy.findByRole("textbox").type("nano script.js{enter}");
// monaco can take a bit
cy.findByRole("code", { timeout: 15_000 }).type("{selectall}{del}")
.type(`export const main = async (ns) => {{}
cy.findByRole("code", { timeout: 15_000 }).type("{selectall}{del}").type(`export const main = async (ns) => {{}
const command = "hack";
ns[command]("n00dles");`);
@ -48,8 +46,6 @@ ns[command]("n00dles");`);
cy.findByRole("button", { name: /Save & Close/i }).click();
cy.findByRole("textbox").type("run script.js{enter}");
cy.findByText(
/Dynamic RAM usage calculated to be greater than initial RAM usage on fn: hack./i,
);
cy.findByText(/Dynamic RAM usage calculated to be greater than initial RAM usage on fn: hack./i);
});
});

@ -49,14 +49,10 @@ describe("tutorial", () => {
cy.findByRole("button", { name: "Next" }).click();
cy.findByText(/hacking exp/i);
cy.findByRole("textbox", { timeout: 15_000 })
.should("not.be.disabled")
.type("nano n00dles.script{enter}");
cy.findByRole("textbox", { timeout: 15_000 }).should("not.be.disabled").type("nano n00dles.script{enter}");
// monaco can take a bit
cy.findByRole("code", { timeout: 15_000 })
.type("{selectall}{del}")
.type("while(true) {{}{enter}hack('n00dles');");
cy.findByRole("code", { timeout: 15_000 }).type("{selectall}{del}").type("while(true) {{}{enter}hack('n00dles');");
cy.findByRole("button", { name: /Save & Close/i }).click();

@ -19,4 +19,4 @@
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
};

@ -1,18 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta charset="utf-8" />
<title>Bitburner</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"/>
<link rel="manifest" href="dist/site.webmanifest"/>
<link rel="mask-icon" href="dist/safari-pinned-tab.svg" color="#000000"/>
<meta name="apple-mobile-web-app-title" content="Bitburner"/>
<meta name="application-name" content="Bitburner"/>
<meta name="msapplication-TileColor" content="#000000"/>
<meta name="msapplication-config" content="dist/browserconfig.xml"/>
<meta name="theme-color" content="#ffffff"/>
<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" />
<link rel="manifest" href="dist/site.webmanifest" />
<link rel="mask-icon" href="dist/safari-pinned-tab.svg" color="#000000" />
<meta name="apple-mobile-web-app-title" content="Bitburner" />
<meta name="application-name" content="Bitburner" />
<meta name="msapplication-TileColor" content="#000000" />
<meta name="msapplication-config" content="dist/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" />
<!-- Google Analytics -->
<script>
@ -28,25 +28,18 @@
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
"script",
"https://www.google-analytics.com/analytics.js",
"ga",
);
})(window, document, "script", "https://www.google-analytics.com/analytics.js", "ga");
</script>
<script>
ga(
"create",
"UA-100157497-1",
"auto",
);
ga("create", "UA-100157497-1", "auto");
ga("send", "pageview");
</script>
<link rel="shortcut icon" href="favicon.ico"><link href="dist/vendor.css" rel="stylesheet"><link href="dist/engineStyle.css" rel="stylesheet"></head>
<link rel="shortcut icon" href="favicon.ico" />
<link href="dist/vendor.css" rel="stylesheet" />
<link href="dist/engineStyle.css" rel="stylesheet" />
</head>
<body>
<div id="entire-game-container" style="visibility: hidden">
<div id="mainmenu-container">
@ -54,9 +47,7 @@
<ul id="mainmenu" class="mainmenu noscrollbar">
<!-- Hacking dropdown -->
<li id="hacking-menu-header-li">
<button id="hacking-menu-header" class="mainmenu-accordion-header noselect">
Hacking
</button>
<button id="hacking-menu-header" class="mainmenu-accordion-header noselect">Hacking</button>
</li>
<li id="terminal-tab" class="mainmenu-accordion-panel noselect">
<button id="terminal-menu-link">Terminal</button>
@ -69,15 +60,12 @@
</li>
<li id="create-program-tab" class="mainmenu-accordion-panel noselect">
<button id="create-program-menu-link">Create Program</button>
<span id="create-program-notification" class="notification-off">
</span>
<span id="create-program-notification" class="notification-off"> </span>
</li>
<!-- Character dropdown -->
<li id="character-menu-header-li">
<button id="character-menu-header" class="mainmenu-accordion-header noselect">
Character
</button>
<button id="character-menu-header" class="mainmenu-accordion-header noselect">Character</button>
</li>
<li id="stats-tab" class="mainmenu-accordion-panel noselect">
<button id="stats-menu-link">Stats</button>
@ -87,13 +75,10 @@
<span id="factions-notification" class="notification-off"> </span>
</li>
<li id="augmentations-tab" class="mainmenu-accordion-panel noselect">
<button id="augmentations-menu-link" style="overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;">
<button id="augmentations-menu-link" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
Augmentations
</button>
<span id="augmentations-notification" class="notification-off">
</span>
<span id="augmentations-notification" class="notification-off"> </span>
</li>
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel noselect">
<button id="hacknet-nodes-menu-link">Hacknet</button>
@ -104,9 +89,7 @@
<!-- World dropdown -->
<li id="world-menu-header-li">
<button id="world-menu-header" class="mainmenu-accordion-header noselect">
World
</button>
<button id="world-menu-header" class="mainmenu-accordion-header noselect">World</button>
</li>
<li id="city-tab" class="mainmenu-accordion-panel noselect">
<button id="city-menu-link">City</button>
@ -131,9 +114,7 @@
</li>
<li id="help-menu-header-li">
<button id="help-menu-header" class="mainmenu-accordion-header noselect">
Help
</button>
<button id="help-menu-header" class="mainmenu-accordion-header noselect">Help</button>
</li>
<li id="milestones-tab" class="mainmenu-accordion-panel noselect">
<button id="milestones-menu-link">Milestones</button>
@ -156,7 +137,7 @@
<p id="script-editor-filename-tag">
<strong style="background-color: #555">Script name: </strong>
</p>
<input id="script-editor-filename" type="text" maxlength="100" tabindex="1"/>
<input id="script-editor-filename" type="text" maxlength="100" tabindex="1" />
</div>
<div id="monaco-editor"></div>
@ -188,17 +169,34 @@
<fieldset>
<label for="script-editor-option-highlightactiveline">Highlight Active Line</label>
<input type="checkbox" class="optionCheckbox" name="script-editor-option-highlightactiveline" id="script-editor-option-highlightactiveline" checked/>
<input
type="checkbox"
class="optionCheckbox"
name="script-editor-option-highlightactiveline"
id="script-editor-option-highlightactiveline"
checked
/>
</fieldset>
<fieldset>
<label for="script-editor-option-showinvisibles">Show Invisibles</label>
<input type="checkbox" class="optionCheckbox" name="script-editor-option-showinvisibles" id="script-editor-option-showinvisibles"/>
<input
type="checkbox"
class="optionCheckbox"
name="script-editor-option-showinvisibles"
id="script-editor-option-showinvisibles"
/>
</fieldset>
<fieldset>
<label for="script-editor-option-usesofttab">Use Soft Tab</label>
<input type="checkbox" class="optionCheckbox" name="script-editor-option-usesofttab" id="script-editor-option-usesofttab" checked/>
<input
type="checkbox"
class="optionCheckbox"
name="script-editor-option-usesofttab"
id="script-editor-option-usesofttab"
checked
/>
</fieldset>
<fieldset id="script-editor-option-flex1-fieldset"></fieldset>
@ -224,7 +222,14 @@
<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;" autocomplete="off"/>
<input
type="text"
id="terminal-input-text-box"
class="terminal-input"
tabindex="1"
onfocus="this.value = this.value;"
autocomplete="off"
/>
</td>
</tr>
</table>
@ -238,19 +243,18 @@
<!-- Active scripts info page -->
<div id="active-scripts-container" class="generic-menupage-container">
<p id="active-scripts-text">
This page displays a list of all of your scripts that are currently
running across every machine. It also provides information about each
script's production. The scripts are categorized by the hostname of
the servers on which they are running.
This page displays a list of all of your scripts that are currently running across every machine. It also
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/>
<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>)
(<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"></ul>
</div>
@ -263,11 +267,9 @@
<!-- Create a program(executable) -->
<div id="create-program-container" class="generic-menupage-container">
<p id="create-program-page-text">
This page displays any programs that you are able to create. Writing
the code for a program takes time, which can vary based on how complex
the program is. If you are working on creating a program you can
cancel at any time. Your progress will be saved and you can continue
later.
This page displays any programs that you are able to create. Writing the code for a program takes time, which
can vary based on how complex the program is. If you are working on creating a program you can cancel at any
time. Your progress will be saved and you can continue later.
</p>
<ul id="create-program-list"></ul>
@ -291,28 +293,76 @@
<!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container">
<h1>Tutorial (AKA Links to Documentation)</h1>
<a id="tutorial-getting-started-link" class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html">
Getting Started</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html">
Servers & Networking</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html">
Hacking</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html">
Scripts</a><br/><br/>
<a
id="tutorial-getting-started-link"
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html"
>
Getting Started</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html"
>
Servers & Networking</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html"
>
Hacking</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html"
>
Scripts</a
><br /><br />
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/netscript.html">
Netscript Programming Language</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html">
Traveling</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html">
Companies</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html">
Infiltration</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html">
Factions</a><br/><br/>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html">
Augmentations</a><br/><br/>
Netscript Programming Language</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html"
>
Traveling</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html"
>
Companies</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html"
>
Infiltration</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html"
>
Factions</a
><br /><br />
<a
class="a-link-button"
target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html"
>
Augmentations</a
><br /><br />
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/shortcuts.html">
Keyboard Shortcuts</a>
Keyboard Shortcuts</a
>
</div>
<!-- Location (visiting a location in World) -->
@ -341,13 +391,9 @@
<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"/>
<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>
<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>
</div>
@ -357,17 +403,12 @@
<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/>
Warning: Joining this faction may prevent you from joining other
factions during this run!
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">
Join!
</button>
<button id="faction-invitation-box-no" class="popup-box-button">
Decide later
</button>
<button id="faction-invitation-box-yes" class="popup-box-button">Join!</button>
<button id="faction-invitation-box-no" class="popup-box-button">Decide later</button>
</div>
</div>
@ -376,15 +417,11 @@
<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/>
<button id="infiltration-box-sell" class="a-link-button">Sell on Black Market</button>
<br /><br />
<select id="infiltration-faction-select" class="dropdown"></select>
<br/>
<button id="infiltration-box-faction" class="a-link-button">
Give to Faction for Reputation
</button>
<br />
<button id="infiltration-box-faction" class="a-link-button">Give to Faction for Reputation</button>
</div>
</div>
@ -395,9 +432,7 @@
<div id="work-in-progress-container" class="generic-fullscreen-container">
<p id="work-in-progress-text"></p>
<button id="work-in-progress-cancel-button" class="work-button">
Cancel Work
</button>
<button id="work-in-progress-cancel-button" class="work-button">Cancel Work</button>
<button id="work-in-progress-something-else-button" class="work-button">
Do something else simultaneously
</button>
@ -428,12 +463,8 @@
<!-- ReactJS Component -->
</div>
<div class="character-quick-options noselect">
<button id="character-overview-save-button" class="character-overview-btn">
Save Game
</button>
<button id="character-overview-options-button" class="character-overview-btn">
Options
</button>
<button id="character-overview-save-button" class="character-overview-btn">Save Game</button>
<button id="character-overview-options-button" class="character-overview-btn">Options</button>
</div>
</div>
</div>
@ -446,180 +477,251 @@
<!-- Game Options -->
<div id="game-options-container" class="popup-box-container">
<div id="game-options-content" class="game-options-box">
<button id="game-options-close-button" aria-label="close options dialog">
&times;
</button>
<button id="game-options-close-button" aria-label="close options dialog">&times;</button>
<h1>Game Options</h1>
<br/>
<br />
<div id="game-options-left-panel">
<!-- Netscript execution time -->
<fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:&nbsp;
<label for="settingsNSExecTimeRangeVal" class="tooltip"
>Netscript exec time:&nbsp;
<span class="tooltiptext">
The minimum number of milliseconds it takes to execute an
operation in Netscript. Setting this too low can result in
poor performance if you have many scripts running. The default
value is 25ms.
The minimum number of milliseconds it takes to execute an operation in Netscript. Setting this too low
can result in poor performance if you have many scripts running. The default value is 25ms.
</span>
</label>
<input class="optionRange" type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/>
<input
class="optionRange"
type="range"
max="100"
min="10"
step="1"
name="settingsNSExecTimeRangeVal"
id="settingsNSExecTimeRangeVal"
value="25"
/>
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Log capacity -->
<fieldset>
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:&nbsp;&nbsp;
<label for="settingsNSLogRangeVal" class="tooltip"
>Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext">
The maximum number of lines a script's logs can hold. Setting
this too high can cause the game to use a lot of memory if you
have many scripts running. The default value is 50.
The maximum number of lines a script's logs can hold. Setting this too high can cause the game to use
a lot of memory if you have many scripts running. The default value is 50.
</span>
</label>
<input class="optionRange" type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/>
<input
class="optionRange"
type="range"
max="100"
min="20"
step="1"
name="settingsNSLogRangeVal"
id="settingsNSLogRangeVal"
value="50"
/>
<em id="settingsNSLogRangeValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Port capacity -->
<fieldset>
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:&nbsp;
<label for="settingsNSPortRangeVal" class="tooltip"
>Netscript port size:&nbsp;
<span class="tooltiptext">
The maximum number of entries that can be written to a port
using Netscript's write() function. Setting this too high can
cause the game to use a lot of memory. The default value is
50.
The maximum number of entries that can be written to a port using Netscript's write() function.
Setting this too high can cause the game to use a lot of memory. The default value is 50.
</span>
</label>
<input class="optionRange" type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/>
<input
class="optionRange"
type="range"
max="100"
min="20"
step="1"
name="settingsNSPortRangeVal"
id="settingsNSPortRangeVal"
value="50"
/>
<em id="settingsNSPortRangeValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Autosave Interval -->
<fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval:&nbsp;&nbsp;&nbsp;
<label for="settingsAutosaveIntervalVal" class="tooltip"
>Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to
disable autosave.
The time (in seconds) between each autosave. Set to 0 to disable autosave.
</span>
</label>
<input class="optionRange" type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/>
<input
class="optionRange"
type="range"
max="600"
min="0"
step="1"
name="settingsAutosaveIntervalVal"
id="settingsAutosaveIntervalVal"
value="60"
/>
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Suppress messages -->
<fieldset>
<label for="settingsSuppressMessages" class="tooltip">Suppress Messages:
<label for="settingsSuppressMessages" class="tooltip"
>Suppress Messages:
<span class="tooltiptext">
If this is set, then any messages you receive will not appear
as popups on the screen. They will still get sent to your home
computer as '.msg' files and can be viewed with the 'cat'
Terminal command.
If this is set, then any messages you receive will not appear as popups on the screen. They will still
get sent to your home computer as '.msg' files and can be viewed with the 'cat' Terminal command.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressMessages"
id="settingsSuppressMessages"
/>
</fieldset>
<!-- Suppress faction invites -->
<fieldset>
<label for="settingsSuppressFactionInvites" class="tooltip">Suppress Faction Invites:
<label for="settingsSuppressFactionInvites" class="tooltip"
>Suppress Faction Invites:
<span class="tooltiptexthigh">
If this is set, then any faction invites you receive will not
appear as popups on the screen. Your outstanding faction
invites can be viewed in the 'Factions' page.
If this is set, then any faction invites you receive will not appear as popups on the screen. Your
outstanding faction invites can be viewed in the 'Factions' page.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressFactionInvites"
id="settingsSuppressFactionInvites"
/>
</fieldset>
<!-- Suppress travel confirmation -->
<fieldset>
<label for="settingsSuppressTravelConfirmation" class="tooltip">Suppress Travel Confirmation:
<label for="settingsSuppressTravelConfirmation" class="tooltip"
>Suppress Travel Confirmation:
<span class="tooltiptexthigh">
If this is set, the confirmation message before traveling will
not show up. You will automatically be deducted the travel
cost as soon as you click.
If this is set, the confirmation message before traveling will not show up. You will automatically be
deducted the travel cost as soon as you click.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressTravelConfirmation"
id="settingsSuppressTravelConfirmation"
/>
</fieldset>
<!-- Suppress buy aug confirmation -->
<fieldset>
<label for="settingsSuppressBuyAugmentationConfirmation" class="tooltip">Suppress buy augmentation confirmation:
<label for="settingsSuppressBuyAugmentationConfirmation" class="tooltip"
>Suppress buy augmentation confirmation:
<span class="tooltiptexthigh">
If this is set, the confirmation message before buying
augmentation will not show up.
If this is set, the confirmation message before buying augmentation will not show up.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressBuyAugmentationConfirmation"
id="settingsSuppressBuyAugmentationConfirmation"
/>
</fieldset>
<!-- Hospitalization Popup -->
<fieldset>
<label for="settingsSuppressHospitalizationPopup" class="tooltip">Suppress Hospitalization popup:
<label for="settingsSuppressHospitalizationPopup" class="tooltip"
>Suppress Hospitalization popup:
<span class="tooltiptexthigh">
If this is set, a popup message will no longer be shown when
you are hospitalized after taking too much damage.
If this is set, a popup message will no longer be shown when you are hospitalized after taking too
much damage.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressHospitalizationPopup"
id="settingsSuppressHospitalizationPopup"
/>
</fieldset>
<!-- Suppress Bladeburner popups -->
<fieldset>
<label for="settingsSuppressBladeburnerPopup" class="tooltip">Suppress Bladeburner Popup:
<label for="settingsSuppressBladeburnerPopup" class="tooltip"
>Suppress Bladeburner Popup:
<span class="tooltiptext">
If this is set, then having your Bladeburner actions
interrupted by being busy with something else will not display
a popup message.
If this is set, then having your Bladeburner actions interrupted by being busy with something else
will not display a popup message.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressBladeburnerPopup" id="settingsSuppressBladeburnerPopup"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressBladeburnerPopup"
id="settingsSuppressBladeburnerPopup"
/>
</fieldset>
<!-- Disable Terminal and Navigation Shortcuts -->
<fieldset>
<label for="settingsDisableHotkeys" class="tooltip">Disable Hotkeys:
<label for="settingsDisableHotkeys" class="tooltip"
>Disable Hotkeys:
<span class="tooltiptexthigh">
If this is set, then most hotkeys (keyboard shortcuts) in the
game are disabled. This includes Terminal commands, hotkeys to
navigate between different parts of the game, and the "Save
and Close (Ctrl + b)" hotkey in the Text Editor.
If this is set, then most hotkeys (keyboard shortcuts) in the game are disabled. This includes
Terminal commands, hotkeys to navigate between different parts of the game, and the "Save and Close
(Ctrl + b)" hotkey in the Text Editor.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys"/>
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys" />
</fieldset>
<!-- View city as list of buttons instead of ASCII art. -->
<fieldset>
<label for="settingsDisableASCIIArt" class="tooltip">Disable ASCII art:
<span class="tooltiptexthigh">
If this is set all ASCII art will be disabled.
</span>
<label for="settingsDisableASCIIArt" class="tooltip"
>Disable ASCII art:
<span class="tooltiptexthigh"> If this is set all ASCII art will be disabled. </span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsDisableASCIIArt"
id="settingsDisableASCIIArt"
/>
</fieldset>
<!-- Disable text effects such as corruption. -->
<fieldset>
<label for="settingsDisableTextEffects" class="tooltip">Disable Text Effects:
<label for="settingsDisableTextEffects" class="tooltip"
>Disable Text Effects:
<span class="tooltiptexthigh">
If this is set, text effects will not be displayed. This can
help if text is difficult to read in certain areas.
If this is set, text effects will not be displayed. This can help if text is difficult to read in
certain areas.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableTextEffects" id="settingsDisableTextEffects"/>
<input
class="optionCheckbox"
type="checkbox"
name="settingsDisableTextEffects"
id="settingsDisableTextEffects"
/>
</fieldset>
<!-- Locale for displaying numbers -->
<fieldset>
<label for="settingsLocale" class="tooltip">Locale:
<span class="tooltiptexthigh">
Sets the locale for displaying numbers. Defaults to 'en'
</span>
<label for="settingsLocale" class="tooltip"
>Locale:
<span class="tooltiptexthigh"> Sets the locale for displaying numbers. Defaults to 'en' </span>
</label>
<select name="settingsLocale" id="settingsLocale" class="dropdown">
<option value="en">en</option>
@ -642,60 +744,59 @@
<!-- Donate button -->
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick"/>
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYA2Y2VGE75oWct89z//G2YEJKmzx0uDTXNrpje9ThxmUnBLFZCY+I11Pors7lGRvFqo5okwnu41CfYMPHDxpAgyYyQndMX9pWUX0gLfBMm2BaHwsNBCwt34WmpQqj7TGsQ+aw9NbmkxiJltGnOa+6/gy10mPZAA3HxiieLeCKkGgDELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQI72F1YSzHUd2AgaDMekHU3AKT93Ey9wkB3486bV+ngFSD6VOHrPweH9QATsp+PMe9QM9vmq+s2bGtTbZaYrFqM3M97SnQ0l7IQ5yuOzdZhRdfysu5uJ8dnuHUzq4gLSzqMnZ6/3c+PoHB8AS1nYHUVL4U0+ogZsO1s97IAQyfck9SaoFlxVtqQhkb8752MkQJJvGu3ZQSQGcVC4hFDPk8prXqyq4BU/k/EliwoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTcwNzI1MDExODE2WjAjBgkqhkiG9w0BCQQxFgQUNo8efiZ7sk7nwKM/6B6Z7sU8hIIwDQYJKoZIhvcNAQEBBQAEgYB+JB4vZ/r48815/1HF/xK3+rOx7bPz3kAXmbhW/mkoF4OUbzqMeljvDIA9q/BDdlCLtxFOw9XlftTzv0eZCW/uCIiwu5wTzPIfPY1SI8WHe4cJbP2f2EYxIVs8D7OSirbW4yVa0+gACaLLj0rzIzNN8P/5PxgB03D+jwkcJABqng==-----END PKCS7-----
"/>
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"/>
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1"/>
<input type="hidden" name="cmd" value="_s-xclick" />
<input
type="hidden"
name="encrypted"
value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYA2Y2VGE75oWct89z//G2YEJKmzx0uDTXNrpje9ThxmUnBLFZCY+I11Pors7lGRvFqo5okwnu41CfYMPHDxpAgyYyQndMX9pWUX0gLfBMm2BaHwsNBCwt34WmpQqj7TGsQ+aw9NbmkxiJltGnOa+6/gy10mPZAA3HxiieLeCKkGgDELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQI72F1YSzHUd2AgaDMekHU3AKT93Ey9wkB3486bV+ngFSD6VOHrPweH9QATsp+PMe9QM9vmq+s2bGtTbZaYrFqM3M97SnQ0l7IQ5yuOzdZhRdfysu5uJ8dnuHUzq4gLSzqMnZ6/3c+PoHB8AS1nYHUVL4U0+ogZsO1s97IAQyfck9SaoFlxVtqQhkb8752MkQJJvGu3ZQSQGcVC4hFDPk8prXqyq4BU/k/EliwoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTcwNzI1MDExODE2WjAjBgkqhkiG9w0BCQQxFgQUNo8efiZ7sk7nwKM/6B6Z7sU8hIIwDQYJKoZIhvcNAQEBBQAEgYB+JB4vZ/r48815/1HF/xK3+rOx7bPz3kAXmbhW/mkoF4OUbzqMeljvDIA9q/BDdlCLtxFOw9XlftTzv0eZCW/uCIiwu5wTzPIfPY1SI8WHe4cJbP2f2EYxIVs8D7OSirbW4yVa0+gACaLLj0rzIzNN8P/5PxgB03D+jwkcJABqng==-----END PKCS7-----
"
/>
<input
type="image"
src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif"
border="0"
name="submit"
alt="PayPal - The safer, easier way to pay online!"
/>
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form>
</div>
<div id="game-options-right-panel">
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank">
Changelog
</a>
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a>
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank"
>Documentation</a
>
<a class="a-link-button" href="https://discord.gg/TFc3hKD" target="_blank">Discord</a>
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
<button id="save-game-link" class="a-link-button">Save Game</button>
<button id="delete-game-link" class="a-link-button">
Delete Game
</button>
<button id="export-game-link" class="a-link-button">
Export Game
</button>
<input type="file" id="import-game-file-selector" name="file"/>
<button id="import-game-link" class="a-link-button">
Import Game
</button>
<button id="copy-save-to-clipboard-link" class="std-button">
Copy Save data to Clipboard
</button>
<button id="delete-game-link" class="a-link-button">Delete Game</button>
<button id="export-game-link" class="a-link-button">Export Game</button>
<input type="file" id="import-game-file-selector" name="file" />
<button id="import-game-link" class="a-link-button">Import Game</button>
<button id="copy-save-to-clipboard-link" class="std-button">Copy Save data to Clipboard</button>
<button id="debug-delete-scripts-link" class="a-link-button tooltip">
Force kill all active scripts
<span class="tooltiptextleft">
Forcefully kill all active running scripts, in case there is a
bug or some unexpected issue with the game. After using this,
save the game and then reload the page. This is different then
normal kill in that normal kill will tell the script to shut
down while force kill just removes the references to it (and it
should crash on it's own). This will not remove the files on
your computer. Just forcefully kill all running instance of all
scripts.
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the
game. After using this, save the game and then reload the page. This is different then normal kill in
that normal kill will tell the script to shut down while force kill just removes the references to it
(and it should crash on it's own). This will not remove the files on your computer. Just forcefully kill
all running instance of all scripts.
</span>
</button>
<button id="debug-soft-reset" class="a-link-button tooltip">
Soft Reset
<span class="tooltiptextleft">
Perform a soft reset. Resets everything as if you had just
purchased an Augmentation.
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
</span>
</button>
<button id="debug-files" class="a-link-button tooltip">
Diagnose files
<span class="tooltiptextleft">
If your save file is extremely big you can use this button to
view a map of all the files on every server. Be careful there
might be spoilers.
If your save file is extremely big you can use this button to view a map of all the files on every
server. Be careful there might be spoilers.
</span>
</button>
</div>
@ -725,10 +826,11 @@
</div>
</div>
<div id="unclickable" style="display: none">
Click on this to upgrade your Source-File -1!
</div>
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="dist/engine.bundle.js"></script><script type="text/javascript" src="dist/engineStyle.bundle.js"></script></body>
<div id="unclickable" style="display: none">Click on this to upgrade your Source-File -1!</div>
<script type="text/javascript" src="dist/vendor.bundle.js"></script>
<script type="text/javascript" src="dist/engine.bundle.js"></script>
<script type="text/javascript" src="dist/engineStyle.bundle.js"></script>
</body>
<!-- Misc Scripts -->
<script src="src/ThirdParty/raphael.min.js"></script>

@ -2,433 +2,366 @@ const numSpaces = 4;
const maxLineLength = 160;
module.exports = {
"env": {
"es6": true,
"node": true
env: {
es6: true,
node: true,
},
extends: "eslint:recommended",
parserOptions: {
ecmaFeatures: {
experimentalObjectRestSpread: true,
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
},
"ecmaVersion": 8,
"sourceType": "module"
},
"rules": {
"accessor-pairs": [
"error",
{
"getWithoutSet": false,
"setWithoutGet": true
}
],
"array-bracket-newline": ["error"],
"array-bracket-spacing": ["error"],
"array-callback-return": ["error"],
"array-element-newline": ["error"],
"arrow-body-style": ["error"],
"arrow-parens": ["error"],
"arrow-spacing": ["error"],
"block-scoped-var": ["error"],
"block-spacing": ["error"],
"brace-style": ["error"],
"callback-return": ["error"],
"camelcase": ["error"],
"capitalized-comments": ["error"],
"class-methods-use-this": ["error"],
"comma-dangle": ["error"],
"comma-spacing": ["error"],
"comma-style": [
"error",
"last"
],
"complexity": ["error"],
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": ["error"],
"consistent-this": ["error"],
"constructor-super": ["error"],
"curly": ["error"],
"default-case": ["error"],
"dot-location": [
"error",
"property"
],
"dot-notation": ["error"],
"eol-last": ["error"],
"eqeqeq": ["error"],
"for-direction": ["error"],
"func-call-spacing": ["error"],
"func-name-matching": ["error"],
"func-names": [
"error",
"never"
],
"func-style": ["error"],
"function-paren-newline": ["error"],
"generator-star-spacing": [
"error",
"before"
],
"getter-return": [
"error",
{
"allowImplicit": false
}
],
"global-require": ["error"],
"guard-for-in": ["error"],
"handle-callback-err": ["error"],
"id-blacklist": ["error"],
"id-length": ["error"],
"id-match": ["error"],
"implicit-arrow-linebreak": [
"error",
"beside"
],
"indent": [
"error",
numSpaces,
{
"SwitchCase": 1
}
],
"init-declarations": ["error"],
"jsx-quotes": ["error"],
"key-spacing": ["error"],
"keyword-spacing": ["error"],
"line-comment-position": ["error"],
"linebreak-style": [
"error",
"windows"
],
"lines-around-comment": ["error"],
"lines-between-class-members": ["error"],
"max-depth": ["error"],
"max-len": [
"error",
maxLineLength
],
"max-lines": [
"error",
{
"skipBlankLines": true,
"skipComments": true
}
],
"max-nested-callbacks": ["error"],
"max-params": ["error"],
"max-statements": ["error"],
"max-statements-per-line": ["error"],
"multiline-comment-style": [
"off",
"starred-block"
],
"multiline-ternary": [
"error",
"never"
],
"new-cap": ["error"],
"new-parens": ["error"],
// TODO: configure this...
"newline-before-return": ["error"],
"newline-per-chained-call": ["error"],
"no-alert": ["error"],
"no-array-constructor": ["error"],
"no-await-in-loop": ["error"],
"no-bitwise": ["error"],
"no-buffer-constructor": ["error"],
"no-caller": ["error"],
"no-case-declarations": ["error"],
"no-catch-shadow": ["error"],
"no-class-assign": ["error"],
"no-compare-neg-zero": ["error"],
"no-cond-assign": [
"error",
"except-parens"
],
"no-confusing-arrow": ["error"],
"no-console": ["error"],
"no-const-assign": ["error"],
"no-constant-condition": [
"error",
{
"checkLoops": false
}
],
"no-continue": ["off"],
"no-control-regex": ["error"],
"no-debugger": ["error"],
"no-delete-var": ["error"],
"no-div-regex": ["error"],
"no-dupe-args": ["error"],
"no-dupe-class-members": ["error"],
"no-dupe-keys": ["error"],
"no-duplicate-case": ["error"],
"no-duplicate-imports": [
"error",
{
"includeExports": true
}
],
"no-else-return": ["error"],
"no-empty": [
"error",
{
"allowEmptyCatch": false
}
],
"no-empty-character-class": ["error"],
"no-empty-function": ["error"],
"no-empty-pattern": ["error"],
"no-eq-null": ["error"],
"no-eval": ["error"],
"no-ex-assign": ["error"],
"no-extend-native": ["error"],
"no-extra-bind": ["error"],
"no-extra-boolean-cast": ["error"],
"no-extra-label": ["error"],
"no-extra-parens": [
"error",
"all",
{
"conditionalAssign": false
}
],
"no-extra-semi": ["error"],
"no-fallthrough": ["error"],
"no-floating-decimal": ["error"],
"no-func-assign": ["error"],
"no-global-assign": ["error"],
"no-implicit-coercion": ["error"],
"no-implicit-globals": ["error"],
"no-implied-eval": ["error"],
"no-inline-comments": ["error"],
"no-inner-declarations": [
"error",
"both"
],
"no-invalid-regexp": ["error"],
"no-invalid-this": ["error"],
"no-irregular-whitespace": [
"error",
{
"skipComments": false,
"skipRegExps": false,
"skipStrings": false,
"skipTemplates": false
}
],
"no-iterator": ["error"],
"no-label-var": ["error"],
"no-labels": ["error"],
"no-lone-blocks": ["error"],
"no-lonely-if": ["error"],
"no-loop-func": ["error"],
"no-magic-numbers": [
"error",
{
"ignore": [
-1,
0,
1
],
"ignoreArrayIndexes": true
}
],
"no-mixed-operators": ["error"],
"no-mixed-requires": ["error"],
"no-mixed-spaces-and-tabs": ["error"],
"no-multi-assign": ["error"],
"no-multi-spaces": ["error"],
"no-multi-str": ["error"],
"no-multiple-empty-lines": [
"error",
{
"max": 1
}
],
"no-native-reassign": ["error"],
"no-negated-condition": ["error"],
"no-negated-in-lhs": ["error"],
"no-nested-ternary": ["error"],
"no-new": ["error"],
"no-new-func": ["error"],
"no-new-object": ["error"],
"no-new-require": ["error"],
"no-new-symbol": ["error"],
"no-new-wrappers": ["error"],
"no-obj-calls": ["error"],
"no-octal": ["error"],
"no-octal-escape": ["error"],
"no-param-reassign": ["error"],
"no-path-concat": ["error"],
"no-plusplus": [
"error",
{
"allowForLoopAfterthoughts": true
}
],
"no-process-env": ["error"],
"no-process-exit": ["error"],
"no-proto": ["error"],
"no-prototype-builtins": ["error"],
"no-redeclare": ["error"],
"no-regex-spaces": ["error"],
"no-restricted-globals": ["error"],
"no-restricted-imports": ["error"],
"no-restricted-modules": ["error"],
"no-restricted-properties": [
"error",
{
"message": "'log' is too general, use an appropriate level when logging.",
"object": "console",
"property": "log"
}
],
"no-restricted-syntax": ["error"],
"no-return-assign": ["error"],
"no-return-await": ["error"],
"no-script-url": ["error"],
"no-self-assign": [
"error",
{
"props": false
}
],
"no-self-compare": ["error"],
"no-sequences": ["error"],
"no-shadow": ["error"],
"no-shadow-restricted-names": ["error"],
"no-spaced-func": ["error"],
"no-sparse-arrays": ["error"],
"no-sync": ["error"],
"no-tabs": ["error"],
"no-template-curly-in-string": ["error"],
"no-ternary": ["off"],
"no-this-before-super": ["error"],
"no-throw-literal": ["error"],
"no-trailing-spaces": ["error"],
"no-undef": ["error"],
"no-undef-init": ["error"],
"no-undefined": ["error"],
"no-underscore-dangle": ["error"],
"no-unexpected-multiline": ["error"],
"no-unmodified-loop-condition": ["error"],
"no-unneeded-ternary": ["error"],
"no-unreachable": ["error"],
"no-unsafe-finally": ["error"],
"no-unsafe-negation": ["error"],
"no-unused-expressions": ["error"],
"no-unused-labels": ["error"],
"no-unused-vars": ["error"],
"no-use-before-define": ["error"],
"no-useless-call": ["error"],
"no-useless-computed-key": ["error"],
"no-useless-concat": ["error"],
"no-useless-constructor": ["error"],
"no-useless-escape": ["error"],
"no-useless-rename": [
"error",
{
"ignoreDestructuring": false,
"ignoreExport": false,
"ignoreImport": false
}
],
"no-useless-return": ["error"],
"no-var": ["error"],
"no-void": ["error"],
"no-warning-comments": ["error"],
"no-whitespace-before-property": ["error"],
"no-with": ["error"],
"nonblock-statement-body-position": [
"error",
"below"
],
"object-curly-newline": ["error"],
"object-curly-spacing": ["error"],
"object-property-newline": ["error"],
"object-shorthand": ["error"],
"one-var": ["off"],
"one-var-declaration-per-line": ["error"],
"operator-assignment": ["error"],
"operator-linebreak": [
"error",
"none"
],
"padded-blocks": ["off"],
"padding-line-between-statements": ["error"],
"prefer-arrow-callback": ["error"],
"prefer-const": ["error"],
"prefer-destructuring": ["off"],
"prefer-numeric-literals": ["error"],
"prefer-promise-reject-errors": ["off"],
"prefer-reflect": ["error"],
"prefer-rest-params": ["error"],
"prefer-spread": ["error"],
"prefer-template": ["error"],
"quote-props": ["error"],
"quotes": ["error"],
"radix": [
"error",
"as-needed"
],
"require-await": ["error"],
"require-jsdoc": ["off"],
"require-yield": ["error"],
"rest-spread-spacing": [
"error",
"never"
],
"semi": ["error"],
"semi-spacing": ["error"],
"semi-style": [
"error",
"last"
],
"sort-imports": ["error"],
"sort-keys": ["error"],
"sort-vars": ["error"],
"space-before-blocks": ["error"],
"space-before-function-paren": ["off"],
"space-in-parens": ["error"],
"space-infix-ops": ["error"],
"space-unary-ops": ["error"],
"spaced-comment": ["error"],
"strict": ["error"],
"switch-colon-spacing": [
"error",
{
"after": true,
"before": false
}
],
"symbol-description": ["error"],
"template-curly-spacing": ["error"],
"template-tag-spacing": ["error"],
"unicode-bom": [
"error",
"never"
],
"use-isnan": ["error"],
"valid-jsdoc": ["error"],
"valid-typeof": ["error"],
"vars-on-top": ["error"],
"wrap-iife": [
"error",
"any"
],
"wrap-regex": ["error"],
"yield-star-spacing": [
"error",
"before"
],
"yoda": [
"error",
"never"
]
}
ecmaVersion: 8,
sourceType: "module",
},
rules: {
"accessor-pairs": [
"error",
{
getWithoutSet: false,
setWithoutGet: true,
},
],
"array-bracket-newline": ["error"],
"array-bracket-spacing": ["error"],
"array-callback-return": ["error"],
"array-element-newline": ["error"],
"arrow-body-style": ["error"],
"arrow-parens": ["error"],
"arrow-spacing": ["error"],
"block-scoped-var": ["error"],
"block-spacing": ["error"],
"brace-style": ["error"],
"callback-return": ["error"],
camelcase: ["error"],
"capitalized-comments": ["error"],
"class-methods-use-this": ["error"],
"comma-dangle": ["error"],
"comma-spacing": ["error"],
"comma-style": ["error", "last"],
complexity: ["error"],
"computed-property-spacing": ["error", "never"],
"consistent-return": ["error"],
"consistent-this": ["error"],
"constructor-super": ["error"],
curly: ["error"],
"default-case": ["error"],
"dot-location": ["error", "property"],
"dot-notation": ["error"],
"eol-last": ["error"],
eqeqeq: ["error"],
"for-direction": ["error"],
"func-call-spacing": ["error"],
"func-name-matching": ["error"],
"func-names": ["error", "never"],
"func-style": ["error"],
"function-paren-newline": ["error"],
"generator-star-spacing": ["error", "before"],
"getter-return": [
"error",
{
allowImplicit: false,
},
],
"global-require": ["error"],
"guard-for-in": ["error"],
"handle-callback-err": ["error"],
"id-blacklist": ["error"],
"id-length": ["error"],
"id-match": ["error"],
"implicit-arrow-linebreak": ["error", "beside"],
indent: [
"error",
numSpaces,
{
SwitchCase: 1,
},
],
"init-declarations": ["error"],
"jsx-quotes": ["error"],
"key-spacing": ["error"],
"keyword-spacing": ["error"],
"line-comment-position": ["error"],
"linebreak-style": ["error", "windows"],
"lines-around-comment": ["error"],
"lines-between-class-members": ["error"],
"max-depth": ["error"],
"max-len": ["error", maxLineLength],
"max-lines": [
"error",
{
skipBlankLines: true,
skipComments: true,
},
],
"max-nested-callbacks": ["error"],
"max-params": ["error"],
"max-statements": ["error"],
"max-statements-per-line": ["error"],
"multiline-comment-style": ["off", "starred-block"],
"multiline-ternary": ["error", "never"],
"new-cap": ["error"],
"new-parens": ["error"],
// TODO: configure this...
"newline-before-return": ["error"],
"newline-per-chained-call": ["error"],
"no-alert": ["error"],
"no-array-constructor": ["error"],
"no-await-in-loop": ["error"],
"no-bitwise": ["error"],
"no-buffer-constructor": ["error"],
"no-caller": ["error"],
"no-case-declarations": ["error"],
"no-catch-shadow": ["error"],
"no-class-assign": ["error"],
"no-compare-neg-zero": ["error"],
"no-cond-assign": ["error", "except-parens"],
"no-confusing-arrow": ["error"],
"no-console": ["error"],
"no-const-assign": ["error"],
"no-constant-condition": [
"error",
{
checkLoops: false,
},
],
"no-continue": ["off"],
"no-control-regex": ["error"],
"no-debugger": ["error"],
"no-delete-var": ["error"],
"no-div-regex": ["error"],
"no-dupe-args": ["error"],
"no-dupe-class-members": ["error"],
"no-dupe-keys": ["error"],
"no-duplicate-case": ["error"],
"no-duplicate-imports": [
"error",
{
includeExports: true,
},
],
"no-else-return": ["error"],
"no-empty": [
"error",
{
allowEmptyCatch: false,
},
],
"no-empty-character-class": ["error"],
"no-empty-function": ["error"],
"no-empty-pattern": ["error"],
"no-eq-null": ["error"],
"no-eval": ["error"],
"no-ex-assign": ["error"],
"no-extend-native": ["error"],
"no-extra-bind": ["error"],
"no-extra-boolean-cast": ["error"],
"no-extra-label": ["error"],
"no-extra-parens": [
"error",
"all",
{
conditionalAssign: false,
},
],
"no-extra-semi": ["error"],
"no-fallthrough": ["error"],
"no-floating-decimal": ["error"],
"no-func-assign": ["error"],
"no-global-assign": ["error"],
"no-implicit-coercion": ["error"],
"no-implicit-globals": ["error"],
"no-implied-eval": ["error"],
"no-inline-comments": ["error"],
"no-inner-declarations": ["error", "both"],
"no-invalid-regexp": ["error"],
"no-invalid-this": ["error"],
"no-irregular-whitespace": [
"error",
{
skipComments: false,
skipRegExps: false,
skipStrings: false,
skipTemplates: false,
},
],
"no-iterator": ["error"],
"no-label-var": ["error"],
"no-labels": ["error"],
"no-lone-blocks": ["error"],
"no-lonely-if": ["error"],
"no-loop-func": ["error"],
"no-magic-numbers": [
"error",
{
ignore: [-1, 0, 1],
ignoreArrayIndexes: true,
},
],
"no-mixed-operators": ["error"],
"no-mixed-requires": ["error"],
"no-mixed-spaces-and-tabs": ["error"],
"no-multi-assign": ["error"],
"no-multi-spaces": ["error"],
"no-multi-str": ["error"],
"no-multiple-empty-lines": [
"error",
{
max: 1,
},
],
"no-native-reassign": ["error"],
"no-negated-condition": ["error"],
"no-negated-in-lhs": ["error"],
"no-nested-ternary": ["error"],
"no-new": ["error"],
"no-new-func": ["error"],
"no-new-object": ["error"],
"no-new-require": ["error"],
"no-new-symbol": ["error"],
"no-new-wrappers": ["error"],
"no-obj-calls": ["error"],
"no-octal": ["error"],
"no-octal-escape": ["error"],
"no-param-reassign": ["error"],
"no-path-concat": ["error"],
"no-plusplus": [
"error",
{
allowForLoopAfterthoughts: true,
},
],
"no-process-env": ["error"],
"no-process-exit": ["error"],
"no-proto": ["error"],
"no-prototype-builtins": ["error"],
"no-redeclare": ["error"],
"no-regex-spaces": ["error"],
"no-restricted-globals": ["error"],
"no-restricted-imports": ["error"],
"no-restricted-modules": ["error"],
"no-restricted-properties": [
"error",
{
message: "'log' is too general, use an appropriate level when logging.",
object: "console",
property: "log",
},
],
"no-restricted-syntax": ["error"],
"no-return-assign": ["error"],
"no-return-await": ["error"],
"no-script-url": ["error"],
"no-self-assign": [
"error",
{
props: false,
},
],
"no-self-compare": ["error"],
"no-sequences": ["error"],
"no-shadow": ["error"],
"no-shadow-restricted-names": ["error"],
"no-spaced-func": ["error"],
"no-sparse-arrays": ["error"],
"no-sync": ["error"],
"no-tabs": ["error"],
"no-template-curly-in-string": ["error"],
"no-ternary": ["off"],
"no-this-before-super": ["error"],
"no-throw-literal": ["error"],
"no-trailing-spaces": ["error"],
"no-undef": ["error"],
"no-undef-init": ["error"],
"no-undefined": ["error"],
"no-underscore-dangle": ["error"],
"no-unexpected-multiline": ["error"],
"no-unmodified-loop-condition": ["error"],
"no-unneeded-ternary": ["error"],
"no-unreachable": ["error"],
"no-unsafe-finally": ["error"],
"no-unsafe-negation": ["error"],
"no-unused-expressions": ["error"],
"no-unused-labels": ["error"],
"no-unused-vars": ["error"],
"no-use-before-define": ["error"],
"no-useless-call": ["error"],
"no-useless-computed-key": ["error"],
"no-useless-concat": ["error"],
"no-useless-constructor": ["error"],
"no-useless-escape": ["error"],
"no-useless-rename": [
"error",
{
ignoreDestructuring: false,
ignoreExport: false,
ignoreImport: false,
},
],
"no-useless-return": ["error"],
"no-var": ["error"],
"no-void": ["error"],
"no-warning-comments": ["error"],
"no-whitespace-before-property": ["error"],
"no-with": ["error"],
"nonblock-statement-body-position": ["error", "below"],
"object-curly-newline": ["error"],
"object-curly-spacing": ["error"],
"object-property-newline": ["error"],
"object-shorthand": ["error"],
"one-var": ["off"],
"one-var-declaration-per-line": ["error"],
"operator-assignment": ["error"],
"operator-linebreak": ["error", "none"],
"padded-blocks": ["off"],
"padding-line-between-statements": ["error"],
"prefer-arrow-callback": ["error"],
"prefer-const": ["error"],
"prefer-destructuring": ["off"],
"prefer-numeric-literals": ["error"],
"prefer-promise-reject-errors": ["off"],
"prefer-reflect": ["error"],
"prefer-rest-params": ["error"],
"prefer-spread": ["error"],
"prefer-template": ["error"],
"quote-props": ["error"],
quotes: ["error"],
radix: ["error", "as-needed"],
"require-await": ["error"],
"require-jsdoc": ["off"],
"require-yield": ["error"],
"rest-spread-spacing": ["error", "never"],
semi: ["error"],
"semi-spacing": ["error"],
"semi-style": ["error", "last"],
"sort-imports": ["error"],
"sort-keys": ["error"],
"sort-vars": ["error"],
"space-before-blocks": ["error"],
"space-before-function-paren": ["off"],
"space-in-parens": ["error"],
"space-infix-ops": ["error"],
"space-unary-ops": ["error"],
"spaced-comment": ["error"],
strict: ["error"],
"switch-colon-spacing": [
"error",
{
after: true,
before: false,
},
],
"symbol-description": ["error"],
"template-curly-spacing": ["error"],
"template-tag-spacing": ["error"],
"unicode-bom": ["error", "never"],
"use-isnan": ["error"],
"valid-jsdoc": ["error"],
"valid-typeof": ["error"],
"vars-on-top": ["error"],
"wrap-iife": ["error", "any"],
"wrap-regex": ["error"],
"yield-star-spacing": ["error", "before"],
yoda: ["error", "never"],
},
};

@ -8,66 +8,74 @@ const path = require("path");
const exec = require("child_process").exec;
const semver = require("./semver");
const getPackageJson = () => new Promise((resolve, reject) => {
const getPackageJson = () =>
new Promise((resolve, reject) => {
try {
/* eslint-disable-next-line global-require */
resolve(require(path.resolve(process.cwd(), "package.json")));
/* eslint-disable-next-line global-require */
resolve(require(path.resolve(process.cwd(), "package.json")));
} catch (error) {
reject(error);
reject(error);
}
});
});
const getEngines = (data) => new Promise((resolve, reject) => {
const getEngines = (data) =>
new Promise((resolve, reject) => {
let versions = null;
if (data.engines) {
versions = data.engines;
versions = data.engines;
}
if (versions) {
resolve(versions);
resolve(versions);
} else {
reject("Missing or improper 'engines' property in 'package.json'");
reject("Missing or improper 'engines' property in 'package.json'");
}
});
});
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
const checkNpmVersion = (engines) =>
new Promise((resolve, reject) => {
exec("npm -v", (error, stdout, stderr) => {
if (error) {
reject(`Unable to find NPM version\n${stderr}`);
}
if (error) {
reject(`Unable to find NPM version\n${stderr}`);
}
const npmVersion = stdout.trim();
const engineVersion = engines.npm || ">=0";
const npmVersion = stdout.trim();
const engineVersion = engines.npm || ">=0";
if (semver.satisfies(npmVersion, engineVersion)) {
resolve();
} else {
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
}
if (semver.satisfies(npmVersion, engineVersion)) {
resolve();
} else {
reject(
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
);
}
});
});
});
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
const checkNodeVersion = (engines) =>
new Promise((resolve, reject) => {
const nodeVersion = process.version.substring(1);
if (semver.satisfies(nodeVersion, engines.node)) {
resolve(engines);
resolve(engines);
} else {
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
reject(
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
);
}
});
});
getPackageJson()
.then(getEngines)
.then(checkNodeVersion)
.then(checkNpmVersion)
.then(
() => true,
(error) => {
// Specifically disable these as the error message gets lost in the normal unhandled output.
/* eslint-disable no-console, no-process-exit */
console.error(error);
process.exit(1);
}
);
.then(getEngines)
.then(checkNodeVersion)
.then(checkNpmVersion)
.then(
() => true,
(error) => {
// Specifically disable these as the error message gets lost in the normal unhandled output.
/* eslint-disable no-console, no-process-exit */
console.error(error);
process.exit(1);
},
);

File diff suppressed because it is too large Load Diff

@ -8,11 +8,7 @@ import { Factions } from "../Faction/Factions";
import { numeralWrapper } from "../ui/numeralFormat";
import { Money } from "../ui/React/Money";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
interface IConstructorParams {
info: string | JSX.Element;
@ -58,11 +54,7 @@ interface IConstructorParams {
programs?: string[];
}
function generateStatsDescription(
mults: IMap<number>,
programs?: string[],
startingMoney?: number,
): JSX.Element {
function generateStatsDescription(mults: IMap<number>, programs?: string[], startingMoney?: number): JSX.Element {
const f = (x: number, decimals = 0): string => {
// look, I don't know how to make a "smart decimals"
// todo, make it smarter
@ -224,8 +216,7 @@ function generateStatsDescription(
desc = (
<>
{desc}
<br />+{f(mults.hacking_speed_mult - 1)} faster hack(), grow(), and
weaken()
<br />+{f(mults.hacking_speed_mult - 1)} faster hack(), grow(), and weaken()
</>
);
if (mults.hacking_chance_mult)
@ -250,15 +241,11 @@ function generateStatsDescription(
</>
);
if (
mults.faction_rep_mult &&
mults.faction_rep_mult === mults.company_rep_mult
) {
if (mults.faction_rep_mult && mults.faction_rep_mult === mults.company_rep_mult) {
desc = (
<>
{desc}
<br />+{f(mults.faction_rep_mult - 1)} reputation from factions and
companies
<br />+{f(mults.faction_rep_mult - 1)} reputation from factions and companies
</>
);
} else {
@ -311,16 +298,14 @@ function generateStatsDescription(
desc = (
<>
{desc}
<br />-{f(-(mults.hacknet_node_purchase_cost_mult - 1))} hacknet nodes
cost
<br />-{f(-(mults.hacknet_node_purchase_cost_mult - 1))} hacknet nodes cost
</>
);
if (mults.hacknet_node_level_cost_mult)
desc = (
<>
{desc}
<br />-{f(-(mults.hacknet_node_level_cost_mult - 1))} hacknet nodes
upgrade cost
<br />-{f(-(mults.hacknet_node_level_cost_mult - 1))} hacknet nodes upgrade cost
</>
);
@ -328,32 +313,28 @@ function generateStatsDescription(
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_max_stamina_mult - 1)} Bladeburner Max
Stamina
<br />+{f(mults.bladeburner_max_stamina_mult - 1)} Bladeburner Max Stamina
</>
);
if (mults.bladeburner_stamina_gain_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_stamina_gain_mult - 1)} Bladeburner Stamina
gain
<br />+{f(mults.bladeburner_stamina_gain_mult - 1)} Bladeburner Stamina gain
</>
);
if (mults.bladeburner_analysis_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_analysis_mult - 1)} Bladeburner Field
Analysis effectiveness
<br />+{f(mults.bladeburner_analysis_mult - 1)} Bladeburner Field Analysis effectiveness
</>
);
if (mults.bladeburner_success_chance_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_success_chance_mult - 1)} Bladeburner
Contracts and Operations success chance
<br />+{f(mults.bladeburner_success_chance_mult - 1)} Bladeburner Contracts and Operations success chance
</>
);
@ -362,8 +343,7 @@ function generateStatsDescription(
<>
{desc}
<br />
Start with <Money money={startingMoney} /> after installing
Augmentations.
Start with <Money money={startingMoney} /> after installing Augmentations.
</>
);
@ -425,8 +405,7 @@ export class Augmentation {
this.info = params.info;
this.prereqs = params.prereqs ? params.prereqs : [];
this.baseRepRequirement =
params.repCost * BitNodeMultipliers.AugmentationRepCost;
this.baseRepRequirement = params.repCost * BitNodeMultipliers.AugmentationRepCost;
this.baseCost = params.moneyCost * BitNodeMultipliers.AugmentationMoneyCost;
this.startingCost = this.baseCost;
@ -504,43 +483,32 @@ export class Augmentation {
this.mults.hacknet_node_money_mult = params.hacknet_node_money_mult;
}
if (params.hacknet_node_purchase_cost_mult) {
this.mults.hacknet_node_purchase_cost_mult =
params.hacknet_node_purchase_cost_mult;
this.mults.hacknet_node_purchase_cost_mult = params.hacknet_node_purchase_cost_mult;
}
if (params.hacknet_node_ram_cost_mult) {
this.mults.hacknet_node_ram_cost_mult = params.hacknet_node_ram_cost_mult;
}
if (params.hacknet_node_core_cost_mult) {
this.mults.hacknet_node_core_cost_mult =
params.hacknet_node_core_cost_mult;
this.mults.hacknet_node_core_cost_mult = params.hacknet_node_core_cost_mult;
}
if (params.hacknet_node_level_cost_mult) {
this.mults.hacknet_node_level_cost_mult =
params.hacknet_node_level_cost_mult;
this.mults.hacknet_node_level_cost_mult = params.hacknet_node_level_cost_mult;
}
if (params.bladeburner_max_stamina_mult) {
this.mults.bladeburner_max_stamina_mult =
params.bladeburner_max_stamina_mult;
this.mults.bladeburner_max_stamina_mult = params.bladeburner_max_stamina_mult;
}
if (params.bladeburner_stamina_gain_mult) {
this.mults.bladeburner_stamina_gain_mult =
params.bladeburner_stamina_gain_mult;
this.mults.bladeburner_stamina_gain_mult = params.bladeburner_stamina_gain_mult;
}
if (params.bladeburner_analysis_mult) {
this.mults.bladeburner_analysis_mult = params.bladeburner_analysis_mult;
}
if (params.bladeburner_success_chance_mult) {
this.mults.bladeburner_success_chance_mult =
params.bladeburner_success_chance_mult;
this.mults.bladeburner_success_chance_mult = params.bladeburner_success_chance_mult;
}
if (params.stats) this.stats = params.stats;
else
this.stats = generateStatsDescription(
this.mults,
params.programs,
params.startingMoney,
);
else this.stats = generateStatsDescription(this.mults, params.programs, params.startingMoney);
}
// Adds this Augmentation to the specified Factions
@ -548,9 +516,7 @@ export class Augmentation {
for (let i = 0; i < factionList.length; ++i) {
const faction: Faction | null = Factions[factionList[i]];
if (faction == null) {
console.warn(
`In Augmentation.addToFactions(), could not find faction with this name: ${factionList[i]}`,
);
console.warn(`In Augmentation.addToFactions(), could not find faction with this name: ${factionList[i]}`);
continue;
}
faction.augmentations.push(this.name);
@ -563,9 +529,7 @@ export class Augmentation {
if (Factions.hasOwnProperty(fac)) {
const facObj: Faction | null = Factions[fac];
if (facObj == null) {
console.warn(
`Invalid Faction object in addToAllFactions(). Key value: ${fac}`,
);
console.warn(`Invalid Faction object in addToAllFactions(). Key value: ${fac}`);
continue;
}
facObj.augmentations.push(this.name);

@ -141,9 +141,7 @@ function initAugmentations() {
Object.keys(randomBonuses.bonuses).forEach(
(key) => (UnstableCircadianModulatorParams[key] = randomBonuses.bonuses[key]),
);
const UnstableCircadianModulator = new Augmentation(
UnstableCircadianModulatorParams,
);
const UnstableCircadianModulator = new Augmentation(UnstableCircadianModulatorParams);
UnstableCircadianModulator.addToFactions(["Speakers for the Dead"]);
if (augmentationExists(AugmentationNames.UnstableCircadianModulator)) {
@ -156,9 +154,7 @@ function initAugmentations() {
name: AugmentationNames.HemoRecirculator,
moneyCost: 4.5e7,
repCost: 1e4,
info:
"A heart implant that greatly increases the body's ability to effectively use and pump " +
"blood.",
info: "A heart implant that greatly increases the body's ability to effectively use and pump " + "blood.",
strength_mult: 1.08,
defense_mult: 1.08,
agility_mult: 1.08,
@ -221,9 +217,7 @@ function initAugmentations() {
name: AugmentationNames.Targeting3,
moneyCost: 1.15e8,
repCost: 2.75e4,
info:
"The latest version of the 'Augmented Targeting' implant adds the ability to " +
"lock-on and track threats.",
info: "The latest version of the 'Augmented Targeting' implant adds the ability to " + "lock-on and track threats.",
prereqs: [AugmentationNames.Targeting2],
dexterity_mult: 1.3,
});
@ -442,15 +436,11 @@ function initAugmentations() {
repCost: 1.125e6,
moneyCost: 4.25e9,
info:
"Graphene is grafted and fused into the skeletal structure, " +
"enhancing bone density and tensile strength.",
"Graphene is grafted and fused into the skeletal structure, " + "enhancing bone density and tensile strength.",
strength_mult: 1.7,
defense_mult: 1.7,
});
GrapheneBoneLacings.addToFactions([
"Fulcrum Secret Technologies",
"The Covenant",
]);
GrapheneBoneLacings.addToFactions(["Fulcrum Secret Technologies", "The Covenant"]);
if (augmentationExists(AugmentationNames.GrapheneBoneLacings)) {
delete Augmentations[AugmentationNames.GrapheneBoneLacings];
}
@ -530,11 +520,7 @@ function initAugmentations() {
prereqs: [AugmentationNames.BionicLegs],
agility_mult: 2.5,
});
GrapheneBionicLegs.addToFactions([
"MegaCorp",
"ECorp",
"Fulcrum Secret Technologies",
]);
GrapheneBionicLegs.addToFactions(["MegaCorp", "ECorp", "Fulcrum Secret Technologies"]);
if (augmentationExists(AugmentationNames.GrapheneBionicLegs)) {
delete Augmentations[AugmentationNames.GrapheneBionicLegs];
}
@ -638,10 +624,7 @@ function initAugmentations() {
hacking_money_mult: 1.15,
hacking_mult: 1.12,
});
ArtificialBioNeuralNetwork.addToFactions([
"BitRunners",
"Fulcrum Secret Technologies",
]);
ArtificialBioNeuralNetwork.addToFactions(["BitRunners", "Fulcrum Secret Technologies"]);
if (augmentationExists(AugmentationNames.ArtificialBioNeuralNetwork)) {
delete Augmentations[AugmentationNames.ArtificialBioNeuralNetwork];
}
@ -677,11 +660,7 @@ function initAugmentations() {
hacking_exp_mult: 1.1,
hacking_mult: 1.08,
});
EnhancedMyelinSheathing.addToFactions([
"Fulcrum Secret Technologies",
"BitRunners",
"The Black Hand",
]);
EnhancedMyelinSheathing.addToFactions(["Fulcrum Secret Technologies", "BitRunners", "The Black Hand"]);
if (augmentationExists(AugmentationNames.EnhancedMyelinSheathing)) {
delete Augmentations[AugmentationNames.EnhancedMyelinSheathing];
}
@ -727,13 +706,7 @@ function initAugmentations() {
"and delete it.",
hacking_money_mult: 1.25,
});
DataJack.addToFactions([
"BitRunners",
"The Black Hand",
"NiteSec",
"Chongqing",
"New Tokyo",
]);
DataJack.addToFactions(["BitRunners", "The Black Hand", "NiteSec", "Chongqing", "New Tokyo"]);
if (augmentationExists(AugmentationNames.DataJack)) {
delete Augmentations[AugmentationNames.DataJack];
}
@ -1001,11 +974,7 @@ function initAugmentations() {
hacking_money_mult: 1.15,
hacking_mult: 1.09,
});
CranialSignalProcessorsG3.addToFactions([
"NiteSec",
"The Black Hand",
"BitRunners",
]);
CranialSignalProcessorsG3.addToFactions(["NiteSec", "The Black Hand", "BitRunners"]);
if (augmentationExists(AugmentationNames.CranialSignalProcessorsG3)) {
delete Augmentations[AugmentationNames.CranialSignalProcessorsG3];
}
@ -1122,9 +1091,7 @@ function initAugmentations() {
name: AugmentationNames.FocusWire,
repCost: 7.5e4,
moneyCost: 9e8,
info:
"A cranial implant that stops procrastination by blocking specific neural pathways " +
"in the brain.",
info: "A cranial implant that stops procrastination by blocking specific neural pathways " + "in the brain.",
hacking_exp_mult: 1.05,
strength_exp_mult: 1.05,
defense_exp_mult: 1.05,
@ -1134,12 +1101,7 @@ function initAugmentations() {
company_rep_mult: 1.1,
work_money_mult: 1.2,
});
FocusWire.addToFactions([
"Bachman & Associates",
"Clarke Incorporated",
"Four Sigma",
"KuaiGong International",
]);
FocusWire.addToFactions(["Bachman & Associates", "Clarke Incorporated", "Four Sigma", "KuaiGong International"]);
if (augmentationExists(AugmentationNames.FocusWire)) {
delete Augmentations[AugmentationNames.FocusWire];
}
@ -1156,12 +1118,7 @@ function initAugmentations() {
company_rep_mult: 1.3,
hacking_mult: 1.08,
});
PCDNI.addToFactions([
"Four Sigma",
"OmniTek Incorporated",
"ECorp",
"Blade Industries",
]);
PCDNI.addToFactions(["Four Sigma", "OmniTek Incorporated", "ECorp", "Blade Industries"]);
if (augmentationExists(AugmentationNames.PCDNI)) {
delete Augmentations[AugmentationNames.PCDNI];
}
@ -1179,11 +1136,7 @@ function initAugmentations() {
company_rep_mult: 1.75,
hacking_mult: 1.1,
});
PCDNIOptimizer.addToFactions([
"Fulcrum Secret Technologies",
"ECorp",
"Blade Industries",
]);
PCDNIOptimizer.addToFactions(["Fulcrum Secret Technologies", "ECorp", "Blade Industries"]);
if (augmentationExists(AugmentationNames.PCDNIOptimizer)) {
delete Augmentations[AugmentationNames.PCDNIOptimizer];
}
@ -1220,13 +1173,7 @@ function initAugmentations() {
company_rep_mult: 1.1,
faction_rep_mult: 1.1,
});
ADRPheromone1.addToFactions([
"Tian Di Hui",
"The Syndicate",
"NWO",
"MegaCorp",
"Four Sigma",
]);
ADRPheromone1.addToFactions(["Tian Di Hui", "The Syndicate", "NWO", "MegaCorp", "Four Sigma"]);
if (augmentationExists(AugmentationNames.ADRPheromone1)) {
delete Augmentations[AugmentationNames.ADRPheromone1];
}
@ -1243,12 +1190,7 @@ function initAugmentations() {
company_rep_mult: 1.2,
faction_rep_mult: 1.2,
});
ADRPheromone2.addToFactions([
"Silhouette",
"Four Sigma",
"Bachman & Associates",
"Clarke Incorporated",
]);
ADRPheromone2.addToFactions(["Silhouette", "Four Sigma", "Bachman & Associates", "Clarke Incorporated"]);
if (augmentationExists(AugmentationNames.ADRPheromone2)) {
delete Augmentations[AugmentationNames.ADRPheromone2];
}
@ -1267,11 +1209,7 @@ function initAugmentations() {
company_rep_mult: 1.15,
faction_rep_mult: 1.15,
});
ShadowsSimulacrum.addToFactions([
"The Syndicate",
"The Dark Army",
"Speakers for the Dead",
]);
ShadowsSimulacrum.addToFactions(["The Syndicate", "The Dark Army", "Speakers for the Dead"]);
if (augmentationExists(AugmentationNames.ShadowsSimulacrum)) {
delete Augmentations[AugmentationNames.ShadowsSimulacrum];
}
@ -1373,9 +1311,8 @@ function initAugmentations() {
"body's nervous system.",
stats: (
<>
This special augmentation can be leveled up infinitely. Each level of
this augmentation increases ALL multipliers by 1%, stacking
multiplicatively.
This special augmentation can be leveled up infinitely. Each level of this augmentation increases ALL
multipliers by 1%, stacking multiplicatively.
</>
),
hacking_chance_mult: 1.01,
@ -1419,17 +1356,13 @@ function initAugmentations() {
// levels that are purchased but not yet installed
let nextLevel = currLevel;
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
if (
Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor
) {
if (Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
++nextLevel;
}
}
let mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
NeuroFluxGovernor.baseRepRequirement =
500 * mult * BitNodeMultipliers.AugmentationRepCost;
NeuroFluxGovernor.baseCost =
750e3 * mult * BitNodeMultipliers.AugmentationMoneyCost;
NeuroFluxGovernor.baseRepRequirement = 500 * mult * BitNodeMultipliers.AugmentationRepCost;
NeuroFluxGovernor.baseCost = 750e3 * mult * BitNodeMultipliers.AugmentationMoneyCost;
if (augmentationExists(AugmentationNames.NeuroFluxGovernor)) {
delete Augmentations[AugmentationNames.NeuroFluxGovernor];
}
@ -1559,9 +1492,7 @@ function initAugmentations() {
name: AugmentationNames.SmartSonar,
repCost: 2.25e4,
moneyCost: 7.5e7,
info:
"A cochlear implant that helps the player detect and locate enemies " +
"using sound propagation.",
info: "A cochlear implant that helps the player detect and locate enemies " + "using sound propagation.",
dexterity_mult: 1.1,
dexterity_exp_mult: 1.15,
crime_money_mult: 1.25,
@ -1593,12 +1524,7 @@ function initAugmentations() {
agility_exp_mult: 1.1,
charisma_exp_mult: 1.1,
});
PowerRecirculator.addToFactions([
"Tetrads",
"The Dark Army",
"The Syndicate",
"NWO",
]);
PowerRecirculator.addToFactions(["Tetrads", "The Dark Army", "The Syndicate", "NWO"]);
if (augmentationExists(AugmentationNames.PowerRecirculator)) {
delete Augmentations[AugmentationNames.PowerRecirculator];
}
@ -1941,9 +1867,8 @@ function initAugmentations() {
moneyCost: 1.25e8,
info: (
<>
A collection of digital assets saved on a small chip. The chip is
implanted into your wrist. A small jack in the chip allows you to
connect it to a computer and upload the assets.
A collection of digital assets saved on a small chip. The chip is implanted into your wrist. A small jack in the
chip allows you to connect it to a computer and upload the assets.
</>
),
startingMoney: 1e6,
@ -2006,8 +1931,7 @@ function initAugmentations() {
repCost: 7.5e3,
moneyCost: 3e7,
info:
"A tiny chip that sits behind the retinae. This implant lets the" +
"user visually detect infrared radiation.",
"A tiny chip that sits behind the retinae. This implant lets the" + "user visually detect infrared radiation.",
crime_success_mult: 1.25,
crime_money_mult: 1.1,
dexterity_mult: 1.1,
@ -2098,8 +2022,7 @@ function initAugmentations() {
repCost: 6.25e4,
moneyCost: 2.75e8,
info:
"Cybernetic arms created from plasteel and carbon fibers that completely replace " +
"the user's organic arms.",
"Cybernetic arms created from plasteel and carbon fibers that completely replace " + "the user's organic arms.",
strength_mult: 1.3,
dexterity_mult: 1.3,
});
@ -2417,8 +2340,8 @@ function initAugmentations() {
"weaponized by Bladeburner units to be used against Synthoids.",
stats: (
<>
This augmentation allows you to perform Bladeburner actions and other
actions (such as working, commiting crimes, etc.) at the same time.
This augmentation allows you to perform Bladeburner actions and other actions (such as working, commiting
crimes, etc.) at the same time.
</>
),
isSpecial: true,
@ -2429,8 +2352,7 @@ function initAugmentations() {
// Update costs based on how many have been purchased
mult = Math.pow(
CONSTANTS.MultipleAugMultiplier *
[1, 0.96, 0.94, 0.93][SourceFileFlags[11]],
CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]],
Player.queuedAugmentations.length,
);
for (var name in Augmentations) {
@ -2445,9 +2367,7 @@ function initAugmentations() {
//Resets an Augmentation during (re-initizliation)
function resetAugmentation(newAugObject) {
if (!(newAugObject instanceof Augmentation)) {
throw new Error(
"Invalid argument 'newAugObject' passed into resetAugmentation",
);
throw new Error("Invalid argument 'newAugObject' passed into resetAugmentation");
}
var name = newAugObject.name;
if (augmentationExists(name)) {
@ -2464,9 +2384,7 @@ function applyAugmentation(aug, reapply = false) {
// Apply multipliers
for (const mult in augObj.mults) {
if (Player[mult] == null) {
console.warn(
`Augmentation has unrecognized multiplier property: ${mult}`,
);
console.warn(`Augmentation has unrecognized multiplier property: ${mult}`);
} else {
Player[mult] *= augObj.mults[mult];
}
@ -2477,9 +2395,7 @@ function applyAugmentation(aug, reapply = false) {
if (!reapply) {
Augmentations[aug.name].level = aug.level;
for (let i = 0; i < Player.augmentations.length; ++i) {
if (
Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor
) {
if (Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
Player.augmentations[i].level = aug.level;
return;
// break;
@ -2503,9 +2419,7 @@ function installAugmentations() {
let augmentationList = "";
let nfgIndex = -1;
for (let i = Player.queuedAugmentations.length - 1; i >= 0; i--) {
if (
Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor
) {
if (Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
nfgIndex = i;
break;
}
@ -2519,8 +2433,7 @@ function installAugmentations() {
}
applyAugmentation(Player.queuedAugmentations[i]);
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex)
continue;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
let level = "";
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
@ -2555,13 +2468,7 @@ export function displayAugmentationsContent(contentEl) {
onExport(Player);
}
ReactDOM.render(
<AugmentationsRoot
exportGameFn={backup}
installAugmentationsFn={installAugmentations}
/>,
contentEl,
);
ReactDOM.render(<AugmentationsRoot exportGameFn={backup} installAugmentationsFn={installAugmentations} />, contentEl);
}
export function isRepeatableAug(aug) {
@ -2574,9 +2481,4 @@ export function isRepeatableAug(aug) {
return false;
}
export {
installAugmentations,
initAugmentations,
applyAugmentation,
augmentationExists,
};
export { installAugmentations, initAugmentations, applyAugmentation, augmentationExists };

@ -15,10 +15,7 @@ import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
export function InstalledAugmentations(): React.ReactElement {
const sourceAugs = Player.augmentations.slice();
if (
Settings.OwnedAugmentationsOrder ===
OwnedAugmentationsOrderSetting.Alphabetically
) {
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
sourceAugs.sort((aug1, aug2) => {
return aug1.name <= aug2.name ? -1 : 1;
});

@ -23,10 +23,7 @@ type IState = {
rerenderFlag: boolean;
};
export class InstalledAugmentationsAndSourceFiles extends React.Component<
IProps,
IState
> {
export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps, IState> {
listRef: React.RefObject<HTMLUListElement>;
constructor(props: IProps) {
@ -89,14 +86,12 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<
}
sortByAcquirementTime(): void {
Settings.OwnedAugmentationsOrder =
OwnedAugmentationsOrderSetting.AcquirementTime;
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime;
this.rerender();
}
sortInOrder(): void {
Settings.OwnedAugmentationsOrder =
OwnedAugmentationsOrderSetting.Alphabetically;
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically;
this.rerender();
}

@ -14,10 +14,7 @@ import { SourceFileAccordion } from "../../ui/React/SourceFileAccordion";
export function OwnedSourceFiles(): React.ReactElement {
const sourceSfs = Player.sourceFiles.slice();
if (
Settings.OwnedAugmentationsOrder ===
OwnedAugmentationsOrderSetting.Alphabetically
) {
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
sourceSfs.sort((sf1, sf2) => {
return sf1.n - sf2.n;
});

@ -25,10 +25,7 @@ export function PlayerMultipliers(): React.ReactElement {
function improvements(r: number): JSX.Element[] {
let elems: JSX.Element[] = [];
if (r) {
elems = [
<td key="2">&nbsp;{"=>"}&nbsp;</td>,
<td key="3">{numeralWrapper.formatPercentage(r)}</td>,
];
elems = [<td key="2">&nbsp;{"=>"}&nbsp;</td>, <td key="3">{numeralWrapper.formatPercentage(r)}</td>];
}
return elems;
}
@ -60,20 +57,17 @@ export function PlayerMultipliers(): React.ReactElement {
[
"Bladeburner Success Chance",
Player.bladeburner_success_chance_mult,
Player.bladeburner_success_chance_mult *
mults.bladeburner_success_chance_mult,
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
],
[
"Bladeburner Max Stamina",
Player.bladeburner_max_stamina_mult,
Player.bladeburner_max_stamina_mult *
mults.bladeburner_max_stamina_mult,
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
],
[
"Bladeburner Stamina Gain",
Player.bladeburner_stamina_gain_mult,
Player.bladeburner_stamina_gain_mult *
mults.bladeburner_stamina_gain_mult,
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
],
[
"Bladeburner Field Analysis",
@ -95,110 +89,46 @@ export function PlayerMultipliers(): React.ReactElement {
</p>
<br />
{MultiplierTable([
[
"Hacking Chance ",
Player.hacking_chance_mult,
Player.hacking_chance_mult * mults.hacking_chance_mult,
],
[
"Hacking Speed ",
Player.hacking_speed_mult,
Player.hacking_speed_mult * mults.hacking_speed_mult,
],
[
"Hacking Money ",
Player.hacking_money_mult,
Player.hacking_money_mult * mults.hacking_money_mult,
],
[
"Hacking Growth ",
Player.hacking_grow_mult,
Player.hacking_grow_mult * mults.hacking_grow_mult,
],
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult],
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult],
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult],
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult],
])}
<br />
{MultiplierTable([
[
"Hacking Level ",
Player.hacking_mult,
Player.hacking_mult * mults.hacking_mult,
],
[
"Hacking Experience ",
Player.hacking_exp_mult,
Player.hacking_exp_mult * mults.hacking_exp_mult,
],
["Hacking Level ", Player.hacking_mult, Player.hacking_mult * mults.hacking_mult],
["Hacking Experience ", Player.hacking_exp_mult, Player.hacking_exp_mult * mults.hacking_exp_mult],
])}
<br />
{MultiplierTable([
[
"Strength Level ",
Player.strength_mult,
Player.strength_mult * mults.strength_mult,
],
[
"Strength Experience ",
Player.strength_exp_mult,
Player.strength_exp_mult * mults.strength_exp_mult,
],
["Strength Level ", Player.strength_mult, Player.strength_mult * mults.strength_mult],
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult],
])}
<br />
{MultiplierTable([
[
"Defense Level ",
Player.defense_mult,
Player.defense_mult * mults.defense_mult,
],
[
"Defense Experience ",
Player.defense_exp_mult,
Player.defense_exp_mult * mults.defense_exp_mult,
],
["Defense Level ", Player.defense_mult, Player.defense_mult * mults.defense_mult],
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult],
])}
<br />
{MultiplierTable([
[
"Dexterity Level ",
Player.dexterity_mult,
Player.dexterity_mult * mults.dexterity_mult,
],
[
"Dexterity Experience ",
Player.dexterity_exp_mult,
Player.dexterity_exp_mult * mults.dexterity_exp_mult,
],
["Dexterity Level ", Player.dexterity_mult, Player.dexterity_mult * mults.dexterity_mult],
["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult],
])}
<br />
{MultiplierTable([
[
"Agility Level ",
Player.agility_mult,
Player.agility_mult * mults.agility_mult,
],
[
"Agility Experience ",
Player.agility_exp_mult,
Player.agility_exp_mult * mults.agility_exp_mult,
],
["Agility Level ", Player.agility_mult, Player.agility_mult * mults.agility_mult],
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult],
])}
<br />
{MultiplierTable([
[
"Charisma Level ",
Player.charisma_mult,
Player.charisma_mult * mults.charisma_mult,
],
[
"Charisma Experience ",
Player.charisma_exp_mult,
Player.charisma_exp_mult * mults.charisma_exp_mult,
],
["Charisma Level ", Player.charisma_mult, Player.charisma_mult * mults.charisma_mult],
["Charisma Experience ", Player.charisma_exp_mult, Player.charisma_exp_mult * mults.charisma_exp_mult],
])}
<br />
@ -211,8 +141,7 @@ export function PlayerMultipliers(): React.ReactElement {
[
"Hacknet Node purchase cost ",
Player.hacknet_node_purchase_cost_mult,
Player.hacknet_node_purchase_cost_mult *
mults.hacknet_node_purchase_cost_mult,
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
],
[
"Hacknet Node RAM upgrade cost ",
@ -222,48 +151,26 @@ export function PlayerMultipliers(): React.ReactElement {
[
"Hacknet Node Core purchase cost ",
Player.hacknet_node_core_cost_mult,
Player.hacknet_node_core_cost_mult *
mults.hacknet_node_core_cost_mult,
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
],
[
"Hacknet Node level upgrade cost ",
Player.hacknet_node_level_cost_mult,
Player.hacknet_node_level_cost_mult *
mults.hacknet_node_level_cost_mult,
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
],
])}
<br />
{MultiplierTable([
[
"Company reputation gain ",
Player.company_rep_mult,
Player.company_rep_mult * mults.company_rep_mult,
],
[
"Faction reputation gain ",
Player.faction_rep_mult,
Player.faction_rep_mult * mults.faction_rep_mult,
],
[
"Salary ",
Player.work_money_mult,
Player.work_money_mult * mults.work_money_mult,
],
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult],
["Faction reputation gain ", Player.faction_rep_mult, Player.faction_rep_mult * mults.faction_rep_mult],
["Salary ", Player.work_money_mult, Player.work_money_mult * mults.work_money_mult],
])}
<br />
{MultiplierTable([
[
"Crime success ",
Player.crime_success_mult,
Player.crime_success_mult * mults.crime_success_mult,
],
[
"Crime money ",
Player.crime_money_mult,
Player.crime_money_mult * mults.crime_money_mult,
],
["Crime success ", Player.crime_success_mult, Player.crime_success_mult * mults.crime_success_mult],
["Crime money ", Player.crime_money_mult, Player.crime_money_mult * mults.crime_money_mult],
])}
<br />

@ -15,17 +15,14 @@ export function PurchasedAugmentations(): React.ReactElement {
// Only render the last NeuroFlux (there are no findLastIndex btw)
let nfgIndex = -1;
for (let i = Player.queuedAugmentations.length - 1; i >= 0; i--) {
if (
Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor
) {
if (Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
nfgIndex = i;
break;
}
}
for (let i = 0; i < Player.queuedAugmentations.length; i++) {
const ownedAug = Player.queuedAugmentations[i];
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex)
continue;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
const aug = Augmentations[ownedAug.name];
let level = null;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {

@ -47,13 +47,10 @@ export class AugmentationsRoot extends React.Component<IProps, IState> {
<div id="augmentations-content">
<h1>Purchased Augmentations</h1>
<p>
Below is a list of all Augmentations you have purchased but not yet
installed. Click the button below to install them.
</p>
<p>
WARNING: Installing your Augmentations resets most of your progress,
including:
Below is a list of all Augmentations you have purchased but not yet installed. Click the button below to
install them.
</p>
<p>WARNING: Installing your Augmentations resets most of your progress, including:</p>
<br />
<p>- Stats/Skill levels and Experience</p>
<p>- Money</p>
@ -64,10 +61,9 @@ export class AugmentationsRoot extends React.Component<IProps, IState> {
<p>- Stocks</p>
<br />
<p>
Installing Augmentations lets you start over with the perks and
benefits granted by all of the Augmentations you have ever installed.
Also, you will keep any scripts and RAM/Core upgrades on your home
computer (but you will lose all programs besides NUKE.exe)
Installing Augmentations lets you start over with the perks and benefits granted by all of the Augmentations
you have ever installed. Also, you will keep any scripts and RAM/Core upgrades on your home computer (but you
will lose all programs besides NUKE.exe)
</p>
<StdButton
onClick={this.props.installAugmentationsFn}
@ -83,9 +79,7 @@ export class AugmentationsRoot extends React.Component<IProps, IState> {
<PurchasedAugmentations />
<h1>Installed Augmentations</h1>
<p>
{`List of all Augmentations ${
Player.sourceFiles.length > 0 ? "and Source Files " : ""
} ` +
{`List of all Augmentations ${Player.sourceFiles.length > 0 ? "and Source Files " : ""} ` +
`that have been installed. You have gained the effects of these.`}
</p>
<InstalledAugmentationsAndSourceFiles />

@ -29,8 +29,8 @@ export function SourceFileMinus1(): React.ReactElement {
panelContent={
<>
<p>
This Source-File can only be acquired with obscure knowledge of
the game, javascript, and the web ecosystem.
This Source-File can only be acquired with obscure knowledge of the game, javascript, and the web
ecosystem.
</p>
<p>It increases all of the player's multipliers by 0.1%</p>
<br />

@ -1,11 +1,7 @@
import { Player } from "../Player";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { addOffset } from "../../utils/helpers/addOffset";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { BladeburnerConstants } from "./data/Constants";
import { IBladeburner } from "./IBladeburner";
import { IAction, ISuccessChanceParams } from "./IAction";
@ -106,10 +102,8 @@ export class Action implements IAction {
if (params && params.name) this.name = params.name;
if (params && params.desc) this.desc = params.desc;
if (params && params.baseDifficulty)
this.baseDifficulty = addOffset(params.baseDifficulty, 10);
if (params && params.difficultyFac)
this.difficultyFac = params.difficultyFac;
if (params && params.baseDifficulty) this.baseDifficulty = addOffset(params.baseDifficulty, 10);
if (params && params.difficultyFac) this.difficultyFac = params.difficultyFac;
if (params && params.rewardFac) this.rewardFac = params.rewardFac;
if (params && params.rankGain) this.rankGain = params.rankGain;
@ -144,11 +138,7 @@ export class Action implements IAction {
if (this.decays.hasOwnProperty(decay)) {
if (this.decays[decay] > 1) {
throw new Error(
"Invalid decays when constructing " +
"Action " +
this.name +
". " +
"Decay value cannot be greater than 1",
"Invalid decays when constructing " + "Action " + this.name + ". " + "Decay value cannot be greater than 1",
);
}
}
@ -156,8 +146,7 @@ export class Action implements IAction {
}
getDifficulty(): number {
const difficulty =
this.baseDifficulty * Math.pow(this.difficultyFac, this.level - 1);
const difficulty = this.baseDifficulty * Math.pow(this.difficultyFac, this.level - 1);
if (isNaN(difficulty)) {
throw new Error("Calculated NaN in Action.getDifficulty()");
}
@ -207,27 +196,16 @@ export class Action implements IAction {
return 1;
}
getChaosCompetencePenalty(
inst: IBladeburner,
params: ISuccessChanceParams,
): number {
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number {
const city = inst.getCurrentCity();
if (params.est) {
return Math.pow(
city.popEst / BladeburnerConstants.PopulationThreshold,
BladeburnerConstants.PopulationExponent,
);
return Math.pow(city.popEst / BladeburnerConstants.PopulationThreshold, BladeburnerConstants.PopulationExponent);
} else {
return Math.pow(
city.pop / BladeburnerConstants.PopulationThreshold,
BladeburnerConstants.PopulationExponent,
);
return Math.pow(city.pop / BladeburnerConstants.PopulationThreshold, BladeburnerConstants.PopulationExponent);
}
}
getChaosDifficultyBonus(
inst: IBladeburner /*, params: ISuccessChanceParams*/,
): number {
getChaosDifficultyBonus(inst: IBladeburner /*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
@ -260,14 +238,9 @@ export class Action implements IAction {
* @params - options:
* est (bool): Get success chance estimate instead of real success chance
*/
getSuccessChance(
inst: IBladeburner,
params: ISuccessChanceParams = { est: false },
): number {
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams = { est: false }): number {
if (inst == null) {
throw new Error(
"Invalid Bladeburner instance passed into Action.getSuccessChance",
);
throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");
}
let difficulty = this.getDifficulty();
let competence = 0;
@ -277,14 +250,10 @@ export class Action implements IAction {
const key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
let effMultiplier = inst.skillMultipliers[key];
if (effMultiplier == null) {
console.error(
`Failed to find Bladeburner Skill multiplier for: ${stat}`,
);
console.error(`Failed to find Bladeburner Skill multiplier for: ${stat}`);
effMultiplier = 1;
}
competence +=
this.weights[stat] *
Math.pow(effMultiplier * playerStatLvl, this.decays[stat]);
competence += this.weights[stat] * Math.pow(effMultiplier * playerStatLvl, this.decays[stat]);
}
}
competence *= Player.getIntelligenceBonus(0.75);
@ -313,24 +282,17 @@ export class Action implements IAction {
competence *= Player.bladeburner_success_chance_mult;
if (isNaN(competence)) {
throw new Error(
"Competence calculated as NaN in Action.getSuccessChance()",
);
throw new Error("Competence calculated as NaN in Action.getSuccessChance()");
}
return Math.min(1, competence / difficulty);
}
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number {
return Math.ceil(
0.5 * this.maxLevel * (2 * baseSuccessesPerLevel + (this.maxLevel - 1)),
);
return Math.ceil(0.5 * this.maxLevel * (2 * baseSuccessesPerLevel + (this.maxLevel - 1)));
}
setMaxLevel(baseSuccessesPerLevel: number): void {
if (
this.successes >=
this.getSuccessesNeededForNextLevel(baseSuccessesPerLevel)
) {
if (this.successes >= this.getSuccessesNeededForNextLevel(baseSuccessesPerLevel)) {
++this.maxLevel;
}
}

@ -1,9 +1,5 @@
import { IActionIdentifier } from "./IActionIdentifier";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
interface IParams {
name?: string;

@ -1,9 +1,5 @@
import { Operation, IOperationParams } from "./Operation";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
export class BlackOperation extends Operation {
constructor(params: IOperationParams | null = null) {

@ -735,9 +735,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
});
BlackOperations["Operation Daedalus"] = new BlackOperation({
name: "Operation Daedalus",
desc:
"Yesterday we obeyed kings and bent our neck to emperors. " +
"Today we kneel only to truth.",
desc: "Yesterday we obeyed kings and bent our neck to emperors. " + "Today we kneel only to truth.",
baseDifficulty: 80e3,
reqdRank: 400e3,
rankGain: 40e3,

File diff suppressed because it is too large Load Diff

@ -1,10 +1,6 @@
import { BladeburnerConstants } from "./data/Constants";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { addOffset } from "../../utils/helpers/addOffset";
interface IChangePopulationByCountParams {
@ -52,10 +48,7 @@ export class City {
this.name = name;
// Synthoid population and estimate
this.pop = getRandomInt(
BladeburnerConstants.PopulationThreshold,
1.5 * BladeburnerConstants.PopulationThreshold,
);
this.pop = getRandomInt(BladeburnerConstants.PopulationThreshold, 1.5 * BladeburnerConstants.PopulationThreshold);
this.popEst = this.pop * (Math.random() + 0.5);
// Number of Synthoid communities population and estimate
@ -83,9 +76,7 @@ export class City {
improvePopulationEstimateByCount(n: number): void {
if (isNaN(n)) {
throw new Error(
"NaN passeed into City.improvePopulationEstimateByCount()",
);
throw new Error("NaN passeed into City.improvePopulationEstimateByCount()");
}
if (this.popEst < this.pop) {
this.popEst += n;
@ -106,9 +97,7 @@ export class City {
improvePopulationEstimateByPercentage(p: number, skillMult = 1): void {
p = p * skillMult;
if (isNaN(p)) {
throw new Error(
"NaN passed into City.improvePopulationEstimateByPercentage()",
);
throw new Error("NaN passed into City.improvePopulationEstimateByPercentage()");
}
if (this.popEst < this.pop) {
++this.popEst; // In case estimate is 0
@ -146,10 +135,7 @@ export class City {
* estChange(int): How much the estimate should change by
* estOffset(int): Add offset to estimate (offset by percentage)
*/
changePopulationByCount(
n: number,
params: IChangePopulationByCountParams = { estChange: 0, estOffset: 0 },
): void {
changePopulationByCount(n: number, params: IChangePopulationByCountParams = { estChange: 0, estOffset: 0 }): void {
if (isNaN(n)) {
throw new Error("NaN passed into City.changePopulationByCount()");
}

@ -1,10 +1,6 @@
import { IBladeburner } from "./IBladeburner";
import { Action, IActionParams } from "./Action";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
export class Contract extends Action {
constructor(params: IActionParams | null = null) {

@ -61,10 +61,7 @@ export interface IAction {
getActionTime(inst: IBladeburner): number;
getTeamSuccessBonus(inst: IBladeburner): number;
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
getChaosCompetencePenalty(
inst: IBladeburner,
params: ISuccessChanceParams,
): number;
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
getChaosDifficultyBonus(inst: IBladeburner): number;
getEstSuccessChance(inst: IBladeburner): number[];
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams): number;

@ -68,57 +68,22 @@ export interface IBladeburner {
getBlackOpNamesNetscriptFn(): string[];
getGeneralActionNamesNetscriptFn(): string[];
getSkillNamesNetscriptFn(): string[];
startActionNetscriptFn(
player: IPlayer,
type: string,
name: string,
workerScript: WorkerScript,
): boolean;
getActionTimeNetscriptFn(
player: IPlayer,
type: string,
name: string,
workerScript: WorkerScript,
): number;
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean;
getActionTimeNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): number;
getActionEstimatedSuccessChanceNetscriptFn(
player: IPlayer,
type: string,
name: string,
workerScript: WorkerScript,
): number[];
getActionCountRemainingNetscriptFn(
type: string,
name: string,
workerScript: WorkerScript,
): number;
getSkillLevelNetscriptFn(
skillName: string,
workerScript: WorkerScript,
): number;
getSkillUpgradeCostNetscriptFn(
skillName: string,
workerScript: WorkerScript,
): number;
upgradeSkillNetscriptFn(
skillName: string,
workerScript: WorkerScript,
): boolean;
getTeamSizeNetscriptFn(
type: string,
name: string,
workerScript: WorkerScript,
): number;
setTeamSizeNetscriptFn(
type: string,
name: string,
size: number,
workerScript: WorkerScript,
): number;
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number;
getSkillUpgradeCostNetscriptFn(skillName: string, workerScript: WorkerScript): number;
upgradeSkillNetscriptFn(skillName: string, workerScript: WorkerScript): boolean;
getTeamSizeNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
setTeamSizeNetscriptFn(type: string, name: string, size: number, workerScript: WorkerScript): number;
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean;
getActionIdFromTypeAndName(
type: string,
name: string,
): IActionIdentifier | null;
getActionIdFromTypeAndName(type: string, name: string): IActionIdentifier | null;
executeStartConsoleCommand(player: IPlayer, args: string[]): void;
executeSkillConsoleCommand(args: string[]): void;
executeLogConsoleCommand(args: string[]): void;

@ -1,11 +1,7 @@
import { IBladeburner } from "./IBladeburner";
import { BladeburnerConstants } from "./data/Constants";
import { Action, IActionParams } from "./Action";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
export interface IOperationParams extends IActionParams {
reqdRank?: number;
@ -37,9 +33,7 @@ export class Operation extends Action {
return inst.skillMultipliers.successChanceOperation;
}
getChaosDifficultyBonus(
inst: IBladeburner /*, params: ISuccessChanceParams*/,
): number {
getChaosDifficultyBonus(inst: IBladeburner /*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);

@ -66,14 +66,10 @@ export class Skill {
constructor(params: ISkillParams = { name: "foo", desc: "foo" }) {
if (!params.name) {
throw new Error(
"Failed to initialize Bladeburner Skill. No name was specified in ctor",
);
throw new Error("Failed to initialize Bladeburner Skill. No name was specified in ctor");
}
if (!params.desc) {
throw new Error(
"Failed to initialize Bladeburner Skills. No desc was specified in ctor",
);
throw new Error("Failed to initialize Bladeburner Skills. No desc was specified in ctor");
}
this.name = params.name;
this.desc = params.desc;
@ -138,10 +134,7 @@ export class Skill {
}
calculateCost(currentLevel: number): number {
return Math.floor(
(this.baseCost + currentLevel * this.costInc) *
BitNodeMultipliers.BladeburnerSkillCost,
);
return Math.floor((this.baseCost + currentLevel * this.costInc) * BitNodeMultipliers.BladeburnerSkillCost);
}
getMultiplier(name: string): number {

@ -8,8 +8,7 @@ export const Skills: IMap<Skill> = {};
Skills[SkillNames.BladesIntuition] = new Skill({
name: SkillNames.BladesIntuition,
desc:
"Each level of this skill increases your success chance " +
"for all Contracts, Operations, and BlackOps by 3%",
"Each level of this skill increases your success chance " + "for all Contracts, Operations, and BlackOps by 3%",
baseCost: 3,
costInc: 2.1,
successChanceAll: 3,
@ -34,18 +33,14 @@ export const Skills: IMap<Skill> = {};
});
Skills[SkillNames.DigitalObserver] = new Skill({
name: SkillNames.DigitalObserver,
desc:
"Each level of this skill increases your success chance in " +
"all Operations and BlackOps by 4%",
desc: "Each level of this skill increases your success chance in " + "all Operations and BlackOps by 4%",
baseCost: 2,
costInc: 2.1,
successChanceOperation: 4,
});
Skills[SkillNames.Tracer] = new Skill({
name: SkillNames.Tracer,
desc:
"Each level of this skill increases your success chance in " +
"all Contracts by 4%",
desc: "Each level of this skill increases your success chance in " + "all Contracts by 4%",
baseCost: 2,
costInc: 2.1,
successChanceContract: 4,
@ -72,9 +67,7 @@ export const Skills: IMap<Skill> = {};
});
Skills[SkillNames.EvasiveSystem] = new Skill({
name: SkillNames.EvasiveSystem,
desc:
"Each level of this skill increases your effective " +
"dexterity and agility for Bladeburner actions by 4%",
desc: "Each level of this skill increases your effective " + "dexterity and agility for Bladeburner actions by 4%",
baseCost: 2,
costInc: 2.1,
effDex: 4,

@ -27,14 +27,7 @@ export const BladeburnerConstants: {
HrcHpGain: number;
HrcStaminaGain: number;
} = {
CityNames: [
"Aevum",
"Chongqing",
"Sector-12",
"New Tokyo",
"Ishima",
"Volhaven",
],
CityNames: ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"],
CyclesPerSecond: 5, // Game cycle is 200 ms
StaminaGainPerSecond: 0.0085,

@ -1,13 +1,7 @@
import * as React from "react";
export const stealthIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16px"
height="16px"
viewBox="0 0 166 132"
style={{ fill: "#adff2f" }}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 166 132" style={{ fill: "#adff2f" }}>
<g>
<path d="M132.658-0.18l-24.321,24.321c-7.915-2.71-16.342-4.392-25.087-4.392c-45.84,0-83,46-83,46 s14.1,17.44,35.635,30.844L12.32,120.158l12.021,12.021L144.68,11.841L132.658-0.18z M52.033,80.445 c-2.104-4.458-3.283-9.438-3.283-14.695c0-19.054,15.446-34.5,34.5-34.5c5.258,0,10.237,1.179,14.695,3.284L52.033,80.445z" />
<path d="M134.865,37.656l-18.482,18.482c0.884,3.052,1.367,6.275,1.367,9.612c0,19.055-15.446,34.5-34.5,34.5 c-3.337,0-6.56-0.483-9.611-1.367l-10.124,10.124c6.326,1.725,12.934,2.743,19.735,2.743c45.84,0,83-46,83-46 S153.987,50.575,134.865,37.656z" />

@ -26,11 +26,7 @@ export function AllPages(props: IProps): React.ReactElement {
return (
<a
onClick={() => setPage(props.name)}
className={
page !== props.name
? "bladeburner-nav-button noselect"
: "bladeburner-nav-button-inactive noselect"
}
className={page !== props.name ? "bladeburner-nav-button noselect" : "bladeburner-nav-button-inactive noselect"}
>
{props.name}
</a>
@ -44,29 +40,14 @@ export function AllPages(props: IProps): React.ReactElement {
<Header name={"BlackOps"} />
<Header name={"Skills"} />
<div style={{ display: "block", margin: "4px", padding: "4px" }}>
{page === "General" && (
<GeneralActionPage
bladeburner={props.bladeburner}
player={props.player}
/>
)}
{page === "Contracts" && (
<ContractPage bladeburner={props.bladeburner} player={props.player} />
)}
{page === "Operations" && (
<OperationPage
bladeburner={props.bladeburner}
player={props.player}
/>
)}
{page === "BlackOps" && (
<BlackOpPage bladeburner={props.bladeburner} player={props.player} />
)}
{page === "General" && <GeneralActionPage bladeburner={props.bladeburner} player={props.player} />}
{page === "Contracts" && <ContractPage bladeburner={props.bladeburner} player={props.player} />}
{page === "Operations" && <OperationPage bladeburner={props.bladeburner} player={props.player} />}
{page === "BlackOps" && <BlackOpPage bladeburner={props.bladeburner} player={props.player} />}
{page === "Skills" && <SkillPage bladeburner={props.bladeburner} />}
</div>
<span className="text">
{stealthIcon} = This action requires stealth, {killIcon} = This action
involves retirement
{stealthIcon} = This action requires stealth, {killIcon} = This action involves retirement
</span>
</>
);

@ -1,8 +1,5 @@
import React, { useState } from "react";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import { stealthIcon, killIcon } from "../data/Icons";
@ -23,17 +20,13 @@ export function BlackOpElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isCompleted = props.bladeburner.blackops[props.action.name] != null;
if (isCompleted) {
return (
<h2 style={{ display: "block" }}>{props.action.name} (COMPLETED)</h2>
);
return <h2 style={{ display: "block" }}>{props.action.name} (COMPLETED)</h2>;
}
const isActive =
props.bladeburner.action.type === ActionTypes["BlackOperation"] &&
props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(
props.bladeburner,
);
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
const actionTime = props.action.getActionTime(props.bladeburner);
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
const computedActionTimeCurrent = Math.min(
@ -62,8 +55,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
<CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
@ -73,9 +65,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
@ -87,21 +77,14 @@ export function BlackOpElem(props: IProps): React.ReactElement {
>
Start
</a>
<a
onClick={onTeam}
style={{ margin: "3px", padding: "3px" }}
className="a-link-button"
>
<a onClick={onTeam} style={{ margin: "3px", padding: "3px" }} className="a-link-button">
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
</a>
</>
)}
<br />
<br />
<p
style={{ display: "inline-block" }}
dangerouslySetInnerHTML={{ __html: props.action.desc }}
/>
<p style={{ display: "inline-block" }} dangerouslySetInnerHTML={{ __html: props.action.desc }} />
<br />
<br />
<p style={{ display: "block", color: hasReqdRank ? "white" : "red" }}>
@ -109,8 +92,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
</p>
<br />
<pre style={{ display: "inline-block" }}>
Estimated Success Chance:{" "}
<SuccessChance chance={estimatedSuccessChance} />{" "}
Estimated Success Chance: <SuccessChance chance={estimatedSuccessChance} />{" "}
{props.action.isStealth ? stealthIcon : <></>}
{props.action.isKill ? killIcon : <></>}
<br />

@ -22,7 +22,8 @@ export function BlackOpList(props: IProps): React.ReactElement {
});
blackops = blackops.filter(
(blackop: BlackOperation, i: number) => !(
(blackop: BlackOperation, i: number) =>
!(
props.bladeburner.blackops[blackops[i].name] == null &&
i !== 0 &&
props.bladeburner.blackops[blackops[i - 1].name] == null
@ -35,11 +36,7 @@ export function BlackOpList(props: IProps): React.ReactElement {
<>
{blackops.map((blackop: BlackOperation) => (
<li key={blackop.name} className="bladeburner-action">
<BlackOpElem
bladeburner={props.bladeburner}
action={blackop}
player={props.player}
/>
<BlackOpElem bladeburner={props.bladeburner} action={blackop} player={props.player} />
</li>
))}
</>

@ -12,19 +12,15 @@ export function BlackOpPage(props: IProps): React.ReactElement {
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
Black Operations (Black Ops) are special, one-time covert operations.
Each Black Op must be unlocked successively by completing the one before
it.
Black Operations (Black Ops) are special, one-time covert operations. 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>
<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete 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.
Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank
losses.
</p>
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
</>

@ -10,10 +10,7 @@ interface ILineProps {
function Line(props: ILineProps): React.ReactElement {
return (
<tr>
<td
className="bladeburner-console-line"
style={{ color: "var(--my-font-color)", whiteSpace: "pre-wrap" }}
>
<td className="bladeburner-console-line" style={{ color: "var(--my-font-color)", whiteSpace: "pre-wrap" }}>
{props.content}
</td>
</tr>
@ -29,9 +26,7 @@ export function Console(props: IProps): React.ReactElement {
const lastRef = useRef<HTMLDivElement>(null);
const setRerender = useState(false)[1];
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(
props.bladeburner.consoleHistory.length,
);
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
// TODO: Figure out how to actually make the scrolling work correctly.
function scrollToBottom(): void {
@ -121,11 +116,7 @@ export function Console(props: IProps): React.ReactElement {
{props.bladeburner.consoleLogs.map((log: any, i: number) => (
<Line key={i} content={log} />
))}
<tr
key="input"
id="bladeburner-console-input-row"
className="bladeburner-console-input-row"
>
<tr key="input" id="bladeburner-console-input-row" className="bladeburner-console-input-row">
<td className="bladeburner-console-input-cell">
<pre>{"> "}</pre>
<input

@ -1,10 +1,7 @@
import React, { useState } from "react";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants";
import { IBladeburner } from "../IBladeburner";
@ -21,11 +18,8 @@ interface IProps {
export function ContractElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isActive =
props.bladeburner.action.type === ActionTypes["Contract"] &&
props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(
props.bladeburner,
);
props.bladeburner.action.type === ActionTypes["Contract"] && props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
@ -43,15 +37,13 @@ export function ContractElem(props: IProps): React.ReactElement {
function increaseLevel(): void {
++props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function decreaseLevel(): void {
--props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
@ -65,8 +57,7 @@ export function ContractElem(props: IProps): React.ReactElement {
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
<CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
@ -76,18 +67,12 @@ export function ContractElem(props: IProps): React.ReactElement {
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
onClick={onStart}
className="a-link-button"
style={{ margin: "3px", padding: "3px" }}
>
<a onClick={onStart} className="a-link-button" style={{ margin: "3px", padding: "3px" }}>
Start
</a>
</>
@ -96,40 +81,24 @@ export function ContractElem(props: IProps): React.ReactElement {
<br />
<pre className="tooltip" style={{ display: "inline-block" }}>
<span className="tooltiptext">
{props.action.getSuccessesNeededForNextLevel(
BladeburnerConstants.ContractSuccessesPerLevel,
)}{" "}
successes needed for next level
{props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel)} successes needed
for next level
</span>
Level: {props.action.level} / {props.action.maxLevel}
</pre>
<a
onClick={increaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
maxLevel ? "a-link-button-inactive" : "a-link-button"
}`}
className={`tooltip ${maxLevel ? "a-link-button-inactive" : "a-link-button"}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
{isActive && <span className="tooltiptext">WARNING: changing the level will restart the Operation</span>}
</a>
<a
onClick={decreaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"
}`}
className={`tooltip ${props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
{isActive && <span className="tooltiptext">WARNING: changing the level will restart the Operation</span>}
</a>
<br />
<br />
@ -137,8 +106,7 @@ export function ContractElem(props: IProps): React.ReactElement {
<span dangerouslySetInnerHTML={{ __html: props.action.desc }} />
<br />
<br />
Estimated success chance:{" "}
<SuccessChance chance={estimatedSuccessChance} />{" "}
Estimated success chance: <SuccessChance chance={estimatedSuccessChance} />{" "}
{props.action.isStealth ? stealthIcon : <></>}
{props.action.isKill ? killIcon : <></>}
<br />
@ -151,22 +119,11 @@ export function ContractElem(props: IProps): React.ReactElement {
Failures: {props.action.failures}
</pre>
<br />
<label
className="tooltip"
style={{ color: "white" }}
htmlFor={autolevelCheckboxId}
>
<label className="tooltip" style={{ color: "white" }} htmlFor={autolevelCheckboxId}>
Autolevel:
<span className="tooltiptext">
Automatically increase operation level when possible
</span>
<span className="tooltiptext">Automatically increase operation level when possible</span>
</label>
<input
type="checkbox"
id={autolevelCheckboxId}
checked={props.action.autoLevel}
onChange={onAutolevel}
/>
<input type="checkbox" id={autolevelCheckboxId} checked={props.action.autoLevel} onChange={onAutolevel} />
</>
);
}

@ -15,11 +15,7 @@ export function ContractList(props: IProps): React.ReactElement {
<>
{names.map((name: string) => (
<li key={name} className="bladeburner-action">
<ContractElem
bladeburner={props.bladeburner}
action={contracts[name]}
player={props.player}
/>
<ContractElem bladeburner={props.bladeburner} action={contracts[name]} player={props.player} />
</li>
))}
</>

@ -12,14 +12,12 @@ export function ContractPage(props: IProps): React.ReactElement {
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
Complete contracts in order to increase your Bladeburner rank and earn
money. Failing a contract will cause you to lose HP, which can lead to
hospitalization.
Complete contracts in order to increase your Bladeburner rank and earn money. Failing a contract will cause you
to lose HP, which can lead to hospitalization.
<br />
<br />
You can unlock higher-level contracts by successfully completing them.
Higher-level contracts are more difficult, but grant more rank,
experience, and money.
You can unlock higher-level contracts by successfully completing them. Higher-level contracts are more
difficult, but grant more rank, experience, and money.
</p>
<ContractList bladeburner={props.bladeburner} player={props.player} />
</>

@ -1,10 +1,7 @@
import React, { useState } from "react";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { CopyableText } from "../../ui/React/CopyableText";
@ -37,13 +34,7 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
})();
const successChance =
props.action.name === "Recruitment"
? Math.max(
0,
Math.min(
props.bladeburner.getRecruitmentSuccessChance(props.player),
1,
),
)
? Math.max(0, Math.min(props.bladeburner.getRecruitmentSuccessChance(props.player), 1))
: -1;
function onStart(): void {
@ -58,8 +49,7 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
<CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
@ -69,28 +59,19 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
onClick={onStart}
className="a-link-button"
style={{ margin: "3px", padding: "3px" }}
>
<a onClick={onStart} className="a-link-button" style={{ margin: "3px", padding: "3px" }}>
Start
</a>
</>
)}
<br />
<br />
<pre
style={{ display: "inline-block" }}
dangerouslySetInnerHTML={{ __html: props.action.desc }}
></pre>
<pre style={{ display: "inline-block" }} dangerouslySetInnerHTML={{ __html: props.action.desc }}></pre>
<br />
<br />
<pre style={{ display: "inline-block" }}>

@ -21,11 +21,7 @@ export function GeneralActionList(props: IProps): React.ReactElement {
<>
{actions.map((action: Action) => (
<li key={action.name} className="bladeburner-action">
<GeneralActionElem
bladeburner={props.bladeburner}
action={action}
player={props.player}
/>
<GeneralActionElem bladeburner={props.bladeburner} action={action} player={props.player} />
</li>
))}
</>

@ -12,13 +12,10 @@ export function GeneralActionPage(props: IProps): React.ReactElement {
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
These are generic actions that will assist you in your Bladeburner
duties. They will not affect your Bladeburner rank in any way.
These are generic actions that will assist you in your Bladeburner duties. They will not affect your Bladeburner
rank in any way.
</p>
<GeneralActionList
bladeburner={props.bladeburner}
player={props.player}
/>
<GeneralActionList bladeburner={props.bladeburner} player={props.player} />
</>
);
}

@ -1,10 +1,7 @@
import React, { useState } from "react";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants";
import { createPopup } from "../../ui/React/createPopup";
@ -23,11 +20,8 @@ interface IProps {
export function OperationElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isActive =
props.bladeburner.action.type === ActionTypes["Operation"] &&
props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(
props.bladeburner,
);
props.bladeburner.action.type === ActionTypes["Operation"] && props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
@ -54,15 +48,13 @@ export function OperationElem(props: IProps): React.ReactElement {
function increaseLevel(): void {
++props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function decreaseLevel(): void {
--props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
@ -76,8 +68,7 @@ export function OperationElem(props: IProps): React.ReactElement {
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
<CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
@ -87,25 +78,15 @@ export function OperationElem(props: IProps): React.ReactElement {
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
onClick={onStart}
className="a-link-button"
style={{ margin: "3px", padding: "3px" }}
>
<a onClick={onStart} className="a-link-button" style={{ margin: "3px", padding: "3px" }}>
Start
</a>
<a
onClick={onTeam}
style={{ margin: "3px", padding: "3px" }}
className="a-link-button"
>
<a onClick={onTeam} style={{ margin: "3px", padding: "3px" }} className="a-link-button">
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
</a>
</>
@ -114,40 +95,24 @@ export function OperationElem(props: IProps): React.ReactElement {
<br />
<pre className="tooltip" style={{ display: "inline-block" }}>
<span className="tooltiptext">
{props.action.getSuccessesNeededForNextLevel(
BladeburnerConstants.OperationSuccessesPerLevel,
)}{" "}
successes needed for next level
{props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel)} successes
needed for next level
</span>
Level: {props.action.level} / {props.action.maxLevel}
</pre>
<a
onClick={increaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
maxLevel ? "a-link-button-inactive" : "a-link-button"
}`}
className={`tooltip ${maxLevel ? "a-link-button-inactive" : "a-link-button"}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
{isActive && <span className="tooltiptext">WARNING: changing the level will restart the Operation</span>}
</a>
<a
onClick={decreaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"
}`}
className={`tooltip ${props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
{isActive && <span className="tooltiptext">WARNING: changing the level will restart the Operation</span>}
</a>
<br />
<br />
@ -155,8 +120,7 @@ export function OperationElem(props: IProps): React.ReactElement {
<span dangerouslySetInnerHTML={{ __html: props.action.desc }} />
<br />
<br />
Estimated success chance:{" "}
<SuccessChance chance={estimatedSuccessChance} />{" "}
Estimated success chance: <SuccessChance chance={estimatedSuccessChance} />{" "}
{props.action.isStealth ? stealthIcon : <></>}
{props.action.isKill ? killIcon : <></>}
<br />
@ -169,22 +133,11 @@ export function OperationElem(props: IProps): React.ReactElement {
Failures: {props.action.failures}
</pre>
<br />
<label
className="tooltip"
style={{ color: "white" }}
htmlFor={autolevelCheckboxId}
>
<label className="tooltip" style={{ color: "white" }} htmlFor={autolevelCheckboxId}>
Autolevel:
<span className="tooltiptext">
Automatically increase operation level when possible
</span>
<span className="tooltiptext">Automatically increase operation level when possible</span>
</label>
<input
type="checkbox"
id={autolevelCheckboxId}
checked={props.action.autoLevel}
onChange={onAutolevel}
/>
<input type="checkbox" id={autolevelCheckboxId} checked={props.action.autoLevel} onChange={onAutolevel} />
</>
);
}

@ -15,11 +15,7 @@ export function OperationList(props: IProps): React.ReactElement {
<>
{names.map((name: string) => (
<li key={name} className="bladeburner-action">
<OperationElem
bladeburner={props.bladeburner}
action={operations[name]}
player={props.player}
/>
<OperationElem bladeburner={props.bladeburner} action={operations[name]} player={props.player} />
</li>
))}
</>

@ -12,23 +12,21 @@ export function OperationPage(props: IProps): React.ReactElement {
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
Carry out operations for the Bladeburner division. Failing an operation
will reduce your Bladeburner rank. It will also cause you to lose HP,
which can lead to hospitalization. In general, operations are harder and
more punishing than contracts, but are also more rewarding.
Carry out operations for the Bladeburner division. Failing an operation will reduce your Bladeburner rank. It
will also cause you to lose HP, which can lead to hospitalization. In general, operations are harder and more
punishing than contracts, but are also more rewarding.
<br />
<br />
Operations can affect the chaos level and Synthoid population of your
current city. The exact effects vary between different Operations.
Operations can affect the chaos level and Synthoid population of your current city. The exact effects vary
between different Operations.
<br />
<br />
For operations, you can use a team. You must first recruit team members.
Having a larger team will improves your chances of success.
For operations, you can use a team. You must first recruit team members. Having a larger team will improves your
chances of success.
<br />
<br />
You can unlock higher-level operations by successfully completing them.
Higher-level operations are more difficult, but grant more rank and
experience.
You can unlock higher-level operations by successfully completing them. Higher-level operations are more
difficult, but grant more rank and experience.
</p>
<OperationList bladeburner={props.bladeburner} player={props.player} />
</>

@ -25,11 +25,7 @@ export function Root(props: IProps): React.ReactElement {
border: "1px solid white",
}}
>
<Stats
bladeburner={props.bladeburner}
player={props.player}
engine={props.engine}
/>
<Stats bladeburner={props.bladeburner} player={props.player} engine={props.engine} />
</div>
<Console bladeburner={props.bladeburner} player={props.player} />
</div>

@ -12,18 +12,13 @@ interface IProps {
export function SkillElem(props: IProps): React.ReactElement {
const skillName = props.skill.name;
let currentLevel = 0;
if (
props.bladeburner.skills[skillName] &&
!isNaN(props.bladeburner.skills[skillName])
) {
if (props.bladeburner.skills[skillName] && !isNaN(props.bladeburner.skills[skillName])) {
currentLevel = props.bladeburner.skills[skillName];
}
const pointCost = props.skill.calculateCost(currentLevel);
const canLevel = props.bladeburner.skillPoints >= pointCost;
const maxLvl = props.skill.maxLvl
? currentLevel >= props.skill.maxLvl
: false;
const maxLvl = props.skill.maxLvl ? currentLevel >= props.skill.maxLvl : false;
function onClick(): void {
if (props.bladeburner.skillPoints < pointCost) return;
@ -40,9 +35,7 @@ export function SkillElem(props: IProps): React.ReactElement {
<a
onClick={onClick}
style={{ display: "inline-block", margin: "3px", padding: "3px" }}
className={
canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive"
}
className={canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive"}
>
Level
</a>
@ -52,14 +45,9 @@ export function SkillElem(props: IProps): React.ReactElement {
{maxLvl ? (
<p style={{ color: "red", display: "block" }}>MAX LEVEL</p>
) : (
<p style={{ display: "block" }}>
Skill Points required: {formatNumber(pointCost, 0)}
</p>
<p style={{ display: "block" }}>Skill Points required: {formatNumber(pointCost, 0)}</p>
)}
<p
style={{ display: "inline-block" }}
dangerouslySetInnerHTML={{ __html: props.skill.desc }}
/>
<p style={{ display: "inline-block" }} dangerouslySetInnerHTML={{ __html: props.skill.desc }} />
</>
);
}

@ -13,11 +13,7 @@ export function SkillList(props: IProps): React.ReactElement {
<>
{Object.keys(Skills).map((skill: string) => (
<li key={skill} className="bladeburner-action">
<SkillElem
bladeburner={props.bladeburner}
skill={Skills[skill]}
onUpgrade={props.onUpgrade}
/>
<SkillElem bladeburner={props.bladeburner} skill={Skills[skill]} onUpgrade={props.onUpgrade} />
</li>
))}
</>

@ -19,94 +19,46 @@ export function SkillPage(props: IProps): React.ReactElement {
return (
<>
<p>
<strong>
Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}
</strong>
<strong>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</strong>
</p>
<p>
You will gain one skill point every{" "}
{BladeburnerConstants.RanksPerSkillPoint} ranks.
You will gain one skill point every {BladeburnerConstants.RanksPerSkillPoint} ranks.
<br />
<br />
Note that when upgrading a skill, the benefit for that skill is
additive. However, the effects of different skills with each other is
multiplicative.
Note that when upgrading a skill, the benefit for that skill is additive. However, the effects of different
skills with each other is multiplicative.
<br />
</p>
<br />
{valid(mults["successChanceAll"]) && (
<p>
Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}
</p>
)}
{valid(mults["successChanceAll"]) && <p>Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}</p>}
{valid(mults["successChanceStealth"]) && (
<p>
Stealth Success Chance: x
{formatNumber(mults["successChanceStealth"], 3)}
</p>
<p>Stealth Success Chance: x{formatNumber(mults["successChanceStealth"], 3)}</p>
)}
{valid(mults["successChanceKill"]) && (
<p>
Retirement Success Chance: x
{formatNumber(mults["successChanceKill"], 3)}
</p>
<p>Retirement Success Chance: x{formatNumber(mults["successChanceKill"], 3)}</p>
)}
{valid(mults["successChanceContract"]) && (
<p>
Contract Success Chance: x
{formatNumber(mults["successChanceContract"], 3)}
</p>
<p>Contract Success Chance: x{formatNumber(mults["successChanceContract"], 3)}</p>
)}
{valid(mults["successChanceOperation"]) && (
<p>
Operation Success Chance: x
{formatNumber(mults["successChanceOperation"], 3)}
</p>
<p>Operation Success Chance: x{formatNumber(mults["successChanceOperation"], 3)}</p>
)}
{valid(mults["successChanceEstimate"]) && (
<p>
Synthoid Data Estimate: x
{formatNumber(mults["successChanceEstimate"], 3)}
</p>
)}
{valid(mults["actionTime"]) && (
<p>Action Time: x{formatNumber(mults["actionTime"], 3)}</p>
)}
{valid(mults["effHack"]) && (
<p>Hacking Skill: x{formatNumber(mults["effHack"], 3)}</p>
)}
{valid(mults["effStr"]) && (
<p>Strength: x{formatNumber(mults["effStr"], 3)}</p>
)}
{valid(mults["effDef"]) && (
<p>Defense: x{formatNumber(mults["effDef"], 3)}</p>
)}
{valid(mults["effDex"]) && (
<p>Dexterity: x{formatNumber(mults["effDex"], 3)}</p>
)}
{valid(mults["effAgi"]) && (
<p>Agility: x{formatNumber(mults["effAgi"], 3)}</p>
)}
{valid(mults["effCha"]) && (
<p>Charisma: x{formatNumber(mults["effCha"], 3)}</p>
)}
{valid(mults["effInt"]) && (
<p>Intelligence: x{formatNumber(mults["effInt"], 3)}</p>
)}
{valid(mults["stamina"]) && (
<p>Stamina: x{formatNumber(mults["stamina"], 3)}</p>
)}
{valid(mults["money"]) && (
<p>Contract Money: x{formatNumber(mults["money"], 3)}</p>
)}
{valid(mults["expGain"]) && (
<p>Exp Gain: x{formatNumber(mults["expGain"], 3)}</p>
<p>Synthoid Data Estimate: x{formatNumber(mults["successChanceEstimate"], 3)}</p>
)}
{valid(mults["actionTime"]) && <p>Action Time: x{formatNumber(mults["actionTime"], 3)}</p>}
{valid(mults["effHack"]) && <p>Hacking Skill: x{formatNumber(mults["effHack"], 3)}</p>}
{valid(mults["effStr"]) && <p>Strength: x{formatNumber(mults["effStr"], 3)}</p>}
{valid(mults["effDef"]) && <p>Defense: x{formatNumber(mults["effDef"], 3)}</p>}
{valid(mults["effDex"]) && <p>Dexterity: x{formatNumber(mults["effDex"], 3)}</p>}
{valid(mults["effAgi"]) && <p>Agility: x{formatNumber(mults["effAgi"], 3)}</p>}
{valid(mults["effCha"]) && <p>Charisma: x{formatNumber(mults["effCha"], 3)}</p>}
{valid(mults["effInt"]) && <p>Intelligence: x{formatNumber(mults["effInt"], 3)}</p>}
{valid(mults["stamina"]) && <p>Stamina: x{formatNumber(mults["stamina"], 3)}</p>}
{valid(mults["money"]) && <p>Contract Money: x{formatNumber(mults["money"], 3)}</p>}
{valid(mults["expGain"]) && <p>Exp Gain: x{formatNumber(mults["expGain"], 3)}</p>}
<br />
<SkillList
bladeburner={props.bladeburner}
onUpgrade={() => setRerender((old) => !old)}
/>
<SkillList bladeburner={props.bladeburner} onUpgrade={() => setRerender((old) => !old)} />
</>
);
}

@ -1,8 +1,5 @@
import React, { useState, useEffect } from "react";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { BladeburnerConstants } from "../data/Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IEngine } from "../../IEngine";
@ -12,10 +9,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { createPopup } from "../../ui/React/createPopup";
import { Factions } from "../../Faction/Factions";
import {
joinFaction,
displayFactionContent,
} from "../../Faction/FactionHelpers";
import { joinFaction, displayFactionContent } from "../../Faction/FactionHelpers";
import { IBladeburner } from "../IBladeburner";
import { TravelPopup } from "./TravelPopup";
@ -83,13 +77,9 @@ export function Stats(props: IProps): React.ReactElement {
} else {
if (props.bladeburner.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(faction);
dialogBoxCreate(
"Congratulations! You were accepted into the Bladeburners faction",
);
dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction");
} else {
dialogBoxCreate(
"You need a rank of 25 to join the Bladeburners Faction!",
);
dialogBoxCreate("You need a rank of 25 to join the Bladeburners Faction!");
}
}
}
@ -98,46 +88,31 @@ export function Stats(props: IProps): React.ReactElement {
<>
<p className="tooltip" style={{ display: "inline-block" }}>
Rank: {formatNumber(props.bladeburner.rank, 2)}
<span className="tooltiptext">
Your rank within the Bladeburner division.
</span>
<span className="tooltiptext">Your rank within the Bladeburner division.</span>
</p>
<br />
<p>
Stamina: {formatNumber(props.bladeburner.stamina, 3)} /{" "}
{formatNumber(props.bladeburner.maxStamina, 3)}
Stamina: {formatNumber(props.bladeburner.stamina, 3)} / {formatNumber(props.bladeburner.maxStamina, 3)}
</p>
<div className="help-tip" onClick={openStaminaHelp}>
?
</div>
<br />
<p>
Stamina Penalty:{" "}
{formatNumber(
(1 - props.bladeburner.calculateStaminaPenalty()) * 100,
1,
)}
%
</p>
<p>Stamina Penalty: {formatNumber((1 - props.bladeburner.calculateStaminaPenalty()) * 100, 1)}%</p>
<br />
<p>Team Size: {formatNumber(props.bladeburner.teamSize, 0)}</p>
<p>Team Members Lost: {formatNumber(props.bladeburner.teamLost, 0)}</p>
<br />
<p>Num Times Hospitalized: {props.bladeburner.numHosp}</p>
<p>
Money Lost From Hospitalizations:{" "}
<Money money={props.bladeburner.moneyLost} />
Money Lost From Hospitalizations: <Money money={props.bladeburner.moneyLost} />
</p>
<br />
<p>Current City: {props.bladeburner.city}</p>
<p className="tooltip" style={{ display: "inline-block" }}>
Est. Synthoid Population:{" "}
{numeralWrapper.formatPopulation(
props.bladeburner.getCurrentCity().popEst,
)}
Est. Synthoid Population: {numeralWrapper.formatPopulation(props.bladeburner.getCurrentCity().popEst)}
<span className="tooltiptext">
This is your Bladeburner division's estimate of how many Synthoids
exist in your current city.
This is your Bladeburner division's estimate of how many Synthoids exist in your current city.
</span>
</p>
<div className="help-tip" onClick={openPopulationHelp}>
@ -145,20 +120,17 @@ export function Stats(props: IProps): React.ReactElement {
</div>
<br />
<p className="tooltip" style={{ display: "inline-block" }}>
Est. Synthoid Communities:{" "}
{formatNumber(props.bladeburner.getCurrentCity().comms, 0)}
Est. Synthoid Communities: {formatNumber(props.bladeburner.getCurrentCity().comms, 0)}
<span className="tooltiptext">
This is your Bladeburner divison's estimate of how many Synthoid
communities exist in your current city.
This is your Bladeburner divison's estimate of how many Synthoid communities exist in your current city.
</span>
</p>
<br />
<p className="tooltip" style={{ display: "inline-block" }}>
City Chaos: {formatNumber(props.bladeburner.getCurrentCity().chaos)}
<span className="tooltiptext">
The city's chaos level due to tensions and conflicts between humans
and Synthoids. Having too high of a chaos level can make contracts and
operations harder.
The city's chaos level due to tensions and conflicts between humans and Synthoids. Having too high of a chaos
level can make contracts and operations harder.
</span>
</p>
<br />
@ -166,56 +138,29 @@ export function Stats(props: IProps): React.ReactElement {
<p className="tooltip" style={{ display: "inline-block" }}>
Bonus time:{" "}
{convertTimeMsToTimeElapsedString(
(props.bladeburner.storedCycles /
BladeburnerConstants.CyclesPerSecond) *
1000,
(props.bladeburner.storedCycles / BladeburnerConstants.CyclesPerSecond) * 1000,
)}
<br />
<span className="tooltiptext">
You gain bonus time while offline or when the game is inactive (e.g.
when the tab is throttled by browser). Bonus time makes the
Bladeburner mechanic progress faster, up to 5x the normal speed.
You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by browser).
Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed.
</span>
</p>
<p>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</p>
<br />
{StatsTable([
[
"Aug. Success Chance mult: ",
formatNumber(props.player.bladeburner_success_chance_mult * 100, 1) +
"%",
],
[
"Aug. Max Stamina mult: ",
formatNumber(props.player.bladeburner_max_stamina_mult * 100, 1) +
"%",
],
[
"Aug. Stamina Gain mult: ",
formatNumber(props.player.bladeburner_stamina_gain_mult * 100, 1) +
"%",
],
[
"Aug. Field Analysis mult: ",
formatNumber(props.player.bladeburner_analysis_mult * 100, 1) + "%",
],
["Aug. Success Chance mult: ", formatNumber(props.player.bladeburner_success_chance_mult * 100, 1) + "%"],
["Aug. Max Stamina mult: ", formatNumber(props.player.bladeburner_max_stamina_mult * 100, 1) + "%"],
["Aug. Stamina Gain mult: ", formatNumber(props.player.bladeburner_stamina_gain_mult * 100, 1) + "%"],
["Aug. Field Analysis mult: ", formatNumber(props.player.bladeburner_analysis_mult * 100, 1) + "%"],
])}
<br />
<a
onClick={openTravel}
className="a-link-button"
style={{ display: "inline-block" }}
>
<a onClick={openTravel} className="a-link-button" style={{ display: "inline-block" }}>
Travel
</a>
<a
onClick={openFaction}
className="a-link-button tooltip"
style={{ display: "inline-block" }}
>
<a onClick={openFaction} className="a-link-button tooltip" style={{ display: "inline-block" }}>
<span className="tooltiptext">
Apply to the Bladeburner Faction, or go to the faction page if you are
already a member
Apply to the Bladeburner Faction, or go to the faction page if you are already a member
</span>
Faction
</a>

@ -12,8 +12,7 @@ export function SuccessChance(props: IProps): React.ReactElement {
return (
<>
{formatNumber(props.chance[0] * 100, 1)}% ~{" "}
{formatNumber(props.chance[1] * 100, 1)}%
{formatNumber(props.chance[0] * 100, 1)}% ~ {formatNumber(props.chance[1] * 100, 1)}%
</>
);
}

@ -17,9 +17,7 @@ export function TeamSizePopup(props: IProps): React.ReactElement {
if (teamSize === undefined) return;
const num = Math.round(teamSize);
if (isNaN(num) || num < 0) {
dialogBoxCreate(
"Invalid value entered for number of Team Members (must be numeric, positive)",
);
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)");
} else {
props.action.teamCount = num;
}
@ -29,10 +27,8 @@ export function TeamSizePopup(props: IProps): React.ReactElement {
return (
<>
<p>
Enter the amount of team members you would like to take on this Op. If
you do not have the specified number of team members, then as many as
possible will be used. Note that team members may be lost during
operations.
Enter the amount of team members you would like to take on this Op. If you do not have the specified number of
team members, then as many as possible will be used. Note that team members may be lost during operations.
</p>
<input
autoFocus

@ -17,19 +17,14 @@ export function TravelPopup(props: IProps): React.ReactElement {
return (
<>
<p>
Travel to a different city for your Bladeburner activities. This does
not cost any money. The city you are in for your Bladeburner duties does
not affect your location in the game otherwise.
Travel to a different city for your Bladeburner activities. This does not cost any money. The city you are in
for your Bladeburner duties does not affect your location in the game otherwise.
</p>
{BladeburnerConstants.CityNames.map((city) => {
// Reusing this css class...it adds a border and makes it
// so that background color changes when you hover
return (
<div
key={city}
className="cmpy-mgmt-find-employee-option"
onClick={() => travel(city)}
>
<div key={city} className="cmpy-mgmt-find-employee-option" onClick={() => travel(city)}>
{city}
</div>
);

@ -76,14 +76,8 @@ export class Blackjack extends Game<Props, State> {
// always reload without saving but w.e)
this.props.p.loseMoney(this.state.bet);
const playerHand = new Hand([
this.deck.safeDrawCard(),
this.deck.safeDrawCard(),
]);
const dealerHand = new Hand([
this.deck.safeDrawCard(),
this.deck.safeDrawCard(),
]);
const playerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
const dealerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
this.setState({
playerHand,
@ -242,9 +236,7 @@ export class Blackjack extends Game<Props, State> {
};
isPlayerWinResult = (result: Result): boolean => {
return (
result === Result.PlayerWon || result === Result.PlayerWonByBlackjack
);
return result === Result.PlayerWon || result === Result.PlayerWonByBlackjack;
};
wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
@ -304,16 +296,8 @@ export class Blackjack extends Game<Props, State> {
};
render(): React.ReactNode {
const {
betInput,
playerHand,
dealerHand,
gameInProgress,
result,
wagerInvalid,
wagerInvalidHelperText,
gains,
} = this.state;
const { betInput, playerHand, dealerHand, gameInProgress, result, wagerInvalid, wagerInvalidHelperText, gains } =
this.state;
// Get the player totals to display.
const playerHandValues = this.getHandDisplayValues(playerHand);
@ -342,9 +326,7 @@ export class Blackjack extends Game<Props, State> {
width: "200px",
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">$</InputAdornment>
),
startAdornment: <InputAdornment position="start">$</InputAdornment>,
}}
/>
@ -357,11 +339,7 @@ export class Blackjack extends Game<Props, State> {
{/* Buttons */}
{!gameInProgress ? (
<div>
<MuiButton
color="primary"
onClick={this.startOnClick}
disabled={wagerInvalid || !this.canStartGame()}
>
<MuiButton color="primary" onClick={this.startOnClick} disabled={wagerInvalid || !this.canStartGame()}>
Start
</MuiButton>
</div>
@ -398,11 +376,7 @@ export class Blackjack extends Game<Props, State> {
<pre>Dealer</pre>
{dealerHand.cards.map((card, i) => (
// Hide every card except the first while game is in progress
<ReactCard
card={card}
hidden={gameInProgress && i !== 0}
key={i}
/>
<ReactCard card={card} hidden={gameInProgress && i !== 0} key={i} />
))}
{!gameInProgress && (

@ -91,23 +91,10 @@ export class CoinFlip extends Game<IProps, IState> {
<pre>{`| | | |`}</pre>
<pre>{`+———————+`}</pre>
<span className="text">Play for: </span>
<input
type="number"
className="text-input"
onChange={this.updateInvestment}
value={this.state.investment}
/>
<input type="number" className="text-input" onChange={this.updateInvestment} value={this.state.investment} />
<br />
<StdButton
onClick={trusted(() => this.play("H"))}
text={"Head!"}
disabled={this.state.playLock}
/>
<StdButton
onClick={trusted(() => this.play("T"))}
text={"Tail!"}
disabled={this.state.playLock}
/>
<StdButton onClick={trusted(() => this.play("H"))} text={"Head!"} disabled={this.state.playLock} />
<StdButton onClick={trusted(() => this.play("T"))} text={"Tail!"} disabled={this.state.playLock} />
<h1>{this.state.status}</h1>
</>
);

@ -13,9 +13,7 @@ export class Game<T, U> extends React.Component<T, U> {
reachedLimit(p: IPlayer): boolean {
const reached = p.getCasinoWinnings() > gainLimit;
if (reached) {
dialogBoxCreate(
<>Alright cheater get out of here. You're not allowed here anymore.</>,
);
dialogBoxCreate(<>Alright cheater get out of here. You're not allowed here anymore.</>);
}
return reached;
}

@ -24,9 +24,7 @@ const minPlay = 0;
const maxPlay = 1e7;
function isRed(n: number): boolean {
return [
1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36,
].includes(n);
return [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36].includes(n);
}
type Strategy = {
@ -34,9 +32,7 @@ type Strategy = {
payout: number;
};
const redNumbers: number[] = [
1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36,
];
const redNumbers: number[] = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
const strategies: {
Red: Strategy;
@ -246,260 +242,116 @@ export class Roulette extends Game<IProps, IState> {
<tbody>
<tr>
<td>
<StdButton
text={"3"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(3)))}
/>
<StdButton text={"3"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(3)))} />
</td>
<td>
<StdButton
text={"6"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(6)))}
/>
<StdButton text={"6"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(6)))} />
</td>
<td>
<StdButton
text={"9"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(9)))}
/>
<StdButton text={"9"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(9)))} />
</td>
<td>
<StdButton
text={"12"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(12)))}
/>
<StdButton text={"12"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(12)))} />
</td>
<td>
<StdButton
text={"15"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(15)))}
/>
<StdButton text={"15"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(15)))} />
</td>
<td>
<StdButton
text={"18"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(18)))}
/>
<StdButton text={"18"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(18)))} />
</td>
<td>
<StdButton
text={"21"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(21)))}
/>
<StdButton text={"21"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(21)))} />
</td>
<td>
<StdButton
text={"24"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(24)))}
/>
<StdButton text={"24"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(24)))} />
</td>
<td>
<StdButton
text={"27"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(27)))}
/>
<StdButton text={"27"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(27)))} />
</td>
<td>
<StdButton
text={"30"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(30)))}
/>
<StdButton text={"30"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(30)))} />
</td>
<td>
<StdButton
text={"33"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(33)))}
/>
<StdButton text={"33"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(33)))} />
</td>
<td>
<StdButton
text={"36"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(36)))}
/>
<StdButton text={"36"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(36)))} />
</td>
</tr>
<tr>
<td>
<StdButton
text={"2"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(2)))}
/>
<StdButton text={"2"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(2)))} />
</td>
<td>
<StdButton
text={"5"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(5)))}
/>
<StdButton text={"5"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(5)))} />
</td>
<td>
<StdButton
text={"8"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(8)))}
/>
<StdButton text={"8"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(8)))} />
</td>
<td>
<StdButton
text={"11"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(11)))}
/>
<StdButton text={"11"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(11)))} />
</td>
<td>
<StdButton
text={"14"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(14)))}
/>
<StdButton text={"14"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(14)))} />
</td>
<td>
<StdButton
text={"17"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(17)))}
/>
<StdButton text={"17"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(17)))} />
</td>
<td>
<StdButton
text={"20"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(20)))}
/>
<StdButton text={"20"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(20)))} />
</td>
<td>
<StdButton
text={"23"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(23)))}
/>
<StdButton text={"23"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(23)))} />
</td>
<td>
<StdButton
text={"26"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(26)))}
/>
<StdButton text={"26"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(26)))} />
</td>
<td>
<StdButton
text={"29"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(29)))}
/>
<StdButton text={"29"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(29)))} />
</td>
<td>
<StdButton
text={"32"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(32)))}
/>
<StdButton text={"32"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(32)))} />
</td>
<td>
<StdButton
text={"35"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(35)))}
/>
<StdButton text={"35"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(35)))} />
</td>
</tr>
<tr>
<td>
<StdButton
text={"1"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(1)))}
/>
<StdButton text={"1"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(1)))} />
</td>
<td>
<StdButton
text={"4"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(4)))}
/>
<StdButton text={"4"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(4)))} />
</td>
<td>
<StdButton
text={"7"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(7)))}
/>
<StdButton text={"7"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(7)))} />
</td>
<td>
<StdButton
text={"10"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(10)))}
/>
<StdButton text={"10"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(10)))} />
</td>
<td>
<StdButton
text={"13"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(13)))}
/>
<StdButton text={"13"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(13)))} />
</td>
<td>
<StdButton
text={"16"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(16)))}
/>
<StdButton text={"16"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(16)))} />
</td>
<td>
<StdButton
text={"19"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(19)))}
/>
<StdButton text={"19"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(19)))} />
</td>
<td>
<StdButton
text={"22"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(22)))}
/>
<StdButton text={"22"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(22)))} />
</td>
<td>
<StdButton
text={"25"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(25)))}
/>
<StdButton text={"25"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(25)))} />
</td>
<td>
<StdButton
text={"28"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(28)))}
/>
<StdButton text={"28"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(28)))} />
</td>
<td>
<StdButton
text={"31"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(31)))}
/>
<StdButton text={"31"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(31)))} />
</td>
<td>
<StdButton
text={"34"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(34)))}
/>
<StdButton text={"34"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(34)))} />
</td>
</tr>
<tr>
@ -571,11 +423,7 @@ export class Roulette extends Game<IProps, IState> {
</tr>
<tr>
<td>
<StdButton
text={"0"}
disabled={!this.state.canPlay}
onClick={trusted(() => this.play(Single(0)))}
/>
<StdButton text={"0"} disabled={!this.state.canPlay} onClick={trusted(() => this.play(Single(0)))} />
</td>
</tr>
</tbody>

@ -1,8 +1,6 @@
import * as React from "react";
export function trusted(
f: () => void,
): (event: React.MouseEvent<HTMLElement, MouseEvent>) => any {
export function trusted(f: () => void): (event: React.MouseEvent<HTMLElement, MouseEvent>) => any {
return function (event: React.MouseEvent<HTMLElement, MouseEvent>): any {
if (!event.isTrusted) return;
f();

@ -18,9 +18,7 @@ export function writeCinematicText(lines) {
cinematicTextFlag = true;
if (lines.constructor !== Array) {
throw new Error(
"Invalid non-array argument passed into writeCinematicText()",
);
throw new Error("Invalid non-array argument passed into writeCinematicText()");
}
// Reuse the 'Red Pill' content
@ -28,17 +26,13 @@ export function writeCinematicText(lines) {
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()",
);
throw new Error("Could not find cinematic-text-container for writeCinematicText()");
}
removeChildrenFromElement(container);
for (let i = 0; i < lines.length; ++i) {
if (!isString(lines[i])) {
throw new Error(
"Invalid non-string element in 'lines' argument. writeCinematicText() failed",
);
throw new Error("Invalid non-string element in 'lines' argument. writeCinematicText() failed");
}
}
@ -88,8 +82,7 @@ function writeCinematicTextLetter(pElem, line, i = 0) {
return resolve(true);
}
pElem.innerHTML =
textToShow + "<span class='typed-cursor'> &#9608; </span>";
pElem.innerHTML = textToShow + "<span class='typed-cursor'> &#9608; </span>";
const promise = writeCinematicTextLetter(pElem, line, i + 1);
promise.then(
function (res) {

@ -92,37 +92,24 @@ export function generateContract(params: IGenerateContractParams): void {
}
// Ensures that a contract's reward type is valid
function sanitizeRewardType(
rewardType: CodingContractRewardType,
): CodingContractRewardType {
function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContractRewardType {
let type = rewardType; // Create copy
const factionsThatAllowHacking = Player.factions.filter((fac) => {
try {
return Factions[fac].getInfo().offerHackingWork;
} catch (e) {
console.error(
`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`,
);
console.error(`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`);
return false;
}
});
if (
type === CodingContractRewardType.FactionReputation &&
factionsThatAllowHacking.length === 0
) {
if (type === CodingContractRewardType.FactionReputation && factionsThatAllowHacking.length === 0) {
type = CodingContractRewardType.CompanyReputation;
}
if (
type === CodingContractRewardType.FactionReputationAll &&
factionsThatAllowHacking.length === 0
) {
if (type === CodingContractRewardType.FactionReputationAll && factionsThatAllowHacking.length === 0) {
type = CodingContractRewardType.CompanyReputation;
}
if (
type === CodingContractRewardType.CompanyReputation &&
Object.keys(Player.jobs).length === 0
) {
if (type === CodingContractRewardType.CompanyReputation && Object.keys(Player.jobs).length === 0) {
type = CodingContractRewardType.Money;
}
@ -148,9 +135,7 @@ function getRandomReward(): ICodingContractReward {
try {
return Factions[fac].getInfo().offerHackingWork;
} catch (e) {
console.error(
`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`,
);
console.error(`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`);
return false;
}
});
@ -160,8 +145,7 @@ function getRandomReward(): ICodingContractReward {
// Get a random faction that player is a part of. That
// faction must allow hacking contracts
const numFactions = factionsThatAllowHacking.length;
const randFaction =
factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
reward.name = randFaction;
break;
}
@ -203,10 +187,7 @@ function getRandomServer(): Server | HacknetServer {
return randServer;
}
function getRandomFilename(
server: Server | HacknetServer,
reward: ICodingContractReward,
): string {
function getRandomFilename(server: Server | HacknetServer, reward: ICodingContractReward): string {
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
for (let i = 0; i < 1000; ++i) {

@ -1,17 +1,8 @@
import {
codingContractTypesMetadata,
DescriptionFunc,
GeneratorFunc,
SolverFunc,
} from "./data/codingcontracttypes";
import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes";
import { IMap } from "./types";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { createPopup, removePopup } from "./ui/React/createPopup";
import { CodingContractPopup } from "./ui/React/CodingContractPopup";
@ -131,11 +122,7 @@ export class CodingContract {
/* String representing the contract's type. Must match type in ContractTypes */
type: string;
constructor(
fn = "",
type = "Find Largest Prime Factor",
reward: ICodingContractReward | null = null,
) {
constructor(fn = "", type = "Find Largest Prime Factor", reward: ICodingContractReward | null = null) {
this.fn = fn;
if (!this.fn.endsWith(".cct")) {
this.fn += ".cct";
@ -143,9 +130,7 @@ export class CodingContract {
// tslint:disable-next-line
if (CodingContractTypes[type] == null) {
throw new Error(
`Error: invalid contract type: ${type} please contact developer`,
);
throw new Error(`Error: invalid contract type: ${type} please contact developer`);
}
this.type = type;

@ -4,11 +4,7 @@ import * as posNames from "./data/companypositionnames";
import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
export interface IConstructorParams {
name: string;
@ -98,10 +94,7 @@ export class Company {
}
hasBusinessConsultantPositions(): boolean {
return (
this.companyPositions[posNames.BusinessConsultantCompanyPositions[0]] !=
null
);
return this.companyPositions[posNames.BusinessConsultantCompanyPositions[0]] != null;
}
hasBusinessPositions(): boolean {
@ -121,10 +114,7 @@ export class Company {
}
hasSoftwareConsultantPositions(): boolean {
return (
this.companyPositions[posNames.SoftwareConsultantCompanyPositions[0]] !=
null
);
return this.companyPositions[posNames.SoftwareConsultantCompanyPositions[0]] != null;
}
hasSoftwarePositions(): boolean {
@ -161,9 +151,7 @@ export class Company {
}
let favorGain = 0,
rep = this.playerReputation + this.rolloverRep;
let reqdRep =
CONSTANTS.CompanyReputationToFavorBase *
Math.pow(CONSTANTS.CompanyReputationToFavorMult, this.favor);
let reqdRep = CONSTANTS.CompanyReputationToFavorBase * Math.pow(CONSTANTS.CompanyReputationToFavorMult, this.favor);
while (rep > 0) {
if (rep >= reqdRep) {
++favorGain;

@ -103,18 +103,12 @@ export class CompanyPosition {
this.requiredCharisma = p.reqdCharisma != null ? p.reqdCharisma : 0;
this.requiredReputation = p.reqdReputation != null ? p.reqdReputation : 0;
this.hackingEffectiveness =
p.hackingEffectiveness != null ? p.hackingEffectiveness : 0;
this.strengthEffectiveness =
p.strengthEffectiveness != null ? p.strengthEffectiveness : 0;
this.defenseEffectiveness =
p.defenseEffectiveness != null ? p.defenseEffectiveness : 0;
this.dexterityEffectiveness =
p.dexterityEffectiveness != null ? p.dexterityEffectiveness : 0;
this.agilityEffectiveness =
p.agilityEffectiveness != null ? p.agilityEffectiveness : 0;
this.charismaEffectiveness =
p.charismaEffectiveness != null ? p.charismaEffectiveness : 0;
this.hackingEffectiveness = p.hackingEffectiveness != null ? p.hackingEffectiveness : 0;
this.strengthEffectiveness = p.strengthEffectiveness != null ? p.strengthEffectiveness : 0;
this.defenseEffectiveness = p.defenseEffectiveness != null ? p.defenseEffectiveness : 0;
this.dexterityEffectiveness = p.dexterityEffectiveness != null ? p.dexterityEffectiveness : 0;
this.agilityEffectiveness = p.agilityEffectiveness != null ? p.agilityEffectiveness : 0;
this.charismaEffectiveness = p.charismaEffectiveness != null ? p.charismaEffectiveness : 0;
if (
Math.round(
@ -126,9 +120,7 @@ export class CompanyPosition {
this.charismaEffectiveness,
) !== 100
) {
console.error(
`CompanyPosition ${this.name} parameters do not sum to 100`,
);
console.error(`CompanyPosition ${this.name} parameters do not sum to 100`);
}
this.hackingExpGain = p.hackingExpGain != null ? p.hackingExpGain : 0;
@ -139,31 +131,16 @@ export class CompanyPosition {
this.charismaExpGain = p.charismaExpGain != null ? p.charismaExpGain : 0;
}
calculateJobPerformance(
hack: number,
str: number,
def: number,
dex: number,
agi: number,
cha: number,
): number {
const hackRatio: number =
(this.hackingEffectiveness * hack) / CONSTANTS.MaxSkillLevel;
const strRatio: number =
(this.strengthEffectiveness * str) / CONSTANTS.MaxSkillLevel;
const defRatio: number =
(this.defenseEffectiveness * def) / CONSTANTS.MaxSkillLevel;
const dexRatio: number =
(this.dexterityEffectiveness * dex) / CONSTANTS.MaxSkillLevel;
const agiRatio: number =
(this.agilityEffectiveness * agi) / CONSTANTS.MaxSkillLevel;
const chaRatio: number =
(this.charismaEffectiveness * cha) / CONSTANTS.MaxSkillLevel;
calculateJobPerformance(hack: number, str: number, def: number, dex: number, agi: number, cha: number): number {
const hackRatio: number = (this.hackingEffectiveness * hack) / CONSTANTS.MaxSkillLevel;
const strRatio: number = (this.strengthEffectiveness * str) / CONSTANTS.MaxSkillLevel;
const defRatio: number = (this.defenseEffectiveness * def) / CONSTANTS.MaxSkillLevel;
const dexRatio: number = (this.dexterityEffectiveness * dex) / CONSTANTS.MaxSkillLevel;
const agiRatio: number = (this.agilityEffectiveness * agi) / CONSTANTS.MaxSkillLevel;
const chaRatio: number = (this.charismaEffectiveness * cha) / CONSTANTS.MaxSkillLevel;
let reputationGain: number =
(this.repMultiplier *
(hackRatio + strRatio + defRatio + dexRatio + agiRatio + chaRatio)) /
100;
(this.repMultiplier * (hackRatio + strRatio + defRatio + dexRatio + agiRatio + chaRatio)) / 100;
if (isNaN(reputationGain)) {
console.error("Company reputation gain calculated to be NaN");
reputationGain = 0;

@ -5,25 +5,15 @@ import { CompanyPosition } from "./CompanyPosition";
* Returns a string with the given CompanyPosition's stat requirements
*/
export function getJobRequirementText(
company: Company,
pos: CompanyPosition,
tooltiptext = false,
): string {
export function getJobRequirementText(company: Company, pos: CompanyPosition, tooltiptext = false): string {
let reqText = "";
const offset: number = company.jobStatReqOffset;
const reqHacking: number =
pos.requiredHacking > 0 ? pos.requiredHacking + offset : 0;
const reqStrength: number =
pos.requiredStrength > 0 ? pos.requiredStrength + offset : 0;
const reqDefense: number =
pos.requiredDefense > 0 ? pos.requiredDefense + offset : 0;
const reqDexterity: number =
pos.requiredDexterity > 0 ? pos.requiredDexterity + offset : 0;
const reqAgility: number =
pos.requiredDexterity > 0 ? pos.requiredDexterity + offset : 0;
const reqCharisma: number =
pos.requiredCharisma > 0 ? pos.requiredCharisma + offset : 0;
const reqHacking: number = pos.requiredHacking > 0 ? pos.requiredHacking + offset : 0;
const reqStrength: number = pos.requiredStrength > 0 ? pos.requiredStrength + offset : 0;
const reqDefense: number = pos.requiredDefense > 0 ? pos.requiredDefense + offset : 0;
const reqDexterity: number = pos.requiredDexterity > 0 ? pos.requiredDexterity + offset : 0;
const reqAgility: number = pos.requiredDexterity > 0 ? pos.requiredDexterity + offset : 0;
const reqCharisma: number = pos.requiredCharisma > 0 ? pos.requiredCharisma + offset : 0;
const reqRep: number = pos.requiredReputation;
if (tooltiptext) {
reqText = "Requires:<br>";

@ -3,9 +3,7 @@
import { CompanyPosition } from "./CompanyPosition";
import { CompanyPositions } from "./CompanyPositions";
export function getNextCompanyPositionHelper(
currPos: CompanyPosition | null,
): CompanyPosition | null {
export function getNextCompanyPositionHelper(currPos: CompanyPosition | null): CompanyPosition | null {
if (currPos == null) {
return null;
}

@ -92,12 +92,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumECorp,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 3,
salaryMultiplier: 3,
jobStatReqOffset: 249,
@ -105,12 +100,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.Sector12MegaCorp,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 3,
salaryMultiplier: 3,
jobStatReqOffset: 249,
@ -118,12 +108,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumBachmanAndAssociates,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.6,
salaryMultiplier: 2.6,
jobStatReqOffset: 224,
@ -131,12 +116,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.Sector12BladeIndustries,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.75,
salaryMultiplier: 2.75,
jobStatReqOffset: 224,
@ -144,12 +124,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.VolhavenNWO,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.75,
salaryMultiplier: 2.75,
jobStatReqOffset: 249,
@ -157,12 +132,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumClarkeIncorporated,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.25,
salaryMultiplier: 2.25,
jobStatReqOffset: 224,
@ -170,12 +140,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.VolhavenOmniTekIncorporated,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.25,
salaryMultiplier: 2.25,
jobStatReqOffset: 224,
@ -183,12 +148,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.Sector12FourSigma,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.5,
salaryMultiplier: 2.5,
jobStatReqOffset: 224,
@ -196,12 +156,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.ChongqingKuaiGongInternational,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSecurityPositions),
expMultiplier: 2.2,
salaryMultiplier: 2.2,
jobStatReqOffset: 224,
@ -209,11 +164,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumFulcrumTechnologies,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions),
expMultiplier: 2,
salaryMultiplier: 2,
jobStatReqOffset: 224,
@ -221,12 +172,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.IshimaStormTechnologies,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllSoftwareConsultantPositions,
AllBusinessPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllSoftwareConsultantPositions, AllBusinessPositions),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 199,
@ -234,12 +180,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.NewTokyoDefComm,
info: "",
companyPositions: Object.assign(
{},
CEOOnly,
AllTechnologyPositions,
AllSoftwareConsultantPositions,
),
companyPositions: Object.assign({}, CEOOnly, AllTechnologyPositions, AllSoftwareConsultantPositions),
expMultiplier: 1.75,
salaryMultiplier: 1.75,
jobStatReqOffset: 199,
@ -247,12 +188,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.VolhavenHeliosLabs,
info: "",
companyPositions: Object.assign(
{},
CEOOnly,
AllTechnologyPositions,
AllSoftwareConsultantPositions,
),
companyPositions: Object.assign({}, CEOOnly, AllTechnologyPositions, AllSoftwareConsultantPositions),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 199,
@ -260,12 +196,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.NewTokyoVitaLife,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSoftwareConsultantPositions),
expMultiplier: 1.8,
salaryMultiplier: 1.8,
jobStatReqOffset: 199,
@ -273,12 +204,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.Sector12IcarusMicrosystems,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSoftwareConsultantPositions),
expMultiplier: 1.9,
salaryMultiplier: 1.9,
jobStatReqOffset: 199,
@ -286,12 +212,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.Sector12UniversalEnergy,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSoftwareConsultantPositions),
expMultiplier: 2,
salaryMultiplier: 2,
jobStatReqOffset: 199,
@ -299,12 +220,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumGalacticCybersystems,
info: "",
companyPositions: Object.assign(
{},
AllTechnologyPositions,
AllBusinessPositions,
AllSoftwareConsultantPositions,
),
companyPositions: Object.assign({}, AllTechnologyPositions, AllBusinessPositions, AllSoftwareConsultantPositions),
expMultiplier: 1.9,
salaryMultiplier: 1.9,
jobStatReqOffset: 199,
@ -312,13 +228,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumAeroCorp,
info: "",
companyPositions: Object.assign(
{},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, CEOOnly, OperationsManagerOnly, AllTechnologyPositions, AllSecurityPositions),
expMultiplier: 1.7,
salaryMultiplier: 1.7,
jobStatReqOffset: 199,
@ -326,13 +236,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.VolhavenOmniaCybersystems,
info: "",
companyPositions: Object.assign(
{},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, CEOOnly, OperationsManagerOnly, AllTechnologyPositions, AllSecurityPositions),
expMultiplier: 1.7,
salaryMultiplier: 1.7,
jobStatReqOffset: 199,
@ -340,13 +244,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.ChongqingSolarisSpaceSystems,
info: "",
companyPositions: Object.assign(
{},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, CEOOnly, OperationsManagerOnly, AllTechnologyPositions, AllSecurityPositions),
expMultiplier: 1.7,
salaryMultiplier: 1.7,
jobStatReqOffset: 199,
@ -354,13 +252,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.Sector12DeltaOne,
info: "",
companyPositions: Object.assign(
{},
CEOOnly,
OperationsManagerOnly,
AllTechnologyPositions,
AllSecurityPositions,
),
companyPositions: Object.assign({}, CEOOnly, OperationsManagerOnly, AllTechnologyPositions, AllSecurityPositions),
expMultiplier: 1.6,
salaryMultiplier: 1.6,
jobStatReqOffset: 199,
@ -458,11 +350,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumRhoConstruction,
info: "",
companyPositions: Object.assign(
{},
SoftwarePositionsUpToLeadDeveloper,
BusinessPositionsUpToOperationsManager,
),
companyPositions: Object.assign({}, SoftwarePositionsUpToLeadDeveloper, BusinessPositionsUpToOperationsManager),
expMultiplier: 1.3,
salaryMultiplier: 1.3,
jobStatReqOffset: 49,
@ -483,11 +371,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.AevumPolice,
info: "",
companyPositions: Object.assign(
{},
AllSecurityPositions,
SoftwarePositionsUpToLeadDeveloper,
),
companyPositions: Object.assign({}, AllSecurityPositions, SoftwarePositionsUpToLeadDeveloper),
expMultiplier: 1.3,
salaryMultiplier: 1.3,
jobStatReqOffset: 99,
@ -549,12 +433,7 @@ export const companiesMetadata: IConstructorParams[] = [
{
name: LocationName.IshimaOmegaSoftware,
info: "",
companyPositions: Object.assign(
{},
AllSoftwarePositions,
AllSoftwareConsultantPositions,
AllITPositions,
),
companyPositions: Object.assign({}, AllSoftwarePositions, AllSoftwareConsultantPositions, AllITPositions),
expMultiplier: 1.1,
salaryMultiplier: 1.1,
jobStatReqOffset: 49,

@ -11,19 +11,11 @@ export const SoftwareCompanyPositions: string[] = [
"Chief Technology Officer",
];
export const ITCompanyPositions: string[] = [
"IT Intern",
"IT Analyst",
"IT Manager",
"Systems Administrator",
];
export const ITCompanyPositions: string[] = ["IT Intern", "IT Analyst", "IT Manager", "Systems Administrator"];
export const SecurityEngineerCompanyPositions: string[] = ["Security Engineer"];
export const NetworkEngineerCompanyPositions: string[] = [
"Network Engineer",
"Network Administrator",
];
export const NetworkEngineerCompanyPositions: string[] = ["Network Engineer", "Network Administrator"];
export const BusinessCompanyPositions: string[] = [
"Business Intern",
@ -43,25 +35,12 @@ export const SecurityCompanyPositions: string[] = [
"Head of Security",
];
export const AgentCompanyPositions: string[] = [
"Field Agent",
"Secret Agent",
"Special Operative",
];
export const AgentCompanyPositions: string[] = ["Field Agent", "Secret Agent", "Special Operative"];
export const MiscCompanyPositions: string[] = ["Waiter", "Employee"];
export const SoftwareConsultantCompanyPositions: string[] = [
"Software Consultant",
"Senior Software Consultant",
];
export const SoftwareConsultantCompanyPositions: string[] = ["Software Consultant", "Senior Software Consultant"];
export const BusinessConsultantCompanyPositions: string[] = [
"Business Consultant",
"Senior Business Consultant",
];
export const BusinessConsultantCompanyPositions: string[] = ["Business Consultant", "Senior Business Consultant"];
export const PartTimeCompanyPositions: string[] = [
"Part-time Waiter",
"Part-time Employee",
];
export const PartTimeCompanyPositions: string[] = ["Part-time Waiter", "Part-time Employee"];

@ -11,11 +11,7 @@ import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrade } from "./data/CorporationUpgrades";
import { Cities } from "../Locations/Cities";
export function NewIndustry(
corporation: ICorporation,
industry: string,
name: string,
): void {
export function NewIndustry(corporation: ICorporation, industry: string, name: string): void {
for (let i = 0; i < corporation.divisions.length; ++i) {
if (corporation.divisions[i].name === name) {
throw new Error("This division name is already in use!");
@ -28,9 +24,7 @@ export function NewIndustry(
throw new Error(`Invalid industry: '${industry}'`);
}
if (corporation.funds.lt(cost)) {
throw new Error(
"Not enough money to create a new division in this industry",
);
throw new Error("Not enough money to create a new division in this industry");
} else if (name === "") {
throw new Error("New division must have a name!");
} else {
@ -45,19 +39,11 @@ export function NewIndustry(
}
}
export function NewCity(
corporation: ICorporation,
division: IIndustry,
city: string,
): void {
export function NewCity(corporation: ICorporation, division: IIndustry, city: string): void {
if (corporation.funds.lt(CorporationConstants.OfficeInitialCost)) {
throw new Error(
"You don't have enough company funds to open a new office!",
);
throw new Error("You don't have enough company funds to open a new office!");
} else {
corporation.funds = corporation.funds.minus(
CorporationConstants.OfficeInitialCost,
);
corporation.funds = corporation.funds.minus(CorporationConstants.OfficeInitialCost);
division.offices[city] = new OfficeSpace({
loc: city,
size: CorporationConstants.OfficeInitialSize,
@ -65,20 +51,14 @@ export function NewCity(
}
}
export function UnlockUpgrade(
corporation: ICorporation,
upgrade: CorporationUnlockUpgrade,
): void {
export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnlockUpgrade): void {
if (corporation.funds.lt(upgrade[1])) {
throw new Error("Insufficient funds");
}
corporation.unlock(upgrade);
}
export function LevelUpgrade(
corporation: ICorporation,
upgrade: CorporationUpgrade,
): void {
export function LevelUpgrade(corporation: ICorporation, upgrade: CorporationUpgrade): void {
const baseCost = upgrade[1];
const priceMult = upgrade[2];
const level = corporation.upgrades[upgrade[0]];
@ -90,18 +70,9 @@ export function LevelUpgrade(
}
}
export function IssueDividends(
corporation: ICorporation,
percent: number,
): void {
if (
isNaN(percent) ||
percent < 0 ||
percent > CorporationConstants.DividendMaxPercentage
) {
throw new Error(
`Invalid value. Must be an integer between 0 and ${CorporationConstants.DividendMaxPercentage}`,
);
export function IssueDividends(corporation: ICorporation, percent: number): void {
if (isNaN(percent) || percent < 0 || percent > CorporationConstants.DividendMaxPercentage) {
throw new Error(`Invalid value. Must be an integer between 0 and ${CorporationConstants.DividendMaxPercentage}`);
}
corporation.dividendPercentage = percent * 100;
@ -148,9 +119,7 @@ export function SellMaterial(mat: Material, amt: string, price: string): void {
mat.sllman[0] = true;
mat.sllman[1] = q; //Use sanitized input
} else if (isNaN(parseFloat(amt))) {
throw new Error(
"Invalid value for sell quantity field! Must be numeric or 'MAX'",
);
throw new Error("Invalid value for sell quantity field! Must be numeric or 'MAX'");
} else {
let q = parseFloat(amt);
if (isNaN(q)) {
@ -166,13 +135,7 @@ export function SellMaterial(mat: Material, amt: string, price: string): void {
}
}
export function SellProduct(
product: Product,
city: string,
amt: string,
price: string,
all: boolean,
): void {
export function SellProduct(product: Product, city: string, amt: string, price: string, all: boolean): void {
//Parse price
if (price.includes("MP")) {
//Dynamically evaluated quantity. First test to make sure its valid
@ -183,9 +146,7 @@ export function SellProduct(
try {
temp = eval(temp);
} catch (e) {
throw new Error(
"Invalid value or expression for sell quantity field: " + e,
);
throw new Error("Invalid value or expression for sell quantity field: " + e);
}
if (temp == null || isNaN(parseFloat(temp))) {
throw new Error("Invalid value or expression for sell quantity field.");
@ -261,18 +222,13 @@ export function SellProduct(
}
}
export function SetSmartSupply(
warehouse: Warehouse,
smartSupply: boolean,
): void {
export function SetSmartSupply(warehouse: Warehouse, smartSupply: boolean): void {
warehouse.smartSupplyEnabled = smartSupply;
}
export function BuyMaterial(material: Material, amt: number): void {
if (isNaN(amt)) {
throw new Error(
`Invalid amount '${amt}' to buy material '${material.name}'`,
);
throw new Error(`Invalid amount '${amt}' to buy material '${material.name}'`);
}
material.buy = amt;
}

@ -1,12 +1,6 @@
import { CorporationState } from "./CorporationState";
import {
CorporationUnlockUpgrade,
CorporationUnlockUpgrades,
} from "./data/CorporationUnlockUpgrades";
import {
CorporationUpgrade,
CorporationUpgrades,
} from "./data/CorporationUpgrades";
import { CorporationUnlockUpgrade, CorporationUnlockUpgrades } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrade, CorporationUpgrades } from "./data/CorporationUpgrades";
import { Warehouse } from "./Warehouse";
import { CorporationConstants } from "./data/Constants";
import { Industry } from "./Industry";
@ -19,11 +13,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { Page, routing } from "../ui/navigationTracking";
import { dialogBoxCreate } from "../../utils/DialogBox";
import {
Reviver,
Generic_toJSON,
Generic_fromJSON,
} from "../../utils/JSONReviver";
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../../utils/JSONReviver";
import { createElement } from "../../utils/uiHelpers/createElement";
import { isString } from "../../utils/helpers/isString";
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
@ -81,9 +71,7 @@ export class Corporation {
addFunds(amt: number): void {
if (!isFinite(amt)) {
console.error(
"Trying to add invalid amount of funds. Report to a developper.",
);
console.error("Trying to add invalid amount of funds. Report to a developper.");
return;
}
this.funds = this.funds.plus(amt);
@ -101,8 +89,7 @@ export class Corporation {
if (this.storedCycles >= CorporationConstants.CyclesPerIndustryStateCycle) {
const state = this.getState();
const marketCycles = 1;
const gameCycles =
marketCycles * CorporationConstants.CyclesPerIndustryStateCycle;
const gameCycles = marketCycles * CorporationConstants.CyclesPerIndustryStateCycle;
this.storedCycles -= gameCycles;
this.divisions.forEach((ind) => {
@ -122,30 +109,18 @@ export class Corporation {
this.revenue = new Decimal(0);
this.expenses = new Decimal(0);
this.divisions.forEach((ind) => {
if (
ind.lastCycleRevenue === -Infinity ||
ind.lastCycleRevenue === Infinity
) {
if (ind.lastCycleRevenue === -Infinity || ind.lastCycleRevenue === Infinity) {
return;
}
if (
ind.lastCycleExpenses === -Infinity ||
ind.lastCycleExpenses === Infinity
) {
if (ind.lastCycleExpenses === -Infinity || ind.lastCycleExpenses === Infinity) {
return;
}
this.revenue = this.revenue.plus(ind.lastCycleRevenue);
this.expenses = this.expenses.plus(ind.lastCycleExpenses);
});
const profit = this.revenue.minus(this.expenses);
const cycleProfit = profit.times(
marketCycles * CorporationConstants.SecsPerMarketCycle,
);
if (
isNaN(this.funds) ||
this.funds === Infinity ||
this.funds === -Infinity
) {
const cycleProfit = profit.times(marketCycles * CorporationConstants.SecsPerMarketCycle);
if (isNaN(this.funds) || this.funds === Infinity || this.funds === -Infinity) {
dialogBoxCreate(
"There was an error calculating your Corporations funds and they got reset to 0. " +
"This is a bug. Please report to game developer.<br><br>" +
@ -160,21 +135,14 @@ export class Corporation {
if (
isNaN(this.dividendPercentage) ||
this.dividendPercentage < 0 ||
this.dividendPercentage >
CorporationConstants.DividendMaxPercentage * 100
this.dividendPercentage > CorporationConstants.DividendMaxPercentage * 100
) {
console.error(
`Invalid Corporation dividend percentage: ${this.dividendPercentage}`,
);
console.error(`Invalid Corporation dividend percentage: ${this.dividendPercentage}`);
} else {
const totalDividends =
(this.dividendPercentage / 100) * cycleProfit;
const totalDividends = (this.dividendPercentage / 100) * cycleProfit;
const retainedEarnings = cycleProfit - totalDividends;
const dividendsPerShare = totalDividends / this.totalShares;
const profit =
this.numShares *
dividendsPerShare *
(1 - this.dividendTaxPercentage / 100);
const profit = this.numShares * dividendsPerShare * (1 - this.dividendTaxPercentage / 100);
player.gainMoney(profit);
player.recordMoneySource(profit, "corporation");
this.addFunds(retainedEarnings);
@ -220,9 +188,7 @@ export class Corporation {
getTargetSharePrice(): number {
// Note: totalShares - numShares is not the same as issuedShares because
// issuedShares does not account for private investors
return (
this.determineValuation() / (2 * (this.totalShares - this.numShares) + 1)
);
return this.determineValuation() / (2 * (this.totalShares - this.numShares) + 1);
}
updateSharePrice(): void {
@ -251,9 +217,7 @@ export class Corporation {
let sharesSold = 0;
let profit = 0;
const maxIterations = Math.ceil(
numShares / CorporationConstants.SHARESPERPRICEUPDATE,
);
const maxIterations = Math.ceil(numShares / CorporationConstants.SHARESPERPRICEUPDATE);
if (isNaN(maxIterations) || maxIterations > 10e6) {
console.error(
`Something went wrong or unexpected when calculating share sale. Maxiterations calculated to be ${maxIterations}`,
@ -273,9 +237,7 @@ export class Corporation {
sharesSold += sharesUntilUpdate;
// Calculate what new share price would be
sharePrice =
this.determineValuation() /
(2 * (this.totalShares + sharesSold - this.numShares));
sharePrice = this.determineValuation() / (2 * (this.totalShares + sharesSold - this.numShares));
}
}
@ -350,10 +312,7 @@ export class Corporation {
for (const city in industry.warehouses) {
const warehouse = industry.warehouses[city];
if (warehouse === 0) continue;
if (
industry.warehouses.hasOwnProperty(city) &&
warehouse instanceof Warehouse
) {
if (industry.warehouses.hasOwnProperty(city) && warehouse instanceof Warehouse) {
warehouse.updateSize(this, industry);
}
}
@ -456,10 +415,7 @@ export class Corporation {
let hasHandbook = false;
const handbookFn = LiteratureNames.CorporationManagementHandbook;
for (let i = 0; i < homeComp.messages.length; ++i) {
if (
isString(homeComp.messages[i]) &&
homeComp.messages[i] === handbookFn
) {
if (isString(homeComp.messages[i]) && homeComp.messages[i] === handbookFn) {
hasHandbook = true;
break;
}
@ -486,17 +442,12 @@ export class Corporation {
rerender(player: IPlayer): void {
if (companyManagementDiv == null) {
console.warn(
`Corporation.rerender() called when companyManagementDiv is null`,
);
console.warn(`Corporation.rerender() called when companyManagementDiv is null`);
return;
}
if (!routing.isOn(Page.Corporation)) return;
ReactDOM.render(
<CorporationRoot corp={this} player={player} />,
companyManagementDiv,
);
ReactDOM.render(<CorporationRoot corp={this} player={player} />, companyManagementDiv);
}
clearUI(): void {

@ -1,17 +1,7 @@
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
// Array of all valid states
export const AllCorporationStates: string[] = [
"START",
"PURCHASE",
"PRODUCTION",
"SALE",
"EXPORT",
];
export const AllCorporationStates: string[] = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
export class CorporationState {
// Number representing what state the Corporation is in. The number

@ -1,10 +1,6 @@
import { CorporationConstants } from "./data/Constants";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { createElement } from "../../utils/uiHelpers/createElement";
import { EmployeePositions } from "./EmployeePositions";
import { ICorporation } from "./ICorporation";
@ -93,39 +89,22 @@ export class Employee {
if (this.hap < office.minHap) {
this.hap = office.minHap;
}
const salary =
this.sal * marketCycles * CorporationConstants.SecsPerMarketCycle;
const salary = this.sal * marketCycles * CorporationConstants.SecsPerMarketCycle;
return salary;
}
calculateProductivity(
corporation: ICorporation,
industry: IIndustry,
): number {
const effCre =
this.cre *
corporation.getEmployeeCreMultiplier() *
industry.getEmployeeCreMultiplier(),
effCha =
this.cha *
corporation.getEmployeeChaMultiplier() *
industry.getEmployeeChaMultiplier(),
effInt =
this.int *
corporation.getEmployeeIntMultiplier() *
industry.getEmployeeIntMultiplier(),
effEff =
this.eff *
corporation.getEmployeeEffMultiplier() *
industry.getEmployeeEffMultiplier();
calculateProductivity(corporation: ICorporation, industry: IIndustry): number {
const effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
effEff = this.eff * corporation.getEmployeeEffMultiplier() * industry.getEmployeeEffMultiplier();
const prodBase = this.mor * this.hap * this.ene * 1e-6;
let prodMult = 0;
switch (this.pos) {
//Calculate productivity based on position. This is multipled by prodBase
//to get final value
case EmployeePositions.Operations:
prodMult =
0.6 * effInt + 0.1 * effCha + this.exp + 0.5 * effCre + effEff;
prodMult = 0.6 * effInt + 0.1 * effCha + this.exp + 0.5 * effCre + effEff;
break;
case EmployeePositions.Engineer:
prodMult = effInt + 0.1 * effCha + 1.5 * this.exp + effEff;
@ -161,27 +140,11 @@ export class Employee {
}
//'panel' is the DOM element on which to create the UI
createUI(
panel: HTMLElement,
corporation: ICorporation,
industry: IIndustry,
): void {
const effCre =
this.cre *
corporation.getEmployeeCreMultiplier() *
industry.getEmployeeCreMultiplier(),
effCha =
this.cha *
corporation.getEmployeeChaMultiplier() *
industry.getEmployeeChaMultiplier(),
effInt =
this.int *
corporation.getEmployeeIntMultiplier() *
industry.getEmployeeIntMultiplier(),
effEff =
this.eff *
corporation.getEmployeeEffMultiplier() *
industry.getEmployeeEffMultiplier();
createUI(panel: HTMLElement, corporation: ICorporation, industry: IIndustry): void {
const effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
effEff = this.eff * corporation.getEmployeeEffMultiplier() * industry.getEmployeeEffMultiplier();
panel.style.color = "white";
panel.appendChild(
createElement("p", {

@ -52,28 +52,12 @@ export interface IIndustry {
process(marketCycles: number, state: string, corporation: ICorporation): void;
processMaterialMarket(): void;
processProductMarket(marketCycles: number): void;
processMaterials(
marketCycles: number,
corporation: ICorporation,
): [number, number];
processProducts(
marketCycles: number,
corporation: ICorporation,
): [number, number];
processProduct(
marketCycles: number,
product: Product,
corporation: ICorporation,
): number;
processMaterials(marketCycles: number, corporation: ICorporation): [number, number];
processProducts(marketCycles: number, corporation: ICorporation): [number, number];
processProduct(marketCycles: number, product: Product, corporation: ICorporation): number;
discontinueProduct(product: Product): void;
upgrade(
upgrade: IndustryUpgrade,
refs: { corporation: ICorporation; office: OfficeSpace },
): void;
getOfficeProductivity(
office: OfficeSpace,
params?: { forProduct?: boolean },
): number;
upgrade(upgrade: IndustryUpgrade, refs: { corporation: ICorporation; office: OfficeSpace }): void;
getOfficeProductivity(office: OfficeSpace, params?: { forProduct?: boolean }): number;
getBusinessFactor(office: OfficeSpace): number;
getAdvertisingFactors(): [number, number, number, number];
getMarketFactor(mat: { dmd: number; cmp: number }): number;

@ -1,15 +1,7 @@
import {
Reviver,
Generic_toJSON,
Generic_fromJSON,
} from "../../utils/JSONReviver";
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../../utils/JSONReviver";
import { CityName } from "../Locations/data/CityNames";
import Decimal from "decimal.js";
import {
Industries,
IndustryStartingCosts,
IndustryResearchTrees,
} from "./IndustryData";
import { Industries, IndustryStartingCosts, IndustryResearchTrees } from "./IndustryData";
import { CorporationConstants } from "./data/Constants";
import { EmployeePositions } from "./EmployeePositions";
import { Material } from "./Material";
@ -121,8 +113,7 @@ export class Industry implements IIndustry {
init(): void {
//Set the unique properties of an industry (how much its affected by real estate/scientific research, etc.)
const startingCost = IndustryStartingCosts[this.type];
if (startingCost === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (startingCost === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.startingCost = startingCost;
switch (this.type) {
case Industries.Energy:
@ -316,9 +307,7 @@ export class Industry implements IIndustry {
this.makesProducts = true;
break;
default:
console.error(
`Invalid Industry Type passed into Industry.init(): ${this.type}`,
);
console.error(`Invalid Industry Type passed into Industry.init(): ${this.type}`);
return;
}
}
@ -344,9 +333,7 @@ export class Industry implements IIndustry {
case Industries.RealEstate:
return "develop and manage real estate properties";
default:
console.error(
"Invalid industry type in Industry.getProductDescriptionText",
);
console.error("Invalid industry type in Industry.getProductDescriptionText");
return "";
}
}
@ -399,11 +386,7 @@ export class Industry implements IIndustry {
if (prod === undefined) continue;
warehouse.sizeUsed += prod.data[warehouse.loc][0] * prod.siz;
if (prod.data[warehouse.loc][0] > 0) {
warehouse.breakdown +=
prodName +
": " +
formatNumber(prod.data[warehouse.loc][0] * prod.siz, 0) +
"<br>";
warehouse.breakdown += prodName + ": " + formatNumber(prod.data[warehouse.loc][0] * prod.siz, 0) + "<br>";
}
}
}
@ -423,12 +406,8 @@ export class Industry implements IIndustry {
this.thisCycleRevenue = new Decimal(0);
this.thisCycleExpenses = new Decimal(0);
}
this.lastCycleRevenue = this.thisCycleRevenue.dividedBy(
marketCycles * CorporationConstants.SecsPerMarketCycle,
);
this.lastCycleExpenses = this.thisCycleExpenses.dividedBy(
marketCycles * CorporationConstants.SecsPerMarketCycle,
);
this.lastCycleRevenue = this.thisCycleRevenue.dividedBy(marketCycles * CorporationConstants.SecsPerMarketCycle);
this.lastCycleExpenses = this.thisCycleExpenses.dividedBy(marketCycles * CorporationConstants.SecsPerMarketCycle);
this.thisCycleRevenue = new Decimal(0);
this.thisCycleExpenses = new Decimal(0);
@ -493,9 +472,7 @@ export class Industry implements IIndustry {
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
//If this industry has a warehouse in this city, process the market
//for every material this industry requires or produces
if (
this.warehouses[CorporationConstants.Cities[i]] instanceof Warehouse
) {
if (this.warehouses[CorporationConstants.Cities[i]] instanceof Warehouse) {
const wh = this.warehouses[CorporationConstants.Cities[i]];
if (wh === 0) continue;
for (const name in reqMats) {
@ -545,10 +522,7 @@ export class Industry implements IIndustry {
}
//Process production, purchase, and import/export of materials
processMaterials(
marketCycles = 1,
corporation: ICorporation,
): [number, number] {
processMaterials(marketCycles = 1, corporation: ICorporation): [number, number] {
let revenue = 0,
expenses = 0;
this.calculateProductionFactors();
@ -588,24 +562,15 @@ export class Industry implements IIndustry {
const mat = warehouse.materials[matName];
let buyAmt = 0;
let maxAmt = 0;
if (
warehouse.smartSupplyEnabled &&
Object.keys(this.reqMats).includes(matName)
) {
if (warehouse.smartSupplyEnabled && Object.keys(this.reqMats).includes(matName)) {
continue;
}
buyAmt =
mat.buy *
CorporationConstants.SecsPerMarketCycle *
marketCycles;
buyAmt = mat.buy * CorporationConstants.SecsPerMarketCycle * marketCycles;
if (matName == "RealEstate") {
maxAmt = buyAmt;
} else {
maxAmt = Math.floor(
(warehouse.size - warehouse.sizeUsed) /
MaterialSizes[matName],
);
maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / MaterialSizes[matName]);
}
buyAmt = Math.min(buyAmt, maxAmt);
if (buyAmt > 0) {
@ -619,25 +584,15 @@ export class Industry implements IIndustry {
const smartBuy: { [key: string]: number | undefined } = {};
for (const matName in warehouse.materials) {
if (!warehouse.materials.hasOwnProperty(matName)) continue;
if (
!warehouse.smartSupplyEnabled ||
!Object.keys(this.reqMats).includes(matName)
)
continue;
if (!warehouse.smartSupplyEnabled || !Object.keys(this.reqMats).includes(matName)) continue;
const mat = warehouse.materials[matName];
//Smart supply tracker is stored as per second rate
const reqMat = this.reqMats[matName];
if (reqMat === undefined)
throw new Error(`reqMat "${matName}" is undefined`);
if (reqMat === undefined) throw new Error(`reqMat "${matName}" is undefined`);
mat.buy = reqMat * warehouse.smartSupplyStore;
let buyAmt =
mat.buy *
CorporationConstants.SecsPerMarketCycle *
marketCycles;
const maxAmt = Math.floor(
(warehouse.size - warehouse.sizeUsed) / MaterialSizes[matName],
);
let buyAmt = mat.buy * CorporationConstants.SecsPerMarketCycle * marketCycles;
const maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / MaterialSizes[matName]);
buyAmt = Math.min(buyAmt, maxAmt);
if (buyAmt > 0) smartBuy[matName] = buyAmt;
}
@ -646,11 +601,9 @@ export class Industry implements IIndustry {
let worseAmt = 1e99;
for (const matName in smartBuy) {
const buyAmt = smartBuy[matName];
if (buyAmt === undefined)
throw new Error(`Somehow smartbuy matname is undefined`);
if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`);
const reqMat = this.reqMats[matName];
if (reqMat === undefined)
throw new Error(`reqMat "${matName}" is undefined`);
if (reqMat === undefined) throw new Error(`reqMat "${matName}" is undefined`);
const amt = buyAmt / reqMat;
if (amt < worseAmt) worseAmt = amt;
}
@ -658,8 +611,7 @@ export class Industry implements IIndustry {
// Align all the materials to the smallest amount.
for (const matName in smartBuy) {
const reqMat = this.reqMats[matName];
if (reqMat === undefined)
throw new Error(`reqMat "${matName}" is undefined`);
if (reqMat === undefined) throw new Error(`reqMat "${matName}" is undefined`);
smartBuy[matName] = worseAmt * reqMat;
}
@ -667,8 +619,7 @@ export class Industry implements IIndustry {
let totalSize = 0;
for (const matName in smartBuy) {
const buyAmt = smartBuy[matName];
if (buyAmt === undefined)
throw new Error(`Somehow smartbuy matname is undefined`);
if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`);
totalSize += buyAmt * MaterialSizes[matName];
}
@ -677,11 +628,8 @@ export class Industry implements IIndustry {
if (totalSize > freeSpace) {
for (const matName in smartBuy) {
const buyAmt = smartBuy[matName];
if (buyAmt === undefined)
throw new Error(`Somehow smartbuy matname is undefined`);
smartBuy[matName] = Math.floor(
(buyAmt * freeSpace) / totalSize,
);
if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`);
smartBuy[matName] = Math.floor((buyAmt * freeSpace) / totalSize);
}
}
@ -690,8 +638,7 @@ export class Industry implements IIndustry {
if (!warehouse.smartSupplyUseLeftovers[matName]) continue;
const mat = warehouse.materials[matName];
const buyAmt = smartBuy[matName];
if (buyAmt === undefined)
throw new Error(`Somehow smartbuy matname is undefined`);
if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`);
smartBuy[matName] = Math.max(0, buyAmt - mat.qty);
}
@ -699,8 +646,7 @@ export class Industry implements IIndustry {
for (const matName in smartBuy) {
const mat = warehouse.materials[matName];
const buyAmt = smartBuy[matName];
if (buyAmt === undefined)
throw new Error(`Somehow smartbuy matname is undefined`);
if (buyAmt === undefined) throw new Error(`Somehow smartbuy matname is undefined`);
mat.qty += buyAmt;
expenses += buyAmt * mat.bCost;
}
@ -741,9 +687,7 @@ export class Industry implements IIndustry {
}
// If not enough space in warehouse, limit the amount of produced materials
if (totalMatSize > 0) {
const maxAmt = Math.floor(
(warehouse.size - warehouse.sizeUsed) / totalMatSize,
);
const maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / totalMatSize);
prod = Math.min(maxAmt, prod);
}
@ -752,8 +696,7 @@ export class Industry implements IIndustry {
}
// Keep track of production for smart supply (/s)
warehouse.smartSupplyStore +=
prod / (CorporationConstants.SecsPerMarketCycle * marketCycles);
warehouse.smartSupplyStore += prod / (CorporationConstants.SecsPerMarketCycle * marketCycles);
// Make sure we have enough resource to make our materials
let producableFrac = 1;
@ -763,10 +706,7 @@ export class Industry implements IIndustry {
if (reqMat === undefined) continue;
const req = reqMat * prod;
if (warehouse.materials[reqMatName].qty < req) {
producableFrac = Math.min(
producableFrac,
warehouse.materials[reqMatName].qty / req,
);
producableFrac = Math.min(producableFrac, warehouse.materials[reqMatName].qty / req);
}
}
}
@ -784,17 +724,14 @@ export class Industry implements IIndustry {
warehouse.materials[reqMatName].qty -= reqMatQtyNeeded;
warehouse.materials[reqMatName].prd = 0;
warehouse.materials[reqMatName].prd -=
reqMatQtyNeeded /
(CorporationConstants.SecsPerMarketCycle * marketCycles);
reqMatQtyNeeded / (CorporationConstants.SecsPerMarketCycle * marketCycles);
}
for (let j = 0; j < this.prodMats.length; ++j) {
warehouse.materials[this.prodMats[j]].qty +=
prod * producableFrac;
warehouse.materials[this.prodMats[j]].qty += prod * producableFrac;
warehouse.materials[this.prodMats[j]].qlt =
office.employeeProd[EmployeePositions.Engineer] / 90 +
Math.pow(this.sciResearch.qty, this.sciFac) +
Math.pow(warehouse.materials["AICores"].qty, this.aiFac) /
10e3;
Math.pow(warehouse.materials["AICores"].qty, this.aiFac) / 10e3;
}
} else {
for (const reqMatName in this.reqMats) {
@ -805,9 +742,7 @@ export class Industry implements IIndustry {
}
//Per second
const fooProd =
(prod * producableFrac) /
(CorporationConstants.SecsPerMarketCycle * marketCycles);
const fooProd = (prod * producableFrac) / (CorporationConstants.SecsPerMarketCycle * marketCycles);
for (let fooI = 0; fooI < this.prodMats.length; ++fooI) {
warehouse.materials[this.prodMats[fooI]].prd = fooProd;
}
@ -855,18 +790,14 @@ export class Industry implements IIndustry {
corporation.getSalesMultiplier() *
advertisingFactor *
this.getSalesMultiplier();
const denominator = Math.sqrt(
sqrtNumerator / sqrtDenominator,
);
const denominator = Math.sqrt(sqrtNumerator / sqrtDenominator);
let optimalPrice;
if (sqrtDenominator === 0 || denominator === 0) {
if (sqrtNumerator === 0) {
optimalPrice = 0; // No production
} else {
optimalPrice = mat.bCost + markupLimit;
console.warn(
`In Corporation, found illegal 0s when trying to calculate MarketTA2 sale cost`,
);
console.warn(`In Corporation, found illegal 0s when trying to calculate MarketTA2 sale cost`);
}
} else {
optimalPrice = numerator / denominator + mat.bCost;
@ -913,10 +844,7 @@ export class Industry implements IIndustry {
let sellAmt;
if (isString(mat.sllman[1])) {
//Dynamically evaluated
let tmp = (mat.sllman[1] as string).replace(
/MAX/g,
maxSell + "",
);
let tmp = (mat.sllman[1] as string).replace(/MAX/g, maxSell + "");
tmp = tmp.replace(/PROD/g, mat.prd + "");
try {
sellAmt = eval(tmp);
@ -942,24 +870,17 @@ export class Industry implements IIndustry {
sellAmt = Math.min(maxSell, mat.sllman[1] as number);
}
sellAmt =
sellAmt *
CorporationConstants.SecsPerMarketCycle *
marketCycles;
sellAmt = sellAmt * CorporationConstants.SecsPerMarketCycle * marketCycles;
sellAmt = Math.min(mat.qty, sellAmt);
if (sellAmt < 0) {
console.warn(
`sellAmt calculated to be negative for ${matName} in ${city}`,
);
console.warn(`sellAmt calculated to be negative for ${matName} in ${city}`);
mat.sll = 0;
continue;
}
if (sellAmt && sCost >= 0) {
mat.qty -= sellAmt;
revenue += sellAmt * sCost;
mat.sll =
sellAmt /
(CorporationConstants.SecsPerMarketCycle * marketCycles);
mat.sll = sellAmt / (CorporationConstants.SecsPerMarketCycle * marketCycles);
} else {
mat.sll = 0;
}
@ -976,9 +897,7 @@ export class Industry implements IIndustry {
const exp = mat.exp[expI];
const amtStr = exp.amt.replace(
/MAX/g,
mat.qty /
(CorporationConstants.SecsPerMarketCycle * marketCycles) +
"",
mat.qty / (CorporationConstants.SecsPerMarketCycle * marketCycles) + "",
);
let amt = 0;
try {
@ -1009,10 +928,7 @@ export class Industry implements IIndustry {
);
continue;
}
amt =
amt *
CorporationConstants.SecsPerMarketCycle *
marketCycles;
amt = amt * CorporationConstants.SecsPerMarketCycle * marketCycles;
if (mat.qty < amt) {
amt = mat.qty;
@ -1025,9 +941,7 @@ export class Industry implements IIndustry {
const expIndustry = corporation.divisions[foo];
const expWarehouse = expIndustry.warehouses[exp.city];
if (!(expWarehouse instanceof Warehouse)) {
console.error(
`Invalid export! ${expIndustry.name} ${exp.city}`,
);
console.error(`Invalid export! ${expIndustry.name} ${exp.city}`);
break;
}
@ -1037,16 +951,11 @@ export class Industry implements IIndustry {
// affect revenue so just return 0's
return [0, 0];
} else {
const maxAmt = Math.floor(
(expWarehouse.size - expWarehouse.sizeUsed) /
MaterialSizes[matName],
);
const maxAmt = Math.floor((expWarehouse.size - expWarehouse.sizeUsed) / MaterialSizes[matName]);
amt = Math.min(maxAmt, amt);
}
expWarehouse.materials[matName].imp +=
amt /
(CorporationConstants.SecsPerMarketCycle *
marketCycles);
amt / (CorporationConstants.SecsPerMarketCycle * marketCycles);
expWarehouse.materials[matName].qty += amt;
expWarehouse.materials[matName].qlt = mat.qlt;
mat.qty -= amt;
@ -1057,8 +966,7 @@ export class Industry implements IIndustry {
}
}
//totalExp should be per second
mat.totalExp /=
CorporationConstants.SecsPerMarketCycle * marketCycles;
mat.totalExp /= CorporationConstants.SecsPerMarketCycle * marketCycles;
}
}
@ -1087,10 +995,7 @@ export class Industry implements IIndustry {
}
//Process production & sale of this industry's FINISHED products (including all of their stats)
processProducts(
marketCycles = 1,
corporation: ICorporation,
): [number, number] {
processProducts(marketCycles = 1, corporation: ICorporation): [number, number] {
let revenue = 0;
const expenses = 0;
@ -1116,8 +1021,7 @@ export class Industry implements IIndustry {
// Management is a multiplier for the production from Engineers
const mgmtFactor = 1 + mgmtProd / (1.2 * total);
const progress =
(Math.pow(engrProd, 0.34) + Math.pow(opProd, 0.2)) * mgmtFactor;
const progress = (Math.pow(engrProd, 0.34) + Math.pow(opProd, 0.2)) * mgmtFactor;
prod.createProduct(marketCycles, progress);
if (prod.prog >= 100) {
@ -1141,11 +1045,7 @@ export class Industry implements IIndustry {
}
//Processes FINISHED products
processProduct(
marketCycles = 1,
product: Product,
corporation: ICorporation,
): number {
processProduct(marketCycles = 1, product: Product, corporation: ICorporation): number {
let totalProfit = 0;
for (let i = 0; i < CorporationConstants.Cities.length; ++i) {
const city = CorporationConstants.Cities[i];
@ -1184,14 +1084,11 @@ export class Industry implements IIndustry {
//If there's not enough space in warehouse, limit the amount of Product
if (netStorageSize > 0) {
const maxAmt = Math.floor(
(warehouse.size - warehouse.sizeUsed) / netStorageSize,
);
const maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / netStorageSize);
prod = Math.min(maxAmt, prod);
}
warehouse.smartSupplyStore +=
prod / (CorporationConstants.SecsPerMarketCycle * marketCycles);
warehouse.smartSupplyStore += prod / (CorporationConstants.SecsPerMarketCycle * marketCycles);
//Make sure we have enough resources to make our Products
let producableFrac = 1;
@ -1199,10 +1096,7 @@ export class Industry implements IIndustry {
if (product.reqMats.hasOwnProperty(reqMatName)) {
const req = product.reqMats[reqMatName] * prod;
if (warehouse.materials[reqMatName].qty < req) {
producableFrac = Math.min(
producableFrac,
warehouse.materials[reqMatName].qty / req,
);
producableFrac = Math.min(producableFrac, warehouse.materials[reqMatName].qty / req);
}
}
}
@ -1211,12 +1105,10 @@ export class Industry implements IIndustry {
if (producableFrac > 0 && prod > 0) {
for (const reqMatName in product.reqMats) {
if (product.reqMats.hasOwnProperty(reqMatName)) {
const reqMatQtyNeeded =
product.reqMats[reqMatName] * prod * producableFrac;
const reqMatQtyNeeded = product.reqMats[reqMatName] * prod * producableFrac;
warehouse.materials[reqMatName].qty -= reqMatQtyNeeded;
warehouse.materials[reqMatName].prd -=
reqMatQtyNeeded /
(CorporationConstants.SecsPerMarketCycle * marketCycles);
reqMatQtyNeeded / (CorporationConstants.SecsPerMarketCycle * marketCycles);
}
}
//Quantity
@ -1224,9 +1116,7 @@ export class Industry implements IIndustry {
}
//Keep track of production Per second
product.data[city][1] =
(prod * producableFrac) /
(CorporationConstants.SecsPerMarketCycle * marketCycles);
product.data[city][1] = (prod * producableFrac) / (CorporationConstants.SecsPerMarketCycle * marketCycles);
break;
}
case "SALE": {
@ -1234,9 +1124,7 @@ export class Industry implements IIndustry {
product.pCost = 0; //Estimated production cost
for (const reqMatName in product.reqMats) {
if (product.reqMats.hasOwnProperty(reqMatName)) {
product.pCost +=
product.reqMats[reqMatName] *
warehouse.materials[reqMatName].bCost;
product.pCost += product.reqMats[reqMatName] * warehouse.materials[reqMatName].bCost;
}
}
@ -1275,9 +1163,7 @@ export class Industry implements IIndustry {
optimalPrice = 0; // No production
} else {
optimalPrice = product.pCost + markupLimit;
console.warn(
`In Corporation, found illegal 0s when trying to calculate MarketTA2 sale cost`,
);
console.warn(`In Corporation, found illegal 0s when trying to calculate MarketTA2 sale cost`);
}
} else {
optimalPrice = numerator / denominator + product.pCost;
@ -1294,10 +1180,7 @@ export class Industry implements IIndustry {
console.error(`mku is zero, reverting to 1 to avoid Infinity`);
product.mku = 1;
}
sCost = sCostString.replace(
/MP/g,
product.pCost + product.rat / product.mku + "",
);
sCost = sCostString.replace(/MP/g, product.pCost + product.rat / product.mku + "");
sCost = eval(sCost);
} else {
sCost = product.sCost;
@ -1350,15 +1233,12 @@ export class Industry implements IIndustry {
if (sellAmt < 0) {
sellAmt = 0;
}
sellAmt =
sellAmt * CorporationConstants.SecsPerMarketCycle * marketCycles;
sellAmt = sellAmt * CorporationConstants.SecsPerMarketCycle * marketCycles;
sellAmt = Math.min(product.data[city][0], sellAmt); //data[0] is qty
if (sellAmt && sCost) {
product.data[city][0] -= sellAmt; //data[0] is qty
totalProfit += sellAmt * sCost;
product.data[city][2] =
sellAmt /
(CorporationConstants.SecsPerMarketCycle * marketCycles); //data[2] is sell property
product.data[city][2] = sellAmt / (CorporationConstants.SecsPerMarketCycle * marketCycles); //data[2] is sell property
} else {
product.data[city][2] = 0; //data[2] is sell property
}
@ -1387,10 +1267,7 @@ export class Industry implements IIndustry {
}
}
upgrade(
upgrade: IndustryUpgrade,
refs: { corporation: ICorporation; office: OfficeSpace },
): void {
upgrade(upgrade: IndustryUpgrade, refs: { corporation: ICorporation; office: OfficeSpace }): void {
const corporation = refs.corporation;
const office = refs.office;
const upgN = upgrade[0];
@ -1403,18 +1280,13 @@ export class Industry implements IIndustry {
case 0: {
//Coffee, 5% energy per employee
for (let i = 0; i < office.employees.length; ++i) {
office.employees[i].ene = Math.min(
office.employees[i].ene * 1.05,
office.maxEne,
);
office.employees[i].ene = Math.min(office.employees[i].ene * 1.05, office.maxEne);
}
break;
}
case 1: {
//AdVert.Inc,
const advMult =
corporation.getAdvertisingMultiplier() *
this.getAdvertisingMultiplier();
const advMult = corporation.getAdvertisingMultiplier() * this.getAdvertisingMultiplier();
this.awareness += 3 * advMult;
this.popularity += 1 * advMult;
this.awareness *= 1.01 * advMult;
@ -1429,10 +1301,7 @@ export class Industry implements IIndustry {
}
// Returns how much of a material can be produced based of office productivity (employee stats)
getOfficeProductivity(
office: OfficeSpace,
params: { forProduct?: boolean } = {},
): number {
getOfficeProductivity(office: OfficeSpace, params: { forProduct?: boolean } = {}): number {
const opProd = office.employeeProd[EmployeePositions.Operations];
const engrProd = office.employeeProd[EmployeePositions.Engineer];
const mgmtProd = office.employeeProd[EmployeePositions.Management];
@ -1471,10 +1340,7 @@ export class Industry implements IIndustry {
getAdvertisingFactors(): [number, number, number, number] {
const awarenessFac = Math.pow(this.awareness + 1, this.advFac);
const popularityFac = Math.pow(this.popularity + 1, this.advFac);
const ratioFac =
this.awareness === 0
? 0.01
: Math.max((this.popularity + 0.001) / this.awareness, 0.01);
const ratioFac = this.awareness === 0 ? 0.01 : Math.max((this.popularity + 0.001) / this.awareness, 0.01);
const totalFac = Math.pow(awarenessFac * popularityFac * ratioFac, 0.85);
return [totalFac, awarenessFac, popularityFac, ratioFac];
}
@ -1491,15 +1357,11 @@ export class Industry implements IIndustry {
updateResearchTree(): void {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry "${this.type}"`);
// Since ResearchTree data isnt saved, we'll update the Research Tree data
// based on the stored 'researched' property in the Industry object
if (
Object.keys(researchTree.researched).length !==
Object.keys(this.researched).length
) {
if (Object.keys(researchTree.researched).length !== Object.keys(this.researched).length) {
for (const research in this.researched) {
researchTree.research(research);
}
@ -1509,80 +1371,70 @@ export class Industry implements IIndustry {
// Get multipliers from Research
getAdvertisingMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getAdvertisingMultiplier();
}
getEmployeeChaMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getEmployeeChaMultiplier();
}
getEmployeeCreMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getEmployeeCreMultiplier();
}
getEmployeeEffMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getEmployeeEffMultiplier();
}
getEmployeeIntMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getEmployeeIntMultiplier();
}
getProductionMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getProductionMultiplier();
}
getProductProductionMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getProductProductionMultiplier();
}
getSalesMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getSalesMultiplier();
}
getScientificResearchMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getScientificResearchMultiplier();
}
getStorageMultiplier(): number {
const researchTree = IndustryResearchTrees[this.type];
if (researchTree === undefined)
throw new Error(`Invalid industry: "${this.type}"`);
if (researchTree === undefined) throw new Error(`Invalid industry: "${this.type}"`);
this.updateResearchTree();
return researchTree.getStorageMultiplier();
}

@ -1,10 +1,7 @@
import React from "react";
import { ResearchTree } from "./ResearchTree";
import { ICorporation } from "./ICorporation";
import {
getBaseResearchTreeCopy,
getProductIndustryResearchTreeCopy,
} from "./data/BaseResearchTree";
import { getBaseResearchTreeCopy, getProductIndustryResearchTreeCopy } from "./data/BaseResearchTree";
import { MoneyCost } from "./ui/MoneyCost";
interface IIndustryMap<T> {
@ -62,16 +59,13 @@ export const IndustryStartingCosts: IIndustryMap<number> = {
};
// Map of description for each industry
export const IndustryDescriptions: IIndustryMap<
(corp: ICorporation) => React.ReactElement
> = {
export const IndustryDescriptions: IIndustryMap<(corp: ICorporation) => React.ReactElement> = {
Energy: (corp: ICorporation) => (
<>
Engage in the production and distribution of energy.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Energy} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Energy} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -81,8 +75,7 @@ export const IndustryDescriptions: IIndustryMap<
Distribute water and provide wastewater services.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Utilities} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Utilities} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -92,20 +85,17 @@ export const IndustryDescriptions: IIndustryMap<
Cultivate crops and breed livestock to produce food.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Agriculture} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Agriculture} corp={corp} />
<br />
Recommended starting Industry: YES
</>
),
Fishing: (corp: ICorporation) => (
<>
Produce food through the breeding and processing of fish and fish
products.
Produce food through the breeding and processing of fish and fish products.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Fishing} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Fishing} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -115,8 +105,7 @@ export const IndustryDescriptions: IIndustryMap<
Extract and process metals from the earth.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Mining} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Mining} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -126,8 +115,7 @@ export const IndustryDescriptions: IIndustryMap<
Create your own restaurants all around the world.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Food} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Food} corp={corp} />
<br />
Recommended starting Industry: YES
</>
@ -137,8 +125,7 @@ export const IndustryDescriptions: IIndustryMap<
Create and distribute tobacco and tobacco-related products.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Tobacco} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Tobacco} corp={corp} />
<br />
Recommended starting Industry: YES
</>
@ -148,8 +135,7 @@ export const IndustryDescriptions: IIndustryMap<
Produce industrial chemicals.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Chemical} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Chemical} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -159,20 +145,17 @@ export const IndustryDescriptions: IIndustryMap<
Discover, develop, and create new pharmaceutical drugs.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Pharmaceutical} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Pharmaceutical} corp={corp} />
<br />
Recommended starting Industry: NO
</>
),
Computer: (corp: ICorporation) => (
<>
Develop and manufacture new computer hardware and networking
infrastructures.
Develop and manufacture new computer hardware and networking infrastructures.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Computer} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Computer} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -182,8 +165,7 @@ export const IndustryDescriptions: IIndustryMap<
Develop and create robots.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Robotics} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Robotics} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -193,8 +175,7 @@ export const IndustryDescriptions: IIndustryMap<
Develop computer software and create AI Cores.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Software} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Software} corp={corp} />
<br />
Recommended starting Industry: YES
</>
@ -204,8 +185,7 @@ export const IndustryDescriptions: IIndustryMap<
Create and manage hospitals.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.Healthcare} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.Healthcare} corp={corp} />
<br />
Recommended starting Industry: NO
</>
@ -215,8 +195,7 @@ export const IndustryDescriptions: IIndustryMap<
Develop and manage real estate properties.
<br />
<br />
Starting cost:{" "}
<MoneyCost money={IndustryStartingCosts.RealEstate} corp={corp} />
Starting cost: <MoneyCost money={IndustryStartingCosts.RealEstate} corp={corp} />
<br />
Recommended starting Industry: NO
</>

@ -6,14 +6,7 @@ export type IndustryUpgrade = [number, number, number, number, string, string];
// The data structure is an array with the following format:
// [index in array, base price, price mult, benefit mult (if applicable), name, desc]
export const IndustryUpgrades: IMap<IndustryUpgrade> = {
"0": [
0,
500e3,
1,
1.05,
"Coffee",
"Provide your employees with coffee, increasing their energy by 5%.",
],
"0": [0, 500e3, 1, 1.05, "Coffee", "Provide your employees with coffee, increasing their energy by 5%."],
"1": [
1,
1e9,

@ -1,8 +1,4 @@
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { Export } from "./Export";
interface IConstructorParams {

@ -2,11 +2,7 @@ import { EmployeePositions } from "./EmployeePositions";
import { CorporationConstants } from "./data/Constants";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { generateRandomString } from "../../utils/StringHelperFunctions";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { Employee } from "./Employee";
import { IIndustry } from "./IIndustry";
import { ICorporation } from "./ICorporation";
@ -53,11 +49,7 @@ export class OfficeSpace {
return this.employees.length >= this.size;
}
process(
marketCycles = 1,
corporation: ICorporation,
industry: IIndustry,
): number {
process(marketCycles = 1, corporation: ICorporation, industry: IIndustry): number {
// HRBuddy AutoRecruitment and training
if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) {
const emp = this.hireRandomEmployee();
@ -119,10 +111,7 @@ export class OfficeSpace {
return salaryPaid;
}
calculateEmployeeProductivity(
corporation: ICorporation,
industry: IIndustry,
): void {
calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void {
//Reset
for (const name in this.employeeProd) {
this.employeeProd[name] = 0;
@ -140,8 +129,7 @@ export class OfficeSpace {
hireRandomEmployee(): Employee | undefined {
if (this.atCapacity()) return;
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null)
return;
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) return;
//Generate three random employees (meh, decent, amazing)
const mult = getRandomInt(76, 100) / 100;
@ -150,9 +138,7 @@ export class OfficeSpace {
exp = getRandomInt(50, 100),
cre = getRandomInt(50, 100),
eff = getRandomInt(50, 100),
sal =
CorporationConstants.EmployeeSalaryMultiplier *
(int + cha + exp + cre + eff);
sal = CorporationConstants.EmployeeSalaryMultiplier * (int + cha + exp + cre + eff);
const emp = new Employee({
intelligence: int * mult,

@ -1,19 +1,12 @@
import { EmployeePositions } from "./EmployeePositions";
import { MaterialSizes } from "./MaterialSizes";
import { IIndustry } from "./IIndustry";
import {
ProductRatingWeights,
IProductRatingWeight,
} from "./ProductRatingWeights";
import { ProductRatingWeights, IProductRatingWeight } from "./ProductRatingWeights";
import { createCityMap } from "../Locations/createCityMap";
import { IMap } from "../types";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
interface IConstructorParams {
@ -132,34 +125,20 @@ export class Product {
}
// @param industry - Industry object. Reference to industry that makes this Product
finishProduct(
employeeProd: { [key: string]: number },
industry: IIndustry,
): void {
finishProduct(employeeProd: { [key: string]: number }, industry: IIndustry): void {
this.fin = true;
//Calculate properties
const progrMult = this.prog / 100;
const engrRatio =
employeeProd[EmployeePositions.Engineer] / employeeProd["total"];
const mgmtRatio =
employeeProd[EmployeePositions.Management] / employeeProd["total"];
const rndRatio =
employeeProd[EmployeePositions.RandD] / employeeProd["total"];
const opsRatio =
employeeProd[EmployeePositions.Operations] / employeeProd["total"];
const busRatio =
employeeProd[EmployeePositions.Business] / employeeProd["total"];
const engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"];
const mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"];
const rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"];
const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"];
const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"];
const designMult = 1 + Math.pow(this.designCost, 0.1) / 100;
const balanceMult =
1.2 * engrRatio +
0.9 * mgmtRatio +
1.3 * rndRatio +
1.5 * opsRatio +
busRatio;
const sciMult =
1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800;
const balanceMult = 1.2 * engrRatio + 0.9 * mgmtRatio + 1.3 * rndRatio + 1.5 * opsRatio + busRatio;
const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800;
const totalMult = progrMult * balanceMult * designMult * sciMult;
this.qlt =
@ -206,21 +185,14 @@ export class Product {
0.05 * employeeProd[EmployeePositions.Business]);
this.calculateRating(industry);
const advMult = 1 + Math.pow(this.advCost, 0.1) / 100;
this.mku =
100 /
(advMult * Math.pow(this.qlt + 0.001, 0.65) * (busRatio + mgmtRatio));
this.mku = 100 / (advMult * Math.pow(this.qlt + 0.001, 0.65) * (busRatio + mgmtRatio));
// I actually don't understand well enough to know if this is right.
// I'm adding this to prevent a crash.
if (this.mku === 0) this.mku = 1;
this.dmd =
industry.awareness === 0
? 20
: Math.min(
100,
advMult * (100 * (industry.popularity / industry.awareness)),
);
industry.awareness === 0 ? 20 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness)));
this.cmp = getRandomInt(0, 70);
//Calculate the product's required materials

@ -40,9 +40,7 @@ export class Node {
constructor(p: IConstructorParams = { cost: 0, text: "" }) {
if (ResearchMap[p.text] == null) {
throw new Error(
`Invalid Research name used when constructing ResearchTree Node: ${p.text}`,
);
throw new Error(`Invalid Research name used when constructing ResearchTree Node: ${p.text}`);
}
this.text = p.text;
@ -87,10 +85,7 @@ export class Node {
HTMLclass: htmlClass,
innerHTML:
`<div id="${sanitizedName}-corp-research-click-listener" class="tooltip">` +
`${this.text}<br>${numeralWrapper.format(
this.cost,
"0,0",
)} Scientific Research` +
`${this.text}<br>${numeralWrapper.format(this.cost, "0,0")} Scientific Research` +
`<span class="tooltiptext">` +
`${research.desc}` +
`</span>` +
@ -243,9 +238,7 @@ export class ResearchTree {
const mult: any = (research as any)[propName];
if (mult == null) {
console.warn(
`Invalid propName specified in ResearchTree.getMultiplierHelper: ${propName}`,
);
console.warn(`Invalid propName specified in ResearchTree.getMultiplierHelper: ${propName}`);
continue;
}
@ -292,9 +285,7 @@ export class ResearchTree {
}
}
console.warn(
`ResearchTree.research() did not find the specified Research node for: ${name}`,
);
console.warn(`ResearchTree.research() did not find the specified Research node for: ${name}`);
}
// Set the tree's Root Node

@ -4,11 +4,7 @@ import { IIndustry } from "./IIndustry";
import { MaterialSizes } from "./MaterialSizes";
import { IMap } from "../types";
import { numeralWrapper } from "../ui/numeralFormat";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
interface IConstructorParams {
@ -95,28 +91,18 @@ export class Warehouse {
if (MaterialSizes.hasOwnProperty(matName)) {
this.sizeUsed += mat.qty * MaterialSizes[matName];
if (mat.qty > 0) {
this.breakdown +=
matName +
": " +
numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0") +
"<br>";
this.breakdown += matName + ": " + numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0") + "<br>";
}
}
}
if (this.sizeUsed > this.size) {
console.warn(
"Warehouse size used greater than capacity, something went wrong",
);
console.warn("Warehouse size used greater than capacity, something went wrong");
}
}
updateSize(corporation: ICorporation, industry: IIndustry): void {
try {
this.size =
this.level *
100 *
corporation.getStorageMultiplier() *
industry.getStorageMultiplier();
this.size = this.level * 100 * corporation.getStorageMultiplier() * industry.getStorageMultiplier();
} catch (e) {
exceptionAlert(e);
}

@ -1,11 +1,5 @@
const CyclesPerMarketCycle = 50;
const AllCorporationStates = [
"START",
"PURCHASE",
"PRODUCTION",
"SALE",
"EXPORT",
];
const AllCorporationStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
export const CorporationConstants: {
INITIALSHARES: number;
SHARESPERPRICEUPDATE: number;
@ -38,18 +32,10 @@ export const CorporationConstants: {
SellSharesCooldown: 18e3, // 1 Hour in terms of game cycles
CyclesPerMarketCycle: CyclesPerMarketCycle,
CyclesPerIndustryStateCycle:
CyclesPerMarketCycle / AllCorporationStates.length,
CyclesPerIndustryStateCycle: CyclesPerMarketCycle / AllCorporationStates.length,
SecsPerMarketCycle: CyclesPerMarketCycle / 5,
Cities: [
"Aevum",
"Chongqing",
"Sector-12",
"New Tokyo",
"Ishima",
"Volhaven",
],
Cities: ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"],
WarehouseInitialCost: 5e9, //Initial purchase cost of warehouse
WarehouseInitialSize: 100,

@ -1,13 +1,6 @@
import { IMap } from "../../types";
export type CorporationUpgrade = [
number,
number,
number,
number,
string,
string,
];
export type CorporationUpgrade = [number, number, number, number, string, string];
// Corporation Upgrades
// Upgrades for entire corporation, levelable upgrades

@ -106,9 +106,7 @@ export const researchMetadata: IConstructorParams[] = [
{
name: "JoyWire",
cost: 20e3,
desc:
"A brain implant which is installed in employees, increasing their " +
"maximum happiness by 10.",
desc: "A brain implant which is installed in employees, increasing their " + "maximum happiness by 10.",
},
{
name: "Market-TA.I",
@ -162,9 +160,7 @@ export const researchMetadata: IConstructorParams[] = [
{
name: "sudo.Assist",
cost: 15e3,
desc:
"Develop a virtual assistant AI to handle and manage administrative " +
"issues for your corporation.",
desc: "Develop a virtual assistant AI to handle and manage administrative " + "issues for your corporation.",
},
{
name: "uPgrade: Capacity.I",

@ -33,10 +33,7 @@ export function BribeFactionPopup(props: IProps): React.ReactElement {
}
function repGain(money: number, stock: number): number {
return (
(money + stock * props.corp.sharePrice) /
CorporationConstants.BribeToRepRatio
);
return (money + stock * props.corp.sharePrice) / CorporationConstants.BribeToRepRatio;
}
function getRepText(money: number, stock: number): string {
@ -69,11 +66,7 @@ export function BribeFactionPopup(props: IProps): React.ReactElement {
} else {
const rep = repGain(money, stock);
dialogBoxCreate(
"You gained " +
numeralWrapper.formatReputation(rep) +
" reputation with " +
fac.name +
" by bribing them.",
"You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.",
);
fac.playerReputation += rep;
props.corp.funds = props.corp.funds.minus(money);
@ -84,16 +77,8 @@ export function BribeFactionPopup(props: IProps): React.ReactElement {
return (
<>
<p>
You can use Corporation funds or stock shares to bribe Faction Leaders
in exchange for faction reputation.
</p>
<select
className="dropdown"
style={{ margin: "3px" }}
defaultValue={selectedFaction}
onChange={changeFaction}
>
<p>You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation.</p>
<select className="dropdown" style={{ margin: "3px" }} defaultValue={selectedFaction} onChange={changeFaction}>
{props.player.factions.map((name: string) => {
const info = Factions[name].getInfo();
if (!info.offersWork()) return;
@ -111,12 +96,7 @@ export function BribeFactionPopup(props: IProps): React.ReactElement {
placeholder="Corporation funds"
style={{ margin: "5px" }}
/>
<input
className="text-input"
onChange={onStockChange}
placeholder="Stock Shares"
style={{ margin: "5px" }}
/>
<input className="text-input" onChange={onStockChange} placeholder="Stock Shares" style={{ margin: "5px" }} />
<button
className="a-link-button"
onClick={() => bribe(money ? money : 0, stock ? stock : 0)}

@ -31,9 +31,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
if (isNaN(shares) || shares <= 0) {
dialogBoxCreate("ERROR: Invalid value for number of shares");
} else if (shares > props.corp.issuedShares) {
dialogBoxCreate(
"ERROR: There are not this many oustanding shares to buy back",
);
dialogBoxCreate("ERROR: There are not this many oustanding shares to buy back");
} else if (shares * buybackPrice > props.player.money) {
dialogBoxCreate(
"ERROR: You do not have enough money to purchase this many shares (you need " +
@ -43,9 +41,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
} else {
props.corp.numShares += shares;
if (isNaN(props.corp.issuedShares)) {
console.warn(
"Corporation issuedShares is NaN: " + props.corp.issuedShares,
);
console.warn("Corporation issuedShares is NaN: " + props.corp.issuedShares);
console.warn("Converting to number now");
const res = props.corp.issuedShares;
if (isNaN(res)) {
@ -69,15 +65,13 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
return (
<>
There are not this many shares available to buy back. There are only{" "}
{numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding
shares.
{numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding shares.
</>
);
} else {
return (
<>
Purchase {shares} shares for a total of{" "}
{numeralWrapper.formatMoney(shares * buybackPrice)}
Purchase {shares} shares for a total of {numeralWrapper.formatMoney(shares * buybackPrice)}
</>
);
}
@ -90,19 +84,15 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
return (
<>
<p>
Enter the number of outstanding shares you would like to buy back. These
shares must be bought at a 10% premium. However, repurchasing shares
from the market tends to lead to an increase in stock price.
Enter the number of outstanding shares you would like to buy back. These shares must be bought at a 10% premium.
However, repurchasing shares from the market tends to lead to an increase in stock price.
<br />
<br />
To purchase these shares, you must use your own money (NOT your
Corporation's funds).
To purchase these shares, you must use your own money (NOT your Corporation's funds).
<br />
<br />
The current buyback price of your company's stock is{" "}
{numeralWrapper.formatMoney(buybackPrice)}. Your company currently has{" "}
{numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding
stock shares.
The current buyback price of your company's stock is {numeralWrapper.formatMoney(buybackPrice)}. Your company
currently has {numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding stock shares.
</p>
<CostIndicator />
<br />
@ -115,11 +105,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
onChange={changeShares}
onKeyDown={onKeyDown}
/>
<button
onClick={buy}
className="a-link-button"
style={{ display: "inline-block" }}
>
<button onClick={buy} className="a-link-button" style={{ display: "inline-block" }}>
Buy shares
</button>
</>

@ -61,7 +61,8 @@ export function CityTabs(props: IProps): React.ReactElement {
return (
<>
{Object.values(props.division.offices).map(
(office: OfficeSpace | 0) => office !== 0 && (
(office: OfficeSpace | 0) =>
office !== 0 && (
<CityTab
current={city === office.loc}
key={office.loc}
@ -70,11 +71,7 @@ export function CityTabs(props: IProps): React.ReactElement {
/>
),
)}
<ExpandButton
corp={props.corp}
division={props.division}
setCity={setCity}
/>
<ExpandButton corp={props.corp} division={props.division} setCity={setCity} />
<Industry
corp={props.corp}
division={props.division}

@ -24,9 +24,8 @@ export function DiscontinueProductPopup(props: IProps): React.ReactElement {
return (
<>
<p>
Are you sure you want to do this? Discontinuing a product removes it
completely and permanently. You will no longer produce this product and
all of its existing stock will be removed and left unsold
Are you sure you want to do this? Discontinuing a product removes it completely and permanently. You will no
longer produce this product and all of its existing stock will be removed and left unsold
</p>
<button className="popup-box-button" onClick={discontinue}>
Discontinue

@ -35,12 +35,8 @@ export function ExpandNewCityPopup(props: IProps): React.ReactElement {
return (
<>
<p>
Would you like to expand into a new city by opening an office? This
would cost{" "}
<MoneyCost
money={CorporationConstants.OfficeInitialCost}
corp={props.corp}
/>
Would you like to expand into a new city by opening an office? This would cost{" "}
<MoneyCost money={CorporationConstants.OfficeInitialCost} corp={props.corp} />
</p>
<select ref={dropdown} className="dropdown" style={{ margin: "5px" }}>
{Object.keys(props.division.offices)

@ -14,16 +14,11 @@ interface IProps {
// Create a popup that lets the player manage exports
export function ExportPopup(props: IProps): React.ReactElement {
if (props.corp.divisions.length === 0)
throw new Error("Export popup created with no divisions.");
if (props.corp.divisions.length === 0) throw new Error("Export popup created with no divisions.");
if (Object.keys(props.corp.divisions[0].warehouses).length === 0)
throw new Error("Export popup created in a division with no warehouses.");
const [industry, setIndustry] = useState<string>(
props.corp.divisions[0].name,
);
const [city, setCity] = useState<string>(
Object.keys(props.corp.divisions[0].warehouses)[0],
);
const [industry, setIndustry] = useState<string>(props.corp.divisions[0].name);
const [city, setCity] = useState<string>(Object.keys(props.corp.divisions[0].warehouses)[0]);
const [amt, setAmt] = useState("");
const setRerender = useState(false)[1];
@ -71,11 +66,7 @@ export function ExportPopup(props: IProps): React.ReactElement {
function removeExport(exp: Export): void {
for (let i = 0; i < props.mat.exp.length; ++i) {
if (
props.mat.exp[i].ind !== exp.ind ||
props.mat.exp[i].city !== exp.city ||
props.mat.exp[i].amt !== exp.amt
)
if (props.mat.exp[i].ind !== exp.ind || props.mat.exp[i].city !== exp.city || props.mat.exp[i].amt !== exp.amt)
continue;
props.mat.exp.splice(i, 1);
break;
@ -83,22 +74,15 @@ export function ExportPopup(props: IProps): React.ReactElement {
rerender();
}
const currentDivision = props.corp.divisions.find(
(division: IIndustry) => division.name === industry,
);
const currentDivision = props.corp.divisions.find((division: IIndustry) => division.name === industry);
return (
<>
<p>
Select the industry and city to export this material to, as well as how
much of this material to export per second. You can set the export
amount to 'MAX' to export all of the materials in this warehouse.
Select the industry and city to export this material to, as well as how much of this material to export per
second. You can set the export amount to 'MAX' to export all of the materials in this warehouse.
</p>
<select
className="dropdown"
onChange={onIndustryChange}
defaultValue={industry}
>
<select className="dropdown" onChange={onIndustryChange} defaultValue={industry}>
{props.corp.divisions.map((division: IIndustry) => (
<option key={division.name} value={division.name}>
{division.name}
@ -116,28 +100,16 @@ export function ExportPopup(props: IProps): React.ReactElement {
);
})}
</select>
<input
className="text-input"
placeholder="Export amount / s"
onChange={onAmtChange}
/>
<button
className="std-button"
style={{ display: "inline-block" }}
onClick={exportMaterial}
>
<input className="text-input" placeholder="Export amount / s" onChange={onAmtChange} />
<button className="std-button" style={{ display: "inline-block" }} onClick={exportMaterial}>
Export
</button>
<p>
Below is a list of all current exports of this material from this
warehouse. Clicking on one of the exports below will REMOVE that export.
Below is a list of all current exports of this material from this warehouse. Clicking on one of the exports
below will REMOVE that export.
</p>
{props.mat.exp.map((exp: Export, index: number) => (
<div
key={index}
className="cmpy-mgmt-existing-export"
onClick={() => removeExport(exp)}
>
<div key={index} className="cmpy-mgmt-existing-export" onClick={() => removeExport(exp)}>
Industry: {exp.ind}
<br />
City: {exp.city}

@ -37,9 +37,7 @@ export function FindInvestorsPopup(props: IProps): React.ReactElement {
return <></>;
}
const funding = val * percShares * roundMultiplier;
const investShares = Math.floor(
CorporationConstants.INITIALSHARES * percShares,
);
const investShares = Math.floor(CorporationConstants.INITIALSHARES * percShares);
function findInvestors(): void {
props.corp.fundingRound++;
@ -51,17 +49,15 @@ export function FindInvestorsPopup(props: IProps): React.ReactElement {
return (
<>
<p>
An investment firm has offered you {numeralWrapper.formatMoney(funding)}{" "}
in funding in exchange for a{" "}
{numeralWrapper.format(percShares * 100, "0.000a")}% stake in the
company ({numeralWrapper.format(investShares, "0.000a")} shares).
An investment firm has offered you {numeralWrapper.formatMoney(funding)} in funding in exchange for a{" "}
{numeralWrapper.format(percShares * 100, "0.000a")}% stake in the company (
{numeralWrapper.format(investShares, "0.000a")} shares).
<br />
<br />
Do you accept or reject this offer?
<br />
<br />
Hint: Investment firms will offer more money if your corporation is
turning a profit
Hint: Investment firms will offer more money if your corporation is turning a profit
</p>
<button onClick={findInvestors} className="std-button">
Accept

@ -14,13 +14,11 @@ interface IProps {
// Create a popup that lets the player manage exports
export function GoPublicPopup(props: IProps): React.ReactElement {
const [shares, setShares] = useState("");
const initialSharePrice =
props.corp.determineValuation() / props.corp.totalShares;
const initialSharePrice = props.corp.determineValuation() / props.corp.totalShares;
function goPublic(): void {
const numShares = parseFloat(shares);
const initialSharePrice =
props.corp.determineValuation() / props.corp.totalShares;
const initialSharePrice = props.corp.determineValuation() / props.corp.totalShares;
if (isNaN(numShares)) {
dialogBoxCreate("Invalid value for number of issued shares");
return;
@ -37,9 +35,7 @@ export function GoPublicPopup(props: IProps): React.ReactElement {
props.corp.rerender(props.player);
dialogBoxCreate(
`You took your ${props.corp.name} public and earned ` +
`${numeralWrapper.formatMoney(
numShares * initialSharePrice,
)} in your IPO`,
`${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`,
);
removePopup(props.popupId);
}
@ -55,16 +51,12 @@ export function GoPublicPopup(props: IProps): React.ReactElement {
return (
<>
<p>
Enter the number of shares you would like to issue for your IPO. These
shares will be publicly sold and you will no longer own them. Your
Corporation will receive {numeralWrapper.formatMoney(initialSharePrice)}{" "}
per share (the IPO money will be deposited directly into your
Corporation's funds).
Enter the number of shares you would like to issue for your IPO. These shares will be publicly sold and you will
no longer own them. Your Corporation will receive {numeralWrapper.formatMoney(initialSharePrice)} per share (the
IPO money will be deposited directly into your Corporation's funds).
<br />
<br />
You have a total of{" "}
{numeralWrapper.format(props.corp.numShares, "0.000a")} of shares that
you can issue.
You have a total of {numeralWrapper.format(props.corp.numShares, "0.000a")} of shares that you can issue.
</p>
<input
className="text-input"

@ -20,9 +20,8 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
const allIndustries = Object.keys(Industries).sort();
const possibleIndustries = allIndustries
.filter(
(industryType: string) => props.corp.divisions.find(
(division: IIndustry) => division.type === industryType,
) === undefined,
(industryType: string) =>
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
)
.sort();
if (possibleIndustries.length === 0) return <></>;
@ -36,13 +35,7 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
});
}
return (
<HeaderTab
current={false}
onClick={openNewIndustryPopup}
text={"Expand into new Industry"}
/>
);
return <HeaderTab current={false} onClick={openNewIndustryPopup} text={"Expand into new Industry"} />;
}
interface IProps {
@ -72,11 +65,7 @@ export function HeaderTabs(props: IProps): React.ReactElement {
))}
<ExpandButton corp={props.corp} setDivisionName={setDivisionName} />
</div>
<MainPanel
corp={props.corp}
divisionName={divisionName}
player={props.player}
/>
<MainPanel corp={props.corp} divisionName={divisionName} player={props.player} />
</>
);
}

@ -2,10 +2,7 @@ import { IIndustry } from "../IIndustry";
// Returns a boolean indicating whether the given material is relevant for the
// current industry.
export function isRelevantMaterial(
matName: string,
division: IIndustry,
): boolean {
export function isRelevantMaterial(matName: string, division: IIndustry): boolean {
// Materials that affect Production multiplier
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate"];

@ -117,9 +117,7 @@ export function HireEmployeePopup(props: IProps): React.ReactElement {
const exp = getRandomInt(50, 100);
const cre = getRandomInt(50, 100);
const eff = getRandomInt(50, 100);
const sal =
CorporationConstants.EmployeeSalaryMultiplier *
(int + cha + exp + cre + eff);
const sal = CorporationConstants.EmployeeSalaryMultiplier * (int + cha + exp + cre + eff);
const emp1 = new Employee({
intelligence: int * mult1,

@ -31,12 +31,7 @@ export function Industry(props: IProps): React.ReactElement {
currentCity={props.city}
office={props.office}
/>
<IndustryOffice
player={props.player}
corp={props.corp}
division={props.division}
office={props.office}
/>
<IndustryOffice player={props.player} corp={props.corp} division={props.division} office={props.office} />
</div>
<div className={"cmpy-mgmt-industry-right-panel"}>
<IndustryWarehouse

@ -41,28 +41,20 @@ interface ISwitchProps {
function SwitchButton(props: ISwitchProps): React.ReactElement {
if (props.manualMode) {
return (
<button
className={"std-button tooltip"}
onClick={() => props.switchMode((old) => !old)}
>
<button className={"std-button tooltip"} onClick={() => props.switchMode((old) => !old)}>
Switch to Auto Mode
<span className={"tooltiptext"}>
Switch to Automatic Assignment Mode, which will automatically assign
employees to your selected jobs. You simply have to select the number
of assignments for each job
Switch to Automatic Assignment Mode, which will automatically assign employees to your selected jobs. You
simply have to select the number of assignments for each job
</span>
</button>
);
} else {
return (
<button
className={"std-button tooltip"}
onClick={() => props.switchMode((old) => !old)}
>
<button className={"std-button tooltip"} onClick={() => props.switchMode((old) => !old)}>
Switch to Manual Mode
<span className={"tooltiptext"}>
Switch to Manual Assignment Mode, which allows you to specify which
employees should get which jobs
Switch to Manual Assignment Mode, which allows you to specify which employees should get which jobs
</span>
</button>
);
@ -83,16 +75,10 @@ function ManualManagement(props: IProps): React.ReactElement {
// Employee Selector
const employees = [];
for (let i = 0; i < props.office.employees.length; ++i) {
employees.push(
<option key={props.office.employees[i].name}>
{props.office.employees[i].name}
</option>,
);
employees.push(<option key={props.office.employees[i].name}>{props.office.employees[i].name}</option>);
}
function employeeSelectorOnChange(
e: React.ChangeEvent<HTMLSelectElement>,
): void {
function employeeSelectorOnChange(e: React.ChangeEvent<HTMLSelectElement>): void {
const name = getSelectText(e.target);
for (let i = 0; i < props.office.employees.length; ++i) {
if (name === props.office.employees[i].name) {
@ -120,9 +106,7 @@ function ManualManagement(props: IProps): React.ReactElement {
}
}
function employeePositionSelectorOnChange(
e: React.ChangeEvent<HTMLSelectElement>,
): void {
function employeePositionSelectorOnChange(e: React.ChangeEvent<HTMLSelectElement>): void {
if (employee === null) return;
const pos = getSelectText(e.target);
employee.pos = pos;
@ -133,26 +117,10 @@ function ManualManagement(props: IProps): React.ReactElement {
const nf = "0.000";
// Employee stats (after applying multipliers)
const effCre = emp
? emp.cre *
props.corp.getEmployeeCreMultiplier() *
props.division.getEmployeeCreMultiplier()
: 0;
const effCha = emp
? emp.cha *
props.corp.getEmployeeChaMultiplier() *
props.division.getEmployeeChaMultiplier()
: 0;
const effInt = emp
? emp.int *
props.corp.getEmployeeIntMultiplier() *
props.division.getEmployeeIntMultiplier()
: 0;
const effEff = emp
? emp.eff *
props.corp.getEmployeeEffMultiplier() *
props.division.getEmployeeEffMultiplier()
: 0;
const effCre = emp ? emp.cre * props.corp.getEmployeeCreMultiplier() * props.division.getEmployeeCreMultiplier() : 0;
const effCha = emp ? emp.cha * props.corp.getEmployeeChaMultiplier() * props.division.getEmployeeChaMultiplier() : 0;
const effInt = emp ? emp.int * props.corp.getEmployeeIntMultiplier() * props.division.getEmployeeIntMultiplier() : 0;
const effEff = emp ? emp.eff * props.corp.getEmployeeEffMultiplier() * props.division.getEmployeeEffMultiplier() : 0;
return (
<div style={employeeInfoDivStyle}>
@ -204,10 +172,7 @@ interface IAutoAssignProps {
function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
const numJob = countEmployee(props.office.employees, props.job);
const numUnassigned = countEmployee(
props.office.employees,
EmployeePositions.Unassigned,
);
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
function assignEmployee(): void {
if (numUnassigned <= 0) {
console.warn("Cannot assign employee. No unassigned employees available");
@ -232,19 +197,12 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
return (
<>
<h2 className={"tooltip"} style={positionHeaderStyle}>
{props.job} ({numJob})
<span className={"tooltiptext"}>{props.desc}</span>
{props.job} ({numJob})<span className={"tooltiptext"}>{props.desc}</span>
</h2>
<button
className={numUnassigned > 0 ? "std-button" : "a-link-button-inactive"}
onClick={assignEmployee}
>
<button className={numUnassigned > 0 ? "std-button" : "a-link-button-inactive"} onClick={assignEmployee}>
+
</button>
<button
className={numJob > 0 ? "std-button" : "a-link-button-inactive"}
onClick={unassignEmployee}
>
<button className={numJob > 0 ? "std-button" : "a-link-button-inactive"} onClick={unassignEmployee}>
-
</button>
<br />
@ -253,10 +211,7 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
}
function AutoManagement(props: IProps): React.ReactElement {
const numUnassigned = countEmployee(
props.office.employees,
EmployeePositions.Unassigned,
);
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
const vechain = props.corp.unlockUpgrades[4] === 1; // Has Vechain upgrade
// Calculate average morale, happiness, and energy. Also salary
@ -330,20 +285,14 @@ function AutoManagement(props: IProps): React.ReactElement {
<p className={"tooltip"} style={{ display: "inline-block" }}>
Material Production:
<span className={"tooltiptext"}>
The base amount of material this office can produce. Does
not include production multipliers from upgrades and
materials. This value is based off the productivity of
your Operations, Engineering, and Management employees
The base amount of material this office can produce. Does not include production multipliers from
upgrades and materials. This value is based off the productivity of your Operations, Engineering,
and Management employees
</span>
</p>
</td>
<td>
<p>
{numeralWrapper.format(
props.division.getOfficeProductivity(props.office),
"0.000",
)}
</p>
<p>{numeralWrapper.format(props.division.getOfficeProductivity(props.office), "0.000")}</p>
</td>
</tr>
<tr>
@ -351,11 +300,9 @@ function AutoManagement(props: IProps): React.ReactElement {
<p className={"tooltip"} style={{ display: "inline-block" }}>
Product Production:
<span className={"tooltiptext"}>
The base amount of any given Product this office can
produce. Does not include production multipliers from
upgrades and materials. This value is based off the
productivity of your Operations, Engineering, and
Management employees
The base amount of any given Product this office can produce. Does not include production
multipliers from upgrades and materials. This value is based off the productivity of your
Operations, Engineering, and Management employees
</span>
</p>
</td>
@ -375,19 +322,12 @@ function AutoManagement(props: IProps): React.ReactElement {
<p className={"tooltip"} style={{ display: "inline-block" }}>
Business Multiplier:
<span className={"tooltiptext"}>
The effect this office's 'Business' employees has on
boosting sales
The effect this office's 'Business' employees has on boosting sales
</span>
</p>
</td>
<td>
<p>
x
{numeralWrapper.format(
props.division.getBusinessFactor(props.office),
"0.000",
)}
</p>
<p>x{numeralWrapper.format(props.division.getBusinessFactor(props.office), "0.000")}</p>
</td>
</tr>
</>
@ -400,9 +340,7 @@ function AutoManagement(props: IProps): React.ReactElement {
division={props.division}
player={props.player}
job={EmployeePositions.Operations}
desc={
"Manages supply chain operations. Improves the amount of Materials and Products you produce."
}
desc={"Manages supply chain operations. Improves the amount of Materials and Products you produce."}
/>
<AutoAssignJob
@ -422,9 +360,7 @@ function AutoManagement(props: IProps): React.ReactElement {
division={props.division}
player={props.player}
job={EmployeePositions.Business}
desc={
"Handles sales and finances. Improves the amount of Materials and Products you can sell."
}
desc={"Handles sales and finances. Improves the amount of Materials and Products you can sell."}
/>
<AutoAssignJob
@ -444,9 +380,7 @@ function AutoManagement(props: IProps): React.ReactElement {
division={props.division}
player={props.player}
job={EmployeePositions.RandD}
desc={
"Research new innovative ways to improve the company. Generates Scientific Research."
}
desc={"Research new innovative ways to improve the company. Generates Scientific Research."}
/>
<AutoAssignJob
@ -464,8 +398,7 @@ function AutoManagement(props: IProps): React.ReactElement {
}
export function IndustryOffice(props: IProps): React.ReactElement {
const [employeeManualAssignMode, setEmployeeManualAssignMode] =
useState(false);
const [employeeManualAssignMode, setEmployeeManualAssignMode] = useState(false);
const buttonStyle = {
fontSize: "13px",
@ -530,28 +463,18 @@ export function IndustryOffice(props: IProps): React.ReactElement {
<p>
Size: {props.office.employees.length} / {props.office.size} employees
</p>
<button
className={hireEmployeeButtonClass}
onClick={openHireEmployeePopup}
style={buttonStyle}
>
<button className={hireEmployeeButtonClass} onClick={openHireEmployeePopup} style={buttonStyle}>
Hire Employee
{props.office.employees.length === 0 && (
<span className={"tooltiptext"}>
You'll need to hire some employees to get your operations started!
It's recommended to have at least one employee in every position
You'll need to hire some employees to get your operations started! It's recommended to have at least one
employee in every position
</span>
)}
</button>
<button
className={autohireEmployeeButtonClass}
onClick={autohireEmployeeButtonOnClick}
style={buttonStyle}
>
<button className={autohireEmployeeButtonClass} onClick={autohireEmployeeButtonOnClick} style={buttonStyle}>
Autohire Employee
<span className={"tooltiptext"}>
Automatically hires an employee and gives him/her a random name
</span>
<span className={"tooltiptext"}>Automatically hires an employee and gives him/her a random name</span>
</button>
<br />
<button
@ -561,9 +484,7 @@ export function IndustryOffice(props: IProps): React.ReactElement {
disabled={props.corp.funds.lt(0)}
>
Upgrade size
<span className={"tooltiptext"}>
Upgrade the office's size so that it can hold more employees!
</span>
<span className={"tooltiptext"}>Upgrade the office's size so that it can hold more employees!</span>
</button>
{!props.division.hasResearch("AutoPartyManager") && (
<button
@ -574,33 +495,19 @@ export function IndustryOffice(props: IProps): React.ReactElement {
>
Throw Party
<span className={"tooltiptext"}>
"Throw an office party to increase your employee's morale and
happiness"
"Throw an office party to increase your employee's morale and happiness"
</span>
</button>
)}
<br />
<div>
<SwitchButton
manualMode={employeeManualAssignMode}
switchMode={setEmployeeManualAssignMode}
/>
<SwitchButton manualMode={employeeManualAssignMode} switchMode={setEmployeeManualAssignMode} />
</div>
{employeeManualAssignMode ? (
<ManualManagement
corp={props.corp}
division={props.division}
office={props.office}
player={props.player}
/>
<ManualManagement corp={props.corp} division={props.division} office={props.office} player={props.player} />
) : (
<AutoManagement
corp={props.corp}
division={props.division}
office={props.office}
player={props.player}
/>
<AutoManagement corp={props.corp} division={props.division} office={props.office} player={props.player} />
)}
</div>
);

@ -40,19 +40,16 @@ export function IndustryOverview(props: IProps): React.ReactElement {
break;
case Industries.Pharmaceutical:
createProductButtonText = "Create Drug";
createProductPopupText =
"Design and develop a new pharmaceutical drug!";
createProductPopupText = "Design and develop a new pharmaceutical drug!";
break;
case Industries.Computer:
case "Computer":
createProductButtonText = "Create Product";
createProductPopupText =
"Design and manufacture a new computer hardware product!";
createProductPopupText = "Design and manufacture a new computer hardware product!";
break;
case Industries.Robotics:
createProductButtonText = "Design Robot";
createProductPopupText =
"Design and create a new robot or robotic system!";
createProductPopupText = "Design and create a new robot or robotic system!";
break;
case Industries.Software:
createProductButtonText = "Develop Software";
@ -82,9 +79,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
const hasMaxProducts = props.division.hasMaximumNumberProducts();
const className = hasMaxProducts
? "a-link-button-inactive tooltip"
: "std-button";
const className = hasMaxProducts ? "a-link-button-inactive tooltip" : "std-button";
const buttonStyle = {
margin: "6px",
display: "inline-block",
@ -110,8 +105,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
{createProductButtonText}
{hasMaxProducts && (
<span className={"tooltiptext"}>
You have reached the maximum number of products:{" "}
{props.division.getMaximumNumberProducts()}
You have reached the maximum number of products: {props.division.getMaximumNumberProducts()}
</span>
)}
</button>
@ -120,9 +114,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
function renderText(): React.ReactElement {
const vechain = props.corp.unlockUpgrades[4] === 1;
const profit = props.division.lastCycleRevenue
.minus(props.division.lastCycleExpenses)
.toNumber();
const profit = props.division.lastCycleRevenue.minus(props.division.lastCycleExpenses).toNumber();
let advertisingInfo = false;
const advertisingFactors = props.division.getAdvertisingFactors();
@ -158,15 +150,9 @@ export function IndustryOverview(props: IProps): React.ReactElement {
"production multiplier of your entire Division.<br><br>" +
"Below are approximations for how effective each material is at boosting " +
"this industry's production multiplier (Bigger bars = more effective):<br><br>" +
`Hardware:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(
props.division.hwFac,
)}<br>` +
`Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(
props.division.robFac,
)}<br>` +
`AI Cores:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(
props.division.aiFac,
)}<br>` +
`Hardware:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(props.division.hwFac)}<br>` +
`Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(props.division.robFac)}<br>` +
`AI Cores:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(props.division.aiFac)}<br>` +
`Real Estate: ${convertEffectFacToGraphic(props.division.reFac)}`,
);
}
@ -181,35 +167,21 @@ export function IndustryOverview(props: IProps): React.ReactElement {
return (
<div>
Industry: {props.division.type} (Corp Funds:{" "}
<Money money={props.corp.funds.toNumber()} />)
Industry: {props.division.type} (Corp Funds: <Money money={props.corp.funds.toNumber()} />)
<br /> <br />
Awareness: {numeralWrapper.format(
props.division.awareness,
"0.000",
)}{" "}
<br />
Popularity: {numeralWrapper.format(
props.division.popularity,
"0.000",
)}{" "}
<br />
Awareness: {numeralWrapper.format(props.division.awareness, "0.000")} <br />
Popularity: {numeralWrapper.format(props.division.popularity, "0.000")} <br />
{advertisingInfo !== false && (
<p className={"tooltip"}>
Advertising Multiplier: x
{numeralWrapper.format(totalAdvertisingFac, "0.000")}
Advertising Multiplier: x{numeralWrapper.format(totalAdvertisingFac, "0.000")}
<span className={"tooltiptext cmpy-mgmt-advertising-info"}>
Total multiplier for this industrys sales due to its awareness and
popularity
Total multiplier for this industrys sales due to its awareness and popularity
<br />
Awareness Bonus: x
{numeralWrapper.format(Math.pow(awarenessFac, 0.85), "0.000")}
Awareness Bonus: x{numeralWrapper.format(Math.pow(awarenessFac, 0.85), "0.000")}
<br />
Popularity Bonus: x
{numeralWrapper.format(Math.pow(popularityFac, 0.85), "0.000")}
Popularity Bonus: x{numeralWrapper.format(Math.pow(popularityFac, 0.85), "0.000")}
<br />
Ratio Multiplier: x
{numeralWrapper.format(Math.pow(ratioFac, 0.85), "0.000")}
Ratio Multiplier: x{numeralWrapper.format(Math.pow(ratioFac, 0.85), "0.000")}
</span>
</p>
)}
@ -224,8 +196,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
</td>
<td>
<p>
<Money money={props.division.lastCycleRevenue.toNumber()} /> /
s
<Money money={props.division.lastCycleRevenue.toNumber()} /> / s
</p>
</td>
</tr>
@ -235,8 +206,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
</td>
<td>
<p>
<Money money={props.division.lastCycleExpenses.toNumber()} />{" "}
/ s
<Money money={props.division.lastCycleExpenses.toNumber()} /> / s
</p>
</td>
</tr>
@ -254,11 +224,10 @@ export function IndustryOverview(props: IProps): React.ReactElement {
</table>
<br />
<p className={"tooltip"}>
Production Multiplier:{" "}
{numeralWrapper.format(props.division.prodMult, "0.00")}
Production Multiplier: {numeralWrapper.format(props.division.prodMult, "0.00")}
<span className={"tooltiptext"}>
Production gain from owning production-boosting materials such as
hardware, Robots, AI Cores, and Real Estate
Production gain from owning production-boosting materials such as hardware, Robots, AI Cores, and Real
Estate
</span>
</p>
<div className={"help-tip"} onClick={productionMultHelpTipOnClick}>
@ -266,11 +235,9 @@ export function IndustryOverview(props: IProps): React.ReactElement {
</div>
<br /> <br />
<p className={"tooltip"}>
Scientific Research:{" "}
{numeralWrapper.format(props.division.sciResearch.qty, "0.000a")}
Scientific Research: {numeralWrapper.format(props.division.sciResearch.qty, "0.000a")}
<span className={"tooltiptext"}>
Scientific Research increases the quality of the materials and
products that you produce.
Scientific Research increases the quality of the materials and products that you produce.
</span>
</p>
<button className={"help-tip"} onClick={openResearchPopup}>
@ -340,15 +307,9 @@ export function IndustryOverview(props: IProps): React.ReactElement {
function renderUpgrade(props: IRenderUpgradeProps): React.ReactElement {
return (
<div
className={"cmpy-mgmt-upgrade-div tooltip"}
onClick={props.onClick}
key={props.key}
>
<div className={"cmpy-mgmt-upgrade-div tooltip"} onClick={props.onClick} key={props.key}>
{props.text}
{props.tooltip != null && (
<span className={"tooltiptext"}>{props.tooltip}</span>
)}
{props.tooltip != null && <span className={"tooltiptext"}>{props.tooltip}</span>}
</div>
);
}
@ -359,9 +320,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
<div className={"cmpy-mgmt-industry-overview-panel"}>
{renderText()}
<br />
<u className={"industry-purchases-and-upgrades-header"}>
Purchases & Upgrades
</u>
<u className={"industry-purchases-and-upgrades-header"}>Purchases & Upgrades</u>
<br />
{renderUpgrades()} <br />
{props.division.makesProducts && makeProductButton}

Some files were not shown because too many files have changed in this diff Show More