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", "trailingComma": "all",
"tabWidth": 2 "tabWidth": 2,
"printWidth": 120
} }

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

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

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

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

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

@ -28,25 +28,18 @@
a.async = 1; a.async = 1;
a.src = g; a.src = g;
m.parentNode.insertBefore(a, m); 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>
<script> <script>
ga( ga("create", "UA-100157497-1", "auto");
"create",
"UA-100157497-1",
"auto",
);
ga("send", "pageview"); ga("send", "pageview");
</script> </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> <body>
<div id="entire-game-container" style="visibility: hidden"> <div id="entire-game-container" style="visibility: hidden">
<div id="mainmenu-container"> <div id="mainmenu-container">
@ -54,9 +47,7 @@
<ul id="mainmenu" class="mainmenu noscrollbar"> <ul id="mainmenu" class="mainmenu noscrollbar">
<!-- Hacking dropdown --> <!-- Hacking dropdown -->
<li id="hacking-menu-header-li"> <li id="hacking-menu-header-li">
<button id="hacking-menu-header" class="mainmenu-accordion-header noselect"> <button id="hacking-menu-header" class="mainmenu-accordion-header noselect">Hacking</button>
Hacking
</button>
</li> </li>
<li id="terminal-tab" class="mainmenu-accordion-panel noselect"> <li id="terminal-tab" class="mainmenu-accordion-panel noselect">
<button id="terminal-menu-link">Terminal</button> <button id="terminal-menu-link">Terminal</button>
@ -69,15 +60,12 @@
</li> </li>
<li id="create-program-tab" class="mainmenu-accordion-panel noselect"> <li id="create-program-tab" class="mainmenu-accordion-panel noselect">
<button id="create-program-menu-link">Create Program</button> <button id="create-program-menu-link">Create Program</button>
<span id="create-program-notification" class="notification-off"> <span id="create-program-notification" class="notification-off"> </span>
</span>
</li> </li>
<!-- Character dropdown --> <!-- Character dropdown -->
<li id="character-menu-header-li"> <li id="character-menu-header-li">
<button id="character-menu-header" class="mainmenu-accordion-header noselect"> <button id="character-menu-header" class="mainmenu-accordion-header noselect">Character</button>
Character
</button>
</li> </li>
<li id="stats-tab" class="mainmenu-accordion-panel noselect"> <li id="stats-tab" class="mainmenu-accordion-panel noselect">
<button id="stats-menu-link">Stats</button> <button id="stats-menu-link">Stats</button>
@ -87,13 +75,10 @@
<span id="factions-notification" class="notification-off"> </span> <span id="factions-notification" class="notification-off"> </span>
</li> </li>
<li id="augmentations-tab" class="mainmenu-accordion-panel noselect"> <li id="augmentations-tab" class="mainmenu-accordion-panel noselect">
<button id="augmentations-menu-link" style="overflow: hidden; <button id="augmentations-menu-link" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
text-overflow: ellipsis;
white-space: nowrap;">
Augmentations Augmentations
</button> </button>
<span id="augmentations-notification" class="notification-off"> <span id="augmentations-notification" class="notification-off"> </span>
</span>
</li> </li>
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel noselect"> <li id="hacknet-nodes-tab" class="mainmenu-accordion-panel noselect">
<button id="hacknet-nodes-menu-link">Hacknet</button> <button id="hacknet-nodes-menu-link">Hacknet</button>
@ -104,9 +89,7 @@
<!-- World dropdown --> <!-- World dropdown -->
<li id="world-menu-header-li"> <li id="world-menu-header-li">
<button id="world-menu-header" class="mainmenu-accordion-header noselect"> <button id="world-menu-header" class="mainmenu-accordion-header noselect">World</button>
World
</button>
</li> </li>
<li id="city-tab" class="mainmenu-accordion-panel noselect"> <li id="city-tab" class="mainmenu-accordion-panel noselect">
<button id="city-menu-link">City</button> <button id="city-menu-link">City</button>
@ -131,9 +114,7 @@
</li> </li>
<li id="help-menu-header-li"> <li id="help-menu-header-li">
<button id="help-menu-header" class="mainmenu-accordion-header noselect"> <button id="help-menu-header" class="mainmenu-accordion-header noselect">Help</button>
Help
</button>
</li> </li>
<li id="milestones-tab" class="mainmenu-accordion-panel noselect"> <li id="milestones-tab" class="mainmenu-accordion-panel noselect">
<button id="milestones-menu-link">Milestones</button> <button id="milestones-menu-link">Milestones</button>
@ -188,17 +169,34 @@
<fieldset> <fieldset>
<label for="script-editor-option-highlightactiveline">Highlight Active Line</label> <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>
<fieldset> <fieldset>
<label for="script-editor-option-showinvisibles">Show Invisibles</label> <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>
<fieldset> <fieldset>
<label for="script-editor-option-usesofttab">Use Soft Tab</label> <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>
<fieldset id="script-editor-option-flex1-fieldset"></fieldset> <fieldset id="script-editor-option-flex1-fieldset"></fieldset>
@ -224,7 +222,14 @@
<tr id="terminal-input"> <tr id="terminal-input">
<td id="terminal-input-td" tabindex="2"> <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> </td>
</tr> </tr>
</table> </table>
@ -238,19 +243,18 @@
<!-- Active scripts info page --> <!-- Active scripts info page -->
<div id="active-scripts-container" class="generic-menupage-container"> <div id="active-scripts-container" class="generic-menupage-container">
<p id="active-scripts-text"> <p id="active-scripts-text">
This page displays a list of all of your scripts that are currently This page displays a list of all of your scripts that are currently running across every machine. It also
running across every machine. It also provides information about each provides information about each script's production. The scripts are categorized by the hostname of the
script's production. The scripts are categorized by the hostname of servers on which they are running.
the servers on which they are running.
</p> </p>
<p id="active-scripts-total-prod"> <p id="active-scripts-total-prod">
Total online production of Active scripts: Total online production of Active scripts:
<span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br />
sec</span><br/>
Total online production since last Aug installation: Total online production since last Aug installation:
<span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span> <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> (<span class="money-gold"
/ sec</span>) ><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span
>)
</p> </p>
<ul class="active-scripts-list" id="active-scripts-list" style="list-style: none"></ul> <ul class="active-scripts-list" id="active-scripts-list" style="list-style: none"></ul>
</div> </div>
@ -263,11 +267,9 @@
<!-- Create a program(executable) --> <!-- Create a program(executable) -->
<div id="create-program-container" class="generic-menupage-container"> <div id="create-program-container" class="generic-menupage-container">
<p id="create-program-page-text"> <p id="create-program-page-text">
This page displays any programs that you are able to create. Writing This page displays any programs that you are able to create. Writing the code for a program takes time, which
the code for a program takes time, which can vary based on how complex can vary based on how complex the program is. If you are working on creating a program you can cancel at any
the program is. If you are working on creating a program you can time. Your progress will be saved and you can continue later.
cancel at any time. Your progress will be saved and you can continue
later.
</p> </p>
<ul id="create-program-list"></ul> <ul id="create-program-list"></ul>
@ -291,28 +293,76 @@
<!-- Tutorial content --> <!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container"> <div id="tutorial-container" class="generic-menupage-container">
<h1>Tutorial (AKA Links to Documentation)</h1> <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"> <a
Getting Started</a><br/><br/> id="tutorial-getting-started-link"
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html"> class="a-link-button"
Servers & Networking</a><br/><br/> target="_blank"
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html"> href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html"
Hacking</a><br/><br/> >
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html"> Getting Started</a
Scripts</a><br/><br/> ><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"> <a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/netscript.html">
Netscript Programming Language</a><br/><br/> Netscript Programming Language</a
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html"> ><br /><br />
Traveling</a><br/><br/> <a
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html"> class="a-link-button"
Companies</a><br/><br/> target="_blank"
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html"> href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html"
Infiltration</a><br/><br/> >
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html"> Traveling</a
Factions</a><br/><br/> ><br /><br />
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html"> <a
Augmentations</a><br/><br/> 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"> <a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/shortcuts.html">
Keyboard Shortcuts</a> Keyboard Shortcuts</a
>
</div> </div>
<!-- Location (visiting a location in World) --> <!-- Location (visiting a location in World) -->
@ -342,12 +392,8 @@
<div id="yes-no-text-input-box-content" class="popup-box-content"> <div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"></p> <p id="yes-no-text-input-box-text"></p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" /> <input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<button id="yes-no-text-input-box-yes" class="popup-box-button"> <button id="yes-no-text-input-box-yes" class="popup-box-button">Yes</button>
Yes <button id="yes-no-text-input-box-no" class="popup-box-button">No</button>
</button>
<button id="yes-no-text-input-box-no" class="popup-box-button">
No
</button>
</div> </div>
</div> </div>
@ -359,15 +405,10 @@
<p id="faction-invitation-box-warning"> <p id="faction-invitation-box-warning">
Would you like to join? <br /> Would you like to join? <br />
<br /> <br />
Warning: Joining this faction may prevent you from joining other Warning: Joining this faction may prevent you from joining other factions during this run!
factions during this run!
</p> </p>
<button id="faction-invitation-box-yes" class="popup-box-button"> <button id="faction-invitation-box-yes" class="popup-box-button">Join!</button>
Join! <button id="faction-invitation-box-no" class="popup-box-button">Decide later</button>
</button>
<button id="faction-invitation-box-no" class="popup-box-button">
Decide later
</button>
</div> </div>
</div> </div>
@ -376,15 +417,11 @@
<div id="infiltration-box-content" class="popup-box-content"> <div id="infiltration-box-content" class="popup-box-content">
<p id="infiltration-box-text"></p> <p id="infiltration-box-text"></p>
<button id="infiltration-box-sell" class="a-link-button"> <button id="infiltration-box-sell" class="a-link-button">Sell on Black Market</button>
Sell on Black Market
</button>
<br /><br /> <br /><br />
<select id="infiltration-faction-select" class="dropdown"></select> <select id="infiltration-faction-select" class="dropdown"></select>
<br /> <br />
<button id="infiltration-box-faction" class="a-link-button"> <button id="infiltration-box-faction" class="a-link-button">Give to Faction for Reputation</button>
Give to Faction for Reputation
</button>
</div> </div>
</div> </div>
@ -395,9 +432,7 @@
<div id="work-in-progress-container" class="generic-fullscreen-container"> <div id="work-in-progress-container" class="generic-fullscreen-container">
<p id="work-in-progress-text"></p> <p id="work-in-progress-text"></p>
<button id="work-in-progress-cancel-button" class="work-button"> <button id="work-in-progress-cancel-button" class="work-button">Cancel Work</button>
Cancel Work
</button>
<button id="work-in-progress-something-else-button" class="work-button"> <button id="work-in-progress-something-else-button" class="work-button">
Do something else simultaneously Do something else simultaneously
</button> </button>
@ -428,12 +463,8 @@
<!-- ReactJS Component --> <!-- ReactJS Component -->
</div> </div>
<div class="character-quick-options noselect"> <div class="character-quick-options noselect">
<button id="character-overview-save-button" class="character-overview-btn"> <button id="character-overview-save-button" class="character-overview-btn">Save Game</button>
Save Game <button id="character-overview-options-button" class="character-overview-btn">Options</button>
</button>
<button id="character-overview-options-button" class="character-overview-btn">
Options
</button>
</div> </div>
</div> </div>
</div> </div>
@ -446,148 +477,210 @@
<!-- Game Options --> <!-- Game Options -->
<div id="game-options-container" class="popup-box-container"> <div id="game-options-container" class="popup-box-container">
<div id="game-options-content" class="game-options-box"> <div id="game-options-content" class="game-options-box">
<button id="game-options-close-button" aria-label="close options dialog"> <button id="game-options-close-button" aria-label="close options dialog">&times;</button>
&times;
</button>
<h1>Game Options</h1> <h1>Game Options</h1>
<br /> <br />
<div id="game-options-left-panel"> <div id="game-options-left-panel">
<!-- Netscript execution time --> <!-- Netscript execution time -->
<fieldset> <fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip">Netscript exec time:&nbsp; <label for="settingsNSExecTimeRangeVal" class="tooltip"
>Netscript exec time:&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The minimum number of milliseconds it takes to execute an The minimum number of milliseconds it takes to execute an operation in Netscript. Setting this too low
operation in Netscript. Setting this too low can result in can result in poor performance if you have many scripts running. The default value is 25ms.
poor performance if you have many scripts running. The default
value is 25ms.
</span> </span>
</label> </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> <em id="settingsNSExecTimeRangeValLabel" style="font-style: normal"></em>
</fieldset> </fieldset>
<!-- Log capacity --> <!-- Log capacity -->
<fieldset> <fieldset>
<label for="settingsNSLogRangeVal" class="tooltip">Netscript log size:&nbsp;&nbsp; <label for="settingsNSLogRangeVal" class="tooltip"
>Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The maximum number of lines a script's logs can hold. Setting The maximum number of lines a script's logs can hold. Setting this too high can cause the game to use
this too high can cause the game to use a lot of memory if you a lot of memory if you have many scripts running. The default value is 50.
have many scripts running. The default value is 50.
</span> </span>
</label> </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> <em id="settingsNSLogRangeValLabel" style="font-style: normal"></em>
</fieldset> </fieldset>
<!-- Port capacity --> <!-- Port capacity -->
<fieldset> <fieldset>
<label for="settingsNSPortRangeVal" class="tooltip">Netscript port size:&nbsp; <label for="settingsNSPortRangeVal" class="tooltip"
>Netscript port size:&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The maximum number of entries that can be written to a port The maximum number of entries that can be written to a port using Netscript's write() function.
using Netscript's write() function. Setting this too high can Setting this too high can cause the game to use a lot of memory. The default value is 50.
cause the game to use a lot of memory. The default value is
50.
</span> </span>
</label> </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> <em id="settingsNSPortRangeValLabel" style="font-style: normal"></em>
</fieldset> </fieldset>
<!-- Autosave Interval --> <!-- Autosave Interval -->
<fieldset> <fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip">Autosave Interval:&nbsp;&nbsp;&nbsp; <label for="settingsAutosaveIntervalVal" class="tooltip"
>Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext"> <span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to The time (in seconds) between each autosave. Set to 0 to disable autosave.
disable autosave.
</span> </span>
</label> </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> <em id="settingsAutosaveIntervalValLabel" style="font-style: normal"></em>
</fieldset> </fieldset>
<!-- Suppress messages --> <!-- Suppress messages -->
<fieldset> <fieldset>
<label for="settingsSuppressMessages" class="tooltip">Suppress Messages: <label for="settingsSuppressMessages" class="tooltip"
>Suppress Messages:
<span class="tooltiptext"> <span class="tooltiptext">
If this is set, then any messages you receive will not appear If this is set, then any messages you receive will not appear as popups on the screen. They will still
as popups on the screen. They will still get sent to your home get sent to your home computer as '.msg' files and can be viewed with the 'cat' Terminal command.
computer as '.msg' files and can be viewed with the 'cat'
Terminal command.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressMessages" id="settingsSuppressMessages"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressMessages"
id="settingsSuppressMessages"
/>
</fieldset> </fieldset>
<!-- Suppress faction invites --> <!-- Suppress faction invites -->
<fieldset> <fieldset>
<label for="settingsSuppressFactionInvites" class="tooltip">Suppress Faction Invites: <label for="settingsSuppressFactionInvites" class="tooltip"
>Suppress Faction Invites:
<span class="tooltiptexthigh"> <span class="tooltiptexthigh">
If this is set, then any faction invites you receive will not If this is set, then any faction invites you receive will not appear as popups on the screen. Your
appear as popups on the screen. Your outstanding faction outstanding faction invites can be viewed in the 'Factions' page.
invites can be viewed in the 'Factions' page.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressFactionInvites"
id="settingsSuppressFactionInvites"
/>
</fieldset> </fieldset>
<!-- Suppress travel confirmation --> <!-- Suppress travel confirmation -->
<fieldset> <fieldset>
<label for="settingsSuppressTravelConfirmation" class="tooltip">Suppress Travel Confirmation: <label for="settingsSuppressTravelConfirmation" class="tooltip"
>Suppress Travel Confirmation:
<span class="tooltiptexthigh"> <span class="tooltiptexthigh">
If this is set, the confirmation message before traveling will If this is set, the confirmation message before traveling will not show up. You will automatically be
not show up. You will automatically be deducted the travel deducted the travel cost as soon as you click.
cost as soon as you click.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressTravelConfirmation"
id="settingsSuppressTravelConfirmation"
/>
</fieldset> </fieldset>
<!-- Suppress buy aug confirmation --> <!-- Suppress buy aug confirmation -->
<fieldset> <fieldset>
<label for="settingsSuppressBuyAugmentationConfirmation" class="tooltip">Suppress buy augmentation confirmation: <label for="settingsSuppressBuyAugmentationConfirmation" class="tooltip"
>Suppress buy augmentation confirmation:
<span class="tooltiptexthigh"> <span class="tooltiptexthigh">
If this is set, the confirmation message before buying If this is set, the confirmation message before buying augmentation will not show up.
augmentation will not show up.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressBuyAugmentationConfirmation" id="settingsSuppressBuyAugmentationConfirmation"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressBuyAugmentationConfirmation"
id="settingsSuppressBuyAugmentationConfirmation"
/>
</fieldset> </fieldset>
<!-- Hospitalization Popup --> <!-- Hospitalization Popup -->
<fieldset> <fieldset>
<label for="settingsSuppressHospitalizationPopup" class="tooltip">Suppress Hospitalization popup: <label for="settingsSuppressHospitalizationPopup" class="tooltip"
>Suppress Hospitalization popup:
<span class="tooltiptexthigh"> <span class="tooltiptexthigh">
If this is set, a popup message will no longer be shown when If this is set, a popup message will no longer be shown when you are hospitalized after taking too
you are hospitalized after taking too much damage. much damage.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressHospitalizationPopup" id="settingsSuppressHospitalizationPopup"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressHospitalizationPopup"
id="settingsSuppressHospitalizationPopup"
/>
</fieldset> </fieldset>
<!-- Suppress Bladeburner popups --> <!-- Suppress Bladeburner popups -->
<fieldset> <fieldset>
<label for="settingsSuppressBladeburnerPopup" class="tooltip">Suppress Bladeburner Popup: <label for="settingsSuppressBladeburnerPopup" class="tooltip"
>Suppress Bladeburner Popup:
<span class="tooltiptext"> <span class="tooltiptext">
If this is set, then having your Bladeburner actions If this is set, then having your Bladeburner actions interrupted by being busy with something else
interrupted by being busy with something else will not display will not display a popup message.
a popup message.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsSuppressBladeburnerPopup" id="settingsSuppressBladeburnerPopup"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressBladeburnerPopup"
id="settingsSuppressBladeburnerPopup"
/>
</fieldset> </fieldset>
<!-- Disable Terminal and Navigation Shortcuts --> <!-- Disable Terminal and Navigation Shortcuts -->
<fieldset> <fieldset>
<label for="settingsDisableHotkeys" class="tooltip">Disable Hotkeys: <label for="settingsDisableHotkeys" class="tooltip"
>Disable Hotkeys:
<span class="tooltiptexthigh"> <span class="tooltiptexthigh">
If this is set, then most hotkeys (keyboard shortcuts) in the If this is set, then most hotkeys (keyboard shortcuts) in the game are disabled. This includes
game are disabled. This includes Terminal commands, hotkeys to Terminal commands, hotkeys to navigate between different parts of the game, and the "Save and Close
navigate between different parts of the game, and the "Save (Ctrl + b)" hotkey in the Text Editor.
and Close (Ctrl + b)" hotkey in the Text Editor.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys" /> <input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys" />
@ -595,31 +688,40 @@
<!-- View city as list of buttons instead of ASCII art. --> <!-- View city as list of buttons instead of ASCII art. -->
<fieldset> <fieldset>
<label for="settingsDisableASCIIArt" class="tooltip">Disable ASCII art: <label for="settingsDisableASCIIArt" class="tooltip"
<span class="tooltiptexthigh"> >Disable ASCII art:
If this is set all ASCII art will be disabled. <span class="tooltiptexthigh"> If this is set all ASCII art will be disabled. </span>
</span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsDisableASCIIArt"
id="settingsDisableASCIIArt"
/>
</fieldset> </fieldset>
<!-- Disable text effects such as corruption. --> <!-- Disable text effects such as corruption. -->
<fieldset> <fieldset>
<label for="settingsDisableTextEffects" class="tooltip">Disable Text Effects: <label for="settingsDisableTextEffects" class="tooltip"
>Disable Text Effects:
<span class="tooltiptexthigh"> <span class="tooltiptexthigh">
If this is set, text effects will not be displayed. This can If this is set, text effects will not be displayed. This can help if text is difficult to read in
help if text is difficult to read in certain areas. certain areas.
</span> </span>
</label> </label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableTextEffects" id="settingsDisableTextEffects"/> <input
class="optionCheckbox"
type="checkbox"
name="settingsDisableTextEffects"
id="settingsDisableTextEffects"
/>
</fieldset> </fieldset>
<!-- Locale for displaying numbers --> <!-- Locale for displaying numbers -->
<fieldset> <fieldset>
<label for="settingsLocale" class="tooltip">Locale: <label for="settingsLocale" class="tooltip"
<span class="tooltiptexthigh"> >Locale:
Sets the locale for displaying numbers. Defaults to 'en' <span class="tooltiptexthigh"> Sets the locale for displaying numbers. Defaults to 'en' </span>
</span>
</label> </label>
<select name="settingsLocale" id="settingsLocale" class="dropdown"> <select name="settingsLocale" id="settingsLocale" class="dropdown">
<option value="en">en</option> <option value="en">en</option>
@ -643,9 +745,19 @@
<!-- Donate button --> <!-- Donate button -->
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank"> <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="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="hidden"
<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!"/> 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" /> <img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form> </form>
</div> </div>
@ -653,49 +765,38 @@
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> <a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank">
Changelog Changelog
</a> </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://discord.gg/TFc3hKD" target="_blank">Discord</a>
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</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="save-game-link" class="a-link-button">Save Game</button>
<button id="delete-game-link" class="a-link-button"> <button id="delete-game-link" class="a-link-button">Delete Game</button>
Delete Game <button id="export-game-link" class="a-link-button">Export Game</button>
</button>
<button id="export-game-link" class="a-link-button">
Export Game
</button>
<input type="file" id="import-game-file-selector" name="file" /> <input type="file" id="import-game-file-selector" name="file" />
<button id="import-game-link" class="a-link-button"> <button id="import-game-link" class="a-link-button">Import Game</button>
Import Game <button id="copy-save-to-clipboard-link" class="std-button">Copy Save data to Clipboard</button>
</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"> <button id="debug-delete-scripts-link" class="a-link-button tooltip">
Force kill all active scripts Force kill all active scripts
<span class="tooltiptextleft"> <span class="tooltiptextleft">
Forcefully kill all active running scripts, in case there is a Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the
bug or some unexpected issue with the game. After using this, game. After using this, save the game and then reload the page. This is different then normal kill in
save the game and then reload the page. This is different then that normal kill will tell the script to shut down while force kill just removes the references to it
normal kill in that normal kill will tell the script to shut (and it should crash on it's own). This will not remove the files on your computer. Just forcefully kill
down while force kill just removes the references to it (and it all running instance of all scripts.
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> </span>
</button> </button>
<button id="debug-soft-reset" class="a-link-button tooltip"> <button id="debug-soft-reset" class="a-link-button tooltip">
Soft Reset Soft Reset
<span class="tooltiptextleft"> <span class="tooltiptextleft">
Perform a soft reset. Resets everything as if you had just Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
purchased an Augmentation.
</span> </span>
</button> </button>
<button id="debug-files" class="a-link-button tooltip"> <button id="debug-files" class="a-link-button tooltip">
Diagnose files Diagnose files
<span class="tooltiptextleft"> <span class="tooltiptextleft">
If your save file is extremely big you can use this button to If your save file is extremely big you can use this button to view a map of all the files on every
view a map of all the files on every server. Be careful there server. Be careful there might be spoilers.
might be spoilers.
</span> </span>
</button> </button>
</div> </div>
@ -725,10 +826,11 @@
</div> </div>
</div> </div>
<div id="unclickable" style="display: none"> <div id="unclickable" style="display: none">Click on this to upgrade your Source-File -1!</div>
Click on this to upgrade your Source-File -1! <script type="text/javascript" src="dist/vendor.bundle.js"></script>
</div> <script type="text/javascript" src="dist/engine.bundle.js"></script>
<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> <script type="text/javascript" src="dist/engineStyle.bundle.js"></script>
</body>
<!-- Misc Scripts --> <!-- Misc Scripts -->
<script src="src/ThirdParty/raphael.min.js"></script> <script src="src/ThirdParty/raphael.min.js"></script>

@ -2,25 +2,25 @@ const numSpaces = 4;
const maxLineLength = 160; const maxLineLength = 160;
module.exports = { module.exports = {
"env": { env: {
"es6": true, es6: true,
"node": true node: true,
}, },
"extends": "eslint:recommended", extends: "eslint:recommended",
"parserOptions": { parserOptions: {
"ecmaFeatures": { ecmaFeatures: {
"experimentalObjectRestSpread": true experimentalObjectRestSpread: true,
}, },
"ecmaVersion": 8, ecmaVersion: 8,
"sourceType": "module" sourceType: "module",
}, },
"rules": { rules: {
"accessor-pairs": [ "accessor-pairs": [
"error", "error",
{ {
"getWithoutSet": false, getWithoutSet: false,
"setWithoutGet": true setWithoutGet: true,
} },
], ],
"array-bracket-newline": ["error"], "array-bracket-newline": ["error"],
"array-bracket-spacing": ["error"], "array-bracket-spacing": ["error"],
@ -33,50 +33,35 @@ module.exports = {
"block-spacing": ["error"], "block-spacing": ["error"],
"brace-style": ["error"], "brace-style": ["error"],
"callback-return": ["error"], "callback-return": ["error"],
"camelcase": ["error"], camelcase: ["error"],
"capitalized-comments": ["error"], "capitalized-comments": ["error"],
"class-methods-use-this": ["error"], "class-methods-use-this": ["error"],
"comma-dangle": ["error"], "comma-dangle": ["error"],
"comma-spacing": ["error"], "comma-spacing": ["error"],
"comma-style": [ "comma-style": ["error", "last"],
"error", complexity: ["error"],
"last" "computed-property-spacing": ["error", "never"],
],
"complexity": ["error"],
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": ["error"], "consistent-return": ["error"],
"consistent-this": ["error"], "consistent-this": ["error"],
"constructor-super": ["error"], "constructor-super": ["error"],
"curly": ["error"], curly: ["error"],
"default-case": ["error"], "default-case": ["error"],
"dot-location": [ "dot-location": ["error", "property"],
"error",
"property"
],
"dot-notation": ["error"], "dot-notation": ["error"],
"eol-last": ["error"], "eol-last": ["error"],
"eqeqeq": ["error"], eqeqeq: ["error"],
"for-direction": ["error"], "for-direction": ["error"],
"func-call-spacing": ["error"], "func-call-spacing": ["error"],
"func-name-matching": ["error"], "func-name-matching": ["error"],
"func-names": [ "func-names": ["error", "never"],
"error",
"never"
],
"func-style": ["error"], "func-style": ["error"],
"function-paren-newline": ["error"], "function-paren-newline": ["error"],
"generator-star-spacing": [ "generator-star-spacing": ["error", "before"],
"error",
"before"
],
"getter-return": [ "getter-return": [
"error", "error",
{ {
"allowImplicit": false allowImplicit: false,
} },
], ],
"global-require": ["error"], "global-require": ["error"],
"guard-for-in": ["error"], "guard-for-in": ["error"],
@ -84,52 +69,37 @@ module.exports = {
"id-blacklist": ["error"], "id-blacklist": ["error"],
"id-length": ["error"], "id-length": ["error"],
"id-match": ["error"], "id-match": ["error"],
"implicit-arrow-linebreak": [ "implicit-arrow-linebreak": ["error", "beside"],
"error", indent: [
"beside"
],
"indent": [
"error", "error",
numSpaces, numSpaces,
{ {
"SwitchCase": 1 SwitchCase: 1,
} },
], ],
"init-declarations": ["error"], "init-declarations": ["error"],
"jsx-quotes": ["error"], "jsx-quotes": ["error"],
"key-spacing": ["error"], "key-spacing": ["error"],
"keyword-spacing": ["error"], "keyword-spacing": ["error"],
"line-comment-position": ["error"], "line-comment-position": ["error"],
"linebreak-style": [ "linebreak-style": ["error", "windows"],
"error",
"windows"
],
"lines-around-comment": ["error"], "lines-around-comment": ["error"],
"lines-between-class-members": ["error"], "lines-between-class-members": ["error"],
"max-depth": ["error"], "max-depth": ["error"],
"max-len": [ "max-len": ["error", maxLineLength],
"error",
maxLineLength
],
"max-lines": [ "max-lines": [
"error", "error",
{ {
"skipBlankLines": true, skipBlankLines: true,
"skipComments": true skipComments: true,
} },
], ],
"max-nested-callbacks": ["error"], "max-nested-callbacks": ["error"],
"max-params": ["error"], "max-params": ["error"],
"max-statements": ["error"], "max-statements": ["error"],
"max-statements-per-line": ["error"], "max-statements-per-line": ["error"],
"multiline-comment-style": [ "multiline-comment-style": ["off", "starred-block"],
"off", "multiline-ternary": ["error", "never"],
"starred-block"
],
"multiline-ternary": [
"error",
"never"
],
"new-cap": ["error"], "new-cap": ["error"],
"new-parens": ["error"], "new-parens": ["error"],
// TODO: configure this... // TODO: configure this...
@ -145,18 +115,15 @@ module.exports = {
"no-catch-shadow": ["error"], "no-catch-shadow": ["error"],
"no-class-assign": ["error"], "no-class-assign": ["error"],
"no-compare-neg-zero": ["error"], "no-compare-neg-zero": ["error"],
"no-cond-assign": [ "no-cond-assign": ["error", "except-parens"],
"error",
"except-parens"
],
"no-confusing-arrow": ["error"], "no-confusing-arrow": ["error"],
"no-console": ["error"], "no-console": ["error"],
"no-const-assign": ["error"], "no-const-assign": ["error"],
"no-constant-condition": [ "no-constant-condition": [
"error", "error",
{ {
"checkLoops": false checkLoops: false,
} },
], ],
"no-continue": ["off"], "no-continue": ["off"],
"no-control-regex": ["error"], "no-control-regex": ["error"],
@ -170,15 +137,15 @@ module.exports = {
"no-duplicate-imports": [ "no-duplicate-imports": [
"error", "error",
{ {
"includeExports": true includeExports: true,
} },
], ],
"no-else-return": ["error"], "no-else-return": ["error"],
"no-empty": [ "no-empty": [
"error", "error",
{ {
"allowEmptyCatch": false allowEmptyCatch: false,
} },
], ],
"no-empty-character-class": ["error"], "no-empty-character-class": ["error"],
"no-empty-function": ["error"], "no-empty-function": ["error"],
@ -194,8 +161,8 @@ module.exports = {
"error", "error",
"all", "all",
{ {
"conditionalAssign": false conditionalAssign: false,
} },
], ],
"no-extra-semi": ["error"], "no-extra-semi": ["error"],
"no-fallthrough": ["error"], "no-fallthrough": ["error"],
@ -206,20 +173,17 @@ module.exports = {
"no-implicit-globals": ["error"], "no-implicit-globals": ["error"],
"no-implied-eval": ["error"], "no-implied-eval": ["error"],
"no-inline-comments": ["error"], "no-inline-comments": ["error"],
"no-inner-declarations": [ "no-inner-declarations": ["error", "both"],
"error",
"both"
],
"no-invalid-regexp": ["error"], "no-invalid-regexp": ["error"],
"no-invalid-this": ["error"], "no-invalid-this": ["error"],
"no-irregular-whitespace": [ "no-irregular-whitespace": [
"error", "error",
{ {
"skipComments": false, skipComments: false,
"skipRegExps": false, skipRegExps: false,
"skipStrings": false, skipStrings: false,
"skipTemplates": false skipTemplates: false,
} },
], ],
"no-iterator": ["error"], "no-iterator": ["error"],
"no-label-var": ["error"], "no-label-var": ["error"],
@ -230,13 +194,9 @@ module.exports = {
"no-magic-numbers": [ "no-magic-numbers": [
"error", "error",
{ {
"ignore": [ ignore: [-1, 0, 1],
-1, ignoreArrayIndexes: true,
0, },
1
],
"ignoreArrayIndexes": true
}
], ],
"no-mixed-operators": ["error"], "no-mixed-operators": ["error"],
"no-mixed-requires": ["error"], "no-mixed-requires": ["error"],
@ -247,8 +207,8 @@ module.exports = {
"no-multiple-empty-lines": [ "no-multiple-empty-lines": [
"error", "error",
{ {
"max": 1 max: 1,
} },
], ],
"no-native-reassign": ["error"], "no-native-reassign": ["error"],
"no-negated-condition": ["error"], "no-negated-condition": ["error"],
@ -268,8 +228,8 @@ module.exports = {
"no-plusplus": [ "no-plusplus": [
"error", "error",
{ {
"allowForLoopAfterthoughts": true allowForLoopAfterthoughts: true,
} },
], ],
"no-process-env": ["error"], "no-process-env": ["error"],
"no-process-exit": ["error"], "no-process-exit": ["error"],
@ -283,10 +243,10 @@ module.exports = {
"no-restricted-properties": [ "no-restricted-properties": [
"error", "error",
{ {
"message": "'log' is too general, use an appropriate level when logging.", message: "'log' is too general, use an appropriate level when logging.",
"object": "console", object: "console",
"property": "log" property: "log",
} },
], ],
"no-restricted-syntax": ["error"], "no-restricted-syntax": ["error"],
"no-return-assign": ["error"], "no-return-assign": ["error"],
@ -295,8 +255,8 @@ module.exports = {
"no-self-assign": [ "no-self-assign": [
"error", "error",
{ {
"props": false props: false,
} },
], ],
"no-self-compare": ["error"], "no-self-compare": ["error"],
"no-sequences": ["error"], "no-sequences": ["error"],
@ -333,10 +293,10 @@ module.exports = {
"no-useless-rename": [ "no-useless-rename": [
"error", "error",
{ {
"ignoreDestructuring": false, ignoreDestructuring: false,
"ignoreExport": false, ignoreExport: false,
"ignoreImport": false ignoreImport: false,
} },
], ],
"no-useless-return": ["error"], "no-useless-return": ["error"],
"no-var": ["error"], "no-var": ["error"],
@ -344,10 +304,7 @@ module.exports = {
"no-warning-comments": ["error"], "no-warning-comments": ["error"],
"no-whitespace-before-property": ["error"], "no-whitespace-before-property": ["error"],
"no-with": ["error"], "no-with": ["error"],
"nonblock-statement-body-position": [ "nonblock-statement-body-position": ["error", "below"],
"error",
"below"
],
"object-curly-newline": ["error"], "object-curly-newline": ["error"],
"object-curly-spacing": ["error"], "object-curly-spacing": ["error"],
"object-property-newline": ["error"], "object-property-newline": ["error"],
@ -355,10 +312,7 @@ module.exports = {
"one-var": ["off"], "one-var": ["off"],
"one-var-declaration-per-line": ["error"], "one-var-declaration-per-line": ["error"],
"operator-assignment": ["error"], "operator-assignment": ["error"],
"operator-linebreak": [ "operator-linebreak": ["error", "none"],
"error",
"none"
],
"padded-blocks": ["off"], "padded-blocks": ["off"],
"padding-line-between-statements": ["error"], "padding-line-between-statements": ["error"],
"prefer-arrow-callback": ["error"], "prefer-arrow-callback": ["error"],
@ -371,24 +325,15 @@ module.exports = {
"prefer-spread": ["error"], "prefer-spread": ["error"],
"prefer-template": ["error"], "prefer-template": ["error"],
"quote-props": ["error"], "quote-props": ["error"],
"quotes": ["error"], quotes: ["error"],
"radix": [ radix: ["error", "as-needed"],
"error",
"as-needed"
],
"require-await": ["error"], "require-await": ["error"],
"require-jsdoc": ["off"], "require-jsdoc": ["off"],
"require-yield": ["error"], "require-yield": ["error"],
"rest-spread-spacing": [ "rest-spread-spacing": ["error", "never"],
"error", semi: ["error"],
"never"
],
"semi": ["error"],
"semi-spacing": ["error"], "semi-spacing": ["error"],
"semi-style": [ "semi-style": ["error", "last"],
"error",
"last"
],
"sort-imports": ["error"], "sort-imports": ["error"],
"sort-keys": ["error"], "sort-keys": ["error"],
"sort-vars": ["error"], "sort-vars": ["error"],
@ -398,37 +343,25 @@ module.exports = {
"space-infix-ops": ["error"], "space-infix-ops": ["error"],
"space-unary-ops": ["error"], "space-unary-ops": ["error"],
"spaced-comment": ["error"], "spaced-comment": ["error"],
"strict": ["error"], strict: ["error"],
"switch-colon-spacing": [ "switch-colon-spacing": [
"error", "error",
{ {
"after": true, after: true,
"before": false before: false,
} },
], ],
"symbol-description": ["error"], "symbol-description": ["error"],
"template-curly-spacing": ["error"], "template-curly-spacing": ["error"],
"template-tag-spacing": ["error"], "template-tag-spacing": ["error"],
"unicode-bom": [ "unicode-bom": ["error", "never"],
"error",
"never"
],
"use-isnan": ["error"], "use-isnan": ["error"],
"valid-jsdoc": ["error"], "valid-jsdoc": ["error"],
"valid-typeof": ["error"], "valid-typeof": ["error"],
"vars-on-top": ["error"], "vars-on-top": ["error"],
"wrap-iife": [ "wrap-iife": ["error", "any"],
"error",
"any"
],
"wrap-regex": ["error"], "wrap-regex": ["error"],
"yield-star-spacing": [ "yield-star-spacing": ["error", "before"],
"error", yoda: ["error", "never"],
"before" },
],
"yoda": [
"error",
"never"
]
}
}; };

@ -8,7 +8,8 @@ const path = require("path");
const exec = require("child_process").exec; const exec = require("child_process").exec;
const semver = require("./semver"); const semver = require("./semver");
const getPackageJson = () => new Promise((resolve, reject) => { const getPackageJson = () =>
new Promise((resolve, reject) => {
try { try {
/* eslint-disable-next-line global-require */ /* eslint-disable-next-line global-require */
resolve(require(path.resolve(process.cwd(), "package.json"))); resolve(require(path.resolve(process.cwd(), "package.json")));
@ -17,7 +18,8 @@ const getPackageJson = () => new Promise((resolve, reject) => {
} }
}); });
const getEngines = (data) => new Promise((resolve, reject) => { const getEngines = (data) =>
new Promise((resolve, reject) => {
let versions = null; let versions = null;
if (data.engines) { if (data.engines) {
@ -31,7 +33,8 @@ const getEngines = (data) => new Promise((resolve, reject) => {
} }
}); });
const checkNpmVersion = (engines) => new Promise((resolve, reject) => { const checkNpmVersion = (engines) =>
new Promise((resolve, reject) => {
exec("npm -v", (error, stdout, stderr) => { exec("npm -v", (error, stdout, stderr) => {
if (error) { if (error) {
reject(`Unable to find NPM version\n${stderr}`); reject(`Unable to find NPM version\n${stderr}`);
@ -43,18 +46,23 @@ const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
if (semver.satisfies(npmVersion, engineVersion)) { if (semver.satisfies(npmVersion, engineVersion)) {
resolve(); resolve();
} else { } else {
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`); 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); const nodeVersion = process.version.substring(1);
if (semver.satisfies(nodeVersion, engines.node)) { if (semver.satisfies(nodeVersion, engines.node)) {
resolve(engines); resolve(engines);
} else { } 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}".`,
);
} }
}); });
@ -69,5 +77,5 @@ getPackageJson()
/* eslint-disable no-console, no-process-exit */ /* eslint-disable no-console, no-process-exit */
console.error(error); console.error(error);
process.exit(1); process.exit(1);
} },
); );

@ -81,30 +81,20 @@ src[NONNUMERICIDENTIFIER] = "\\d*[a-zA-Z-][a-zA-Z0-9-]*";
// ## Main Version // ## Main Version
// Three dot-separated numeric identifiers. // Three dot-separated numeric identifiers.
src[ src[MAINVERSION] = `(${src[NUMERICIDENTIFIER]})\\.(${src[NUMERICIDENTIFIER]})\\.(${src[NUMERICIDENTIFIER]})`;
MAINVERSION
] = `(${src[NUMERICIDENTIFIER]})\\.(${src[NUMERICIDENTIFIER]})\\.(${src[NUMERICIDENTIFIER]})`;
src[ src[
MAINVERSIONLOOSE MAINVERSIONLOOSE
] = `(${src[NUMERICIDENTIFIERLOOSE]})\\.(${src[NUMERICIDENTIFIERLOOSE]})\\.(${src[NUMERICIDENTIFIERLOOSE]})`; ] = `(${src[NUMERICIDENTIFIERLOOSE]})\\.(${src[NUMERICIDENTIFIERLOOSE]})\\.(${src[NUMERICIDENTIFIERLOOSE]})`;
// ## Pre-release Version Identifier // ## Pre-release Version Identifier
// A numeric identifier, or a non-numeric identifier. // A numeric identifier, or a non-numeric identifier.
src[ src[PRERELEASEIDENTIFIER] = `(?:${src[NUMERICIDENTIFIER]}|${src[NONNUMERICIDENTIFIER]})`;
PRERELEASEIDENTIFIER src[PRERELEASEIDENTIFIERLOOSE] = `(?:${src[NUMERICIDENTIFIERLOOSE]}|${src[NONNUMERICIDENTIFIER]})`;
] = `(?:${src[NUMERICIDENTIFIER]}|${src[NONNUMERICIDENTIFIER]})`;
src[
PRERELEASEIDENTIFIERLOOSE
] = `(?:${src[NUMERICIDENTIFIERLOOSE]}|${src[NONNUMERICIDENTIFIER]})`;
// ## Pre-release Version // ## Pre-release Version
// Hyphen, followed by one or more dot-separated pre-release version identifiers. // Hyphen, followed by one or more dot-separated pre-release version identifiers.
src[ src[PRERELEASE] = `(?:-(${src[PRERELEASEIDENTIFIER]}(?:\\.${src[PRERELEASEIDENTIFIER]})*))`;
PRERELEASE src[PRERELEASELOOSE] = `(?:-?(${src[PRERELEASEIDENTIFIERLOOSE]}(?:\\.${src[PRERELEASEIDENTIFIERLOOSE]})*))`;
] = `(?:-(${src[PRERELEASEIDENTIFIER]}(?:\\.${src[PRERELEASEIDENTIFIER]})*))`;
src[
PRERELEASELOOSE
] = `(?:-?(${src[PRERELEASEIDENTIFIERLOOSE]}(?:\\.${src[PRERELEASEIDENTIFIERLOOSE]})*))`;
// ## Build Metadata Identifier // ## Build Metadata Identifier
// Any combination of digits, letters, or hyphens. // Any combination of digits, letters, or hyphens.
@ -180,9 +170,7 @@ src[COMPARATORLOOSE] = `^${src[GTLT]}\\s*(${LOOSEPLAIN})$|^$`;
src[COMPARATOR] = `^${src[GTLT]}\\s*(${FULLPLAIN})$|^$`; src[COMPARATOR] = `^${src[GTLT]}\\s*(${FULLPLAIN})$|^$`;
// An expression to strip any whitespace between the gtlt and the thing it modifies, so that `> 1.2.3` ==> `>1.2.3` // An expression to strip any whitespace between the gtlt and the thing it modifies, so that `> 1.2.3` ==> `>1.2.3`
src[ src[COMPARATORTRIM] = `(\\s*)${src[GTLT]}\\s*(${LOOSEPLAIN}|${src[XRANGEPLAIN]})`;
COMPARATORTRIM
] = `(\\s*)${src[GTLT]}\\s*(${LOOSEPLAIN}|${src[XRANGEPLAIN]})`;
// This one has to use the /g flag // This one has to use the /g flag
re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], "g"); re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], "g");
@ -190,13 +178,9 @@ const comparatorTrimReplace = "$1$2$3";
// Something like `1.2.3 - 1.2.4` // Something like `1.2.3 - 1.2.4`
// Note that these all use the loose form, because they'll be checked against either the strict or loose comparator form later. // Note that these all use the loose form, because they'll be checked against either the strict or loose comparator form later.
src[ src[HYPHENRANGE] = `^\\s*(${src[XRANGEPLAIN]})\\s+-\\s+(${src[XRANGEPLAIN]})\\s*$`;
HYPHENRANGE
] = `^\\s*(${src[XRANGEPLAIN]})\\s+-\\s+(${src[XRANGEPLAIN]})\\s*$`;
src[ src[HYPHENRANGELOOSE] = `^\\s*(${src[XRANGEPLAINLOOSE]})\\s+-\\s+(${src[XRANGEPLAINLOOSE]})\\s*$`;
HYPHENRANGELOOSE
] = `^\\s*(${src[XRANGEPLAINLOOSE]})\\s+-\\s+(${src[XRANGEPLAINLOOSE]})\\s*$`;
// Star ranges basically just allow anything at all. // Star ranges basically just allow anything at all.
src[STAR] = "(<|>)?=?\\s*\\*"; src[STAR] = "(<|>)?=?\\s*\\*";
@ -289,9 +273,7 @@ function replaceTilde(comp, loose) {
if (prerelease.charAt(0) !== "-") { if (prerelease.charAt(0) !== "-") {
prerelease = `-${prerelease}`; prerelease = `-${prerelease}`;
} }
ret = `>=${major}.${minor}.${patch}${prerelease} <${major}.${ ret = `>=${major}.${minor}.${patch}${prerelease} <${major}.${Number(minor) + 1}.0`;
Number(minor) + 1
}.0`;
} else { } else {
// ~1.2.3 == >=1.2.3 <1.3.0 // ~1.2.3 == >=1.2.3 <1.3.0
ret = `>=${major}.${minor}.${patch} <${major}.${Number(minor) + 1}.0`; ret = `>=${major}.${minor}.${patch} <${major}.${Number(minor) + 1}.0`;
@ -337,24 +319,16 @@ function replaceCaret(comp, loose) {
} }
if (major === "0") { if (major === "0") {
if (minor === "0") { if (minor === "0") {
ret = `>=${major}.${minor}.${patch}${prerelease} <${major}.${minor}.${ ret = `>=${major}.${minor}.${patch}${prerelease} <${major}.${minor}.${Number(patch) + 1}`;
Number(patch) + 1
}`;
} else { } else {
ret = `>=${major}.${minor}.${patch}${prerelease} <${major}.${ ret = `>=${major}.${minor}.${patch}${prerelease} <${major}.${Number(minor) + 1}.0`;
Number(minor) + 1
}.0`;
} }
} else { } else {
ret = `>=${major}.${minor}.${patch}${prerelease} <${ ret = `>=${major}.${minor}.${patch}${prerelease} <${Number(major) + 1}.0.0`;
Number(major) + 1
}.0.0`;
} }
} else if (major === "0") { } else if (major === "0") {
if (minor === "0") { if (minor === "0") {
ret = `>=${major}.${minor}.${patch} <${major}.${minor}.${ ret = `>=${major}.${minor}.${patch} <${major}.${minor}.${Number(patch) + 1}`;
Number(patch) + 1
}`;
} else { } else {
ret = `>=${major}.${minor}.${patch} <${major}.${Number(minor) + 1}.0`; ret = `>=${major}.${minor}.${patch} <${major}.${Number(minor) + 1}.0`;
} }
@ -470,7 +444,6 @@ function parseComparator(comp, loose) {
} }
class SemVer { class SemVer {
/** /**
* A semantic version. * A semantic version.
* @param {string} version The version. * @param {string} version The version.
@ -514,7 +487,7 @@ class SemVer {
// Numberify any prerelease numeric ids // Numberify any prerelease numeric ids
if (matches[4]) { if (matches[4]) {
this.prerelease = matches[4].split(".").map((id) => { this.prerelease = matches[4].split(".").map((id) => {
if ((/^[0-9]+$/).test(id)) { if (/^[0-9]+$/.test(id)) {
const num = Number(id); const num = Number(id);
if (num >= 0 && num < MAX_SAFE_INTEGER) { if (num >= 0 && num < MAX_SAFE_INTEGER) {
return num; return num;
@ -558,7 +531,9 @@ class SemVer {
} }
return ( return (
compareIdentifiers(this.major, other.major) || compareIdentifiers(this.minor, other.minor) || compareIdentifiers(this.patch, other.patch) compareIdentifiers(this.major, other.major) ||
compareIdentifiers(this.minor, other.minor) ||
compareIdentifiers(this.patch, other.patch)
); );
} }
@ -598,7 +573,8 @@ class SemVer {
} }
} }
const compare = (leftVersion, rightVersion, loose) => new SemVer(leftVersion, loose).compare(new SemVer(rightVersion, loose)); const compare = (leftVersion, rightVersion, loose) =>
new SemVer(leftVersion, loose).compare(new SemVer(rightVersion, loose));
const gt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) > 0; const gt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) > 0;
const lt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) < 0; const lt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) < 0;
const eq = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) === 0; const eq = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) === 0;
@ -670,9 +646,7 @@ function testSet(set, version) {
if (set[idx].semver !== ANY) { if (set[idx].semver !== ANY) {
if (set[idx].semver.prerelease.length > 0) { if (set[idx].semver.prerelease.length > 0) {
const allowed = set[idx].semver; const allowed = set[idx].semver;
if ( if (allowed.major === version.major && allowed.minor === version.minor && allowed.patch === version.patch) {
allowed.major === version.major && allowed.minor === version.minor && allowed.patch === version.patch
) {
return true; return true;
} }
} }

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

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

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

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

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

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

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

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

@ -1,11 +1,7 @@
import { IBladeburner } from "./IBladeburner"; import { IBladeburner } from "./IBladeburner";
import { BladeburnerConstants } from "./data/Constants"; import { BladeburnerConstants } from "./data/Constants";
import { Action, IActionParams } from "./Action"; import { Action, IActionParams } from "./Action";
import { import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
export interface IOperationParams extends IActionParams { export interface IOperationParams extends IActionParams {
reqdRank?: number; reqdRank?: number;
@ -37,9 +33,7 @@ export class Operation extends Action {
return inst.skillMultipliers.successChanceOperation; return inst.skillMultipliers.successChanceOperation;
} }
getChaosDifficultyBonus( getChaosDifficultyBonus(inst: IBladeburner /*, params: ISuccessChanceParams*/): number {
inst: IBladeburner /*, params: ISuccessChanceParams*/,
): number {
const city = inst.getCurrentCity(); const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) { if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (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" }) { constructor(params: ISkillParams = { name: "foo", desc: "foo" }) {
if (!params.name) { if (!params.name) {
throw new Error( throw new Error("Failed to initialize Bladeburner Skill. No name was specified in ctor");
"Failed to initialize Bladeburner Skill. No name was specified in ctor",
);
} }
if (!params.desc) { if (!params.desc) {
throw new Error( throw new Error("Failed to initialize Bladeburner Skills. No desc was specified in ctor");
"Failed to initialize Bladeburner Skills. No desc was specified in ctor",
);
} }
this.name = params.name; this.name = params.name;
this.desc = params.desc; this.desc = params.desc;
@ -138,10 +134,7 @@ export class Skill {
} }
calculateCost(currentLevel: number): number { calculateCost(currentLevel: number): number {
return Math.floor( return Math.floor((this.baseCost + currentLevel * this.costInc) * BitNodeMultipliers.BladeburnerSkillCost);
(this.baseCost + currentLevel * this.costInc) *
BitNodeMultipliers.BladeburnerSkillCost,
);
} }
getMultiplier(name: string): number { getMultiplier(name: string): number {

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

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

@ -1,13 +1,7 @@
import * as React from "react"; import * as React from "react";
export const stealthIcon = ( export const stealthIcon = (
<svg <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 166 132" style={{ fill: "#adff2f" }}>
xmlns="http://www.w3.org/2000/svg"
width="16px"
height="16px"
viewBox="0 0 166 132"
style={{ fill: "#adff2f" }}
>
<g> <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="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" /> <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 ( return (
<a <a
onClick={() => setPage(props.name)} onClick={() => setPage(props.name)}
className={ className={page !== props.name ? "bladeburner-nav-button noselect" : "bladeburner-nav-button-inactive noselect"}
page !== props.name
? "bladeburner-nav-button noselect"
: "bladeburner-nav-button-inactive noselect"
}
> >
{props.name} {props.name}
</a> </a>
@ -44,29 +40,14 @@ export function AllPages(props: IProps): React.ReactElement {
<Header name={"BlackOps"} /> <Header name={"BlackOps"} />
<Header name={"Skills"} /> <Header name={"Skills"} />
<div style={{ display: "block", margin: "4px", padding: "4px" }}> <div style={{ display: "block", margin: "4px", padding: "4px" }}>
{page === "General" && ( {page === "General" && <GeneralActionPage bladeburner={props.bladeburner} player={props.player} />}
<GeneralActionPage {page === "Contracts" && <ContractPage bladeburner={props.bladeburner} player={props.player} />}
bladeburner={props.bladeburner} {page === "Operations" && <OperationPage bladeburner={props.bladeburner} player={props.player} />}
player={props.player} {page === "BlackOps" && <BlackOpPage 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} />} {page === "Skills" && <SkillPage bladeburner={props.bladeburner} />}
</div> </div>
<span className="text"> <span className="text">
{stealthIcon} = This action requires stealth, {killIcon} = This action {stealthIcon} = This action requires stealth, {killIcon} = This action involves retirement
involves retirement
</span> </span>
</> </>
); );

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -19,94 +19,46 @@ export function SkillPage(props: IProps): React.ReactElement {
return ( return (
<> <>
<p> <p>
<strong> <strong>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</strong>
Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}
</strong>
</p> </p>
<p> <p>
You will gain one skill point every{" "} You will gain one skill point every {BladeburnerConstants.RanksPerSkillPoint} ranks.
{BladeburnerConstants.RanksPerSkillPoint} ranks.
<br /> <br />
<br /> <br />
Note that when upgrading a skill, the benefit for that skill is Note that when upgrading a skill, the benefit for that skill is additive. However, the effects of different
additive. However, the effects of different skills with each other is skills with each other is multiplicative.
multiplicative.
<br /> <br />
</p> </p>
<br /> <br />
{valid(mults["successChanceAll"]) && ( {valid(mults["successChanceAll"]) && <p>Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}</p>}
<p>
Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}
</p>
)}
{valid(mults["successChanceStealth"]) && ( {valid(mults["successChanceStealth"]) && (
<p> <p>Stealth Success Chance: x{formatNumber(mults["successChanceStealth"], 3)}</p>
Stealth Success Chance: x
{formatNumber(mults["successChanceStealth"], 3)}
</p>
)} )}
{valid(mults["successChanceKill"]) && ( {valid(mults["successChanceKill"]) && (
<p> <p>Retirement Success Chance: x{formatNumber(mults["successChanceKill"], 3)}</p>
Retirement Success Chance: x
{formatNumber(mults["successChanceKill"], 3)}
</p>
)} )}
{valid(mults["successChanceContract"]) && ( {valid(mults["successChanceContract"]) && (
<p> <p>Contract Success Chance: x{formatNumber(mults["successChanceContract"], 3)}</p>
Contract Success Chance: x
{formatNumber(mults["successChanceContract"], 3)}
</p>
)} )}
{valid(mults["successChanceOperation"]) && ( {valid(mults["successChanceOperation"]) && (
<p> <p>Operation Success Chance: x{formatNumber(mults["successChanceOperation"], 3)}</p>
Operation Success Chance: x
{formatNumber(mults["successChanceOperation"], 3)}
</p>
)} )}
{valid(mults["successChanceEstimate"]) && ( {valid(mults["successChanceEstimate"]) && (
<p> <p>Synthoid Data Estimate: x{formatNumber(mults["successChanceEstimate"], 3)}</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>
)} )}
{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 /> <br />
<SkillList <SkillList bladeburner={props.bladeburner} onUpgrade={() => setRerender((old) => !old)} />
bladeburner={props.bladeburner}
onUpgrade={() => setRerender((old) => !old)}
/>
</> </>
); );
} }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -20,9 +20,8 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
const allIndustries = Object.keys(Industries).sort(); const allIndustries = Object.keys(Industries).sort();
const possibleIndustries = allIndustries const possibleIndustries = allIndustries
.filter( .filter(
(industryType: string) => props.corp.divisions.find( (industryType: string) =>
(division: IIndustry) => division.type === industryType, props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
) === undefined,
) )
.sort(); .sort();
if (possibleIndustries.length === 0) return <></>; if (possibleIndustries.length === 0) return <></>;
@ -36,13 +35,7 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
}); });
} }
return ( return <HeaderTab current={false} onClick={openNewIndustryPopup} text={"Expand into new Industry"} />;
<HeaderTab
current={false}
onClick={openNewIndustryPopup}
text={"Expand into new Industry"}
/>
);
} }
interface IProps { interface IProps {
@ -72,11 +65,7 @@ export function HeaderTabs(props: IProps): React.ReactElement {
))} ))}
<ExpandButton corp={props.corp} setDivisionName={setDivisionName} /> <ExpandButton corp={props.corp} setDivisionName={setDivisionName} />
</div> </div>
<MainPanel <MainPanel corp={props.corp} divisionName={divisionName} player={props.player} />
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 // Returns a boolean indicating whether the given material is relevant for the
// current industry. // current industry.
export function isRelevantMaterial( export function isRelevantMaterial(matName: string, division: IIndustry): boolean {
matName: string,
division: IIndustry,
): boolean {
// Materials that affect Production multiplier // Materials that affect Production multiplier
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate"]; const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate"];

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

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

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

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

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