Merge branch 'dev' into streamline-create-programs

This commit is contained in:
Olivier Gagnon 2018-06-20 18:50:08 -04:00 committed by GitHub
commit 0ea6312d49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 15394 additions and 166564 deletions

2
.gitignore vendored

@ -2,3 +2,5 @@ Changelog.txt
Netburner.txt Netburner.txt
/node_modules /node_modules
/dist/*.map /dist/*.map
/tests/*.map
/tests/*.bundle.*

@ -22,12 +22,6 @@
background-color: #777; background-color: #777;
} }
/* Select industry type when creating a new division */
.cmpy-mgmt-industry-select {
color:white;
background-color:black;
}
/* Switch between Cities */ /* Switch between Cities */
.cmpy-mgmt-city-tab { .cmpy-mgmt-city-tab {
display:inline-block; display:inline-block;

@ -288,30 +288,44 @@
} }
#hacknet-nodes-text, #hacknet-nodes-text,
#hacknet-nodes-money,
#hacknet-nodes-container li { #hacknet-nodes-container li {
width: 70%;
margin: 10px; margin: 10px;
padding: 10px; padding: 10px;
} }
#hacknet-nodes-purchase-button { #hacknet-nodes-container li {
display: inline-block; float: left;
overflow: hidden;
white-space: nowrap;
}
#hacknet-nodes-list {
list-style: none;
width: 82vw;
}
#hacknet-nodes-money {
margin: 10px;
float: left;
} }
#hacknet-nodes-money-multipliers-div { #hacknet-nodes-money-multipliers-div {
display: inline-block; display: inline-block;
width: 70%; width: 70vw;
} }
#hacknet-nodes-multipliers { #hacknet-nodes-multipliers {
float: right; float: right;
} }
#hacknet-nodes-purchase-button {
display: inline-block;
}
.hacknet-node { .hacknet-node {
margin: 6px; margin: 6px;
padding: 6px; padding: 6px;
width: 85%; width: 34vw;
border: 2px solid var(--my-highlight-color); border: 2px solid var(--my-highlight-color);
-webkit-box-shadow: -webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.1), inset 0 0 8px rgba(0,0,0,0.1),
@ -324,12 +338,28 @@
0 0 16px rgba(0,0,0,0.1); 0 0 16px rgba(0,0,0,0.1);
} }
.hacknet-node-button-div a { .hacknet-node-container {
display: block; display: inline-table;
} }
.hacknet-node-button-div:not(:last-child) { .hacknet-node-container .row {
border-bottom: none; display: table-row;
height: 30px;
}
.hacknet-node-container .row p {
display: table-cell;
}
.hacknet-node-container .upgradable-info {
display: inline-block;
margin: 0 4px; /* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: 48px; /* Four times font-size */
}
.menu-page-text {
width: 70vw;
} }
/* World */ /* World */
@ -456,6 +486,21 @@
width: 50%; width: 50%;
} }
/* Dev menu */
#dev-menu-container {
position: fixed;
padding-top: 10px;
}
#dev-menu-text {
width: 70%;
margin: 10px;
}
#dev-menu-container a {
width: 50%;
}
/* Location */ /* Location */
#location-container { #location-container {
position: fixed; position: fixed;

@ -15,7 +15,10 @@ body {
background-color: var(--my-background-color); background-color: var(--my-background-color);
} }
p, pre, h2 { p,
pre,
h2,
.text {
color: var(--my-font-color); color: var(--my-font-color);
} }
@ -135,6 +138,11 @@ a:link, a:visited {
padding: 5px; padding: 5px;
margin: 5px; margin: 5px;
border: 1px solid #333333; border: 1px solid #333333;
-moz-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
} }
.a-link-button:hover { .a-link-button:hover {
@ -189,6 +197,16 @@ a:link, a:visited {
pointer-events: none; pointer-events: none;
} }
.dropdown {
color:white;
background-color:black;
}
.text-input {
color:white;
background-color:black;
}
/* Notification icon (for create program right now only) */ /* Notification icon (for create program right now only) */
#create-program-tab { #create-program-tab {
position:relative; position:relative;

BIN
dist/android-chrome-192x192.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
dist/android-chrome-512x512.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
dist/apple-touch-icon.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

9
dist/browserconfig.xml vendored Normal file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="dist/mstile-70x70.png"/>
<TileColor>#000000</TileColor>
</tile>
</msapplication>
</browserconfig>

20958
dist/engine.bundle.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/favicon-16x16.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

BIN
dist/favicon-32x32.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

BIN
dist/mstile-70x70.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

1
dist/safari-pinned-tab.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

19
dist/site.webmanifest vendored Normal file

@ -0,0 +1,19 @@
{
"name": "Bitburner",
"short_name": "Bitburner",
"icons": [
{
"src": "android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

143601
dist/tests.bundle.js vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -3,8 +3,34 @@
Changelog Changelog
========= =========
v0.37.1 v0.38.0 - 6/12/2018
------- -------------------
* New BitNode: BN-12 The Recursion - Implemented by Github user hydroflame
* Bladeburner Changes:
* Bladeburner progress is no longer reset when installing Augmentations
* The number of successess needed to increase a Contract/Operation's max level now scales with the current max level (gradually gets harder)
* All Bladeburner Augmentations are now slightly more expensive and require more reputation
* Black Operations now give higher rank rewards
* Doubled the base amount of money gained from Contracts
* Increased the amount of experience gained from Contracts/Actions
* Added a new Augmentation: The Blade's Simulacrum
* Bladeburner faction reputation gain is now properly affected by favor
* Hacking is now slightly less profitable in BitNode-3
* Updated Hacknet Nodes UI - Implemented by Github user kopelli
* Bug Fix: Fixed an exploit that allowed calling any Netscript function without incurring any RAM Cost in NetscriptJS
v0.37.2 - 6/2/2018
------------------
* After joining the Bladeburners division, there is now a button to go to the Bladeburner content
in the 'City' page
* You now start with $250m in BitNode-8 (increased from $100m)
* Bug Fix: You can now no longer directly edit Hacknet Node values through NetscriptJS (hopefully)
* Bug Fix: Bladeburners is no longer accessible in BN-8
* Bug Fix: getBitNodeMultipliers() Netscript function now returns a copy rather than the original object
v0.37.1 - 5/22/2018
-------------------
* You now earn money from successfully completing Bladeburner contracts. The amount you earn is based * You now earn money from successfully completing Bladeburner contracts. The amount you earn is based
on the difficulty of the contract. on the difficulty of the contract.
* Completing Field Analysis in Bladeburner now grants 0.1 rank * Completing Field Analysis in Bladeburner now grants 0.1 rank

@ -387,6 +387,34 @@ ls
Returns an array with the filenames of all files on the specified server (as strings). The returned array Returns an array with the filenames of all files on the specified server (as strings). The returned array
is sorted in alphabetic order is sorted in alphabetic order
ps
^^
.. js:function:: ps(hostname/ip=current ip)
:param string ip: Hostname or IP address of the target server.
If not specified, it will be the current server's IP by default
Returns an array with general information about all scripts running on the specified
target server. The information for each server is given in an object with
the following structure::
{
filename: Script name,
threads: Number of threads script is running with,
args: Script's arguments
}
Example usage (using :doc:`netscriptjs`)::
export async function main(ns) {
const ps = ns.ps("home");
for (let i = 0; i < ps.length; ++i) {
ns.tprint(ps[i].filename + ' ' + ps[i].threads);
ns.tprint(ps[i].args);
}
}
hasRootAccess hasRootAccess
^^^^^^^^^^^^^ ^^^^^^^^^^^^^

@ -1,3 +1,5 @@
.. _netscriptjs:
NetscriptJS (Netscript 2.0) NetscriptJS (Netscript 2.0)
=========================== ===========================
Netscript 2.0, or Netscript JS, is the new and improved version of Netscript that Netscript 2.0, or Netscript JS, is the new and improved version of Netscript that

@ -50,8 +50,43 @@
<div class="section" id="changelog"> <div class="section" id="changelog">
<span id="id1"></span><h1>Changelog<a class="headerlink" href="#changelog" title="Permalink to this headline"></a></h1> <span id="id1"></span><h1>Changelog<a class="headerlink" href="#changelog" title="Permalink to this headline"></a></h1>
<div class="section" id="v0-37-1"> <div class="section" id="v0-38-0-6-12-2018">
<h2>v0.37.1<a class="headerlink" href="#v0-37-1" title="Permalink to this headline"></a></h2> <h2>v0.38.0 - 6/12/2018<a class="headerlink" href="#v0-38-0-6-12-2018" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>New BitNode: BN-12 The Recursion - Implemented by Github user hydroflame</li>
<li><dl class="first docutils">
<dt>Bladeburner Changes:</dt>
<dd><ul class="first last">
<li>Bladeburner progress is no longer reset when installing Augmentations</li>
<li>The number of successess needed to increase a Contract/Operation's max level now scales with the current max level (gradually gets harder)</li>
<li>All Bladeburner Augmentations are now slightly more expensive and require more reputation</li>
<li>Black Operations now give higher rank rewards</li>
<li>Doubled the base amount of money gained from Contracts</li>
<li>Increased the amount of experience gained from Contracts/Actions</li>
<li>Added a new Augmentation: The Blade's Simulacrum</li>
<li>Bladeburner faction reputation gain is now properly affected by favor</li>
</ul>
</dd>
</dl>
</li>
<li>Hacking is now slightly less profitable in BitNode-3</li>
<li>Updated Hacknet Nodes UI - Implemented by Github user kopelli</li>
<li>Bug Fix: Fixed an exploit that allowed calling any Netscript function without incurring any RAM Cost in NetscriptJS</li>
</ul>
</div>
<div class="section" id="v0-37-2-6-2-2018">
<h2>v0.37.2 - 6/2/2018<a class="headerlink" href="#v0-37-2-6-2-2018" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>After joining the Bladeburners division, there is now a button to go to the Bladeburner content
in the 'City' page</li>
<li>You now start with $250m in BitNode-8 (increased from $100m)</li>
<li>Bug Fix: You can now no longer directly edit Hacknet Node values through NetscriptJS (hopefully)</li>
<li>Bug Fix: Bladeburners is no longer accessible in BN-8</li>
<li>Bug Fix: getBitNodeMultipliers() Netscript function now returns a copy rather than the original object</li>
</ul>
</div>
<div class="section" id="v0-37-1-5-22-2018">
<h2>v0.37.1 - 5/22/2018<a class="headerlink" href="#v0-37-1-5-22-2018" title="Permalink to this headline"></a></h2>
<ul class="simple"> <ul class="simple">
<li>You now earn money from successfully completing Bladeburner contracts. The amount you earn is based <li>You now earn money from successfully completing Bladeburner contracts. The amount you earn is based
on the difficulty of the contract.</li> on the difficulty of the contract.</li>
@ -971,7 +1006,9 @@ on the difficulty of the contract.</li>
<li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li> <li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li> <li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#"> Changelog</a><ul> <li class="toctree-l1 current"><a class="current reference internal" href="#"> Changelog</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#v0-37-1">v0.37.1</a></li> <li class="toctree-l2"><a class="reference internal" href="#v0-38-0-6-12-2018">v0.38.0 - 6/12/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="#v0-37-2-6-2-2018">v0.37.2 - 6/2/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="#v0-37-1-5-22-2018">v0.37.1 - 5/22/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="#v0-37-0-5-20-2018">v0.37.0 - 5/20/2018</a></li> <li class="toctree-l2"><a class="reference internal" href="#v0-37-0-5-20-2018">v0.37.0 - 5/20/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="#v0-36-1-5-11-2018">v0.36.1 - 5/11/2018</a></li> <li class="toctree-l2"><a class="reference internal" href="#v0-36-1-5-11-2018">v0.36.1 - 5/11/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="#v0-36-0-5-2-2018">v0.36.0 - 5/2/2018</a></li> <li class="toctree-l2"><a class="reference internal" href="#v0-36-0-5-2-2018">v0.36.0 - 5/2/2018</a></li>

@ -326,6 +326,8 @@
<li><a href="netscriptfunctions.html#print">print() (built-in function)</a> <li><a href="netscriptfunctions.html#print">print() (built-in function)</a>
</li> </li>
<li><a href="netscriptfunctions.html#prompt">prompt() (built-in function)</a> <li><a href="netscriptfunctions.html#prompt">prompt() (built-in function)</a>
</li>
<li><a href="netscriptfunctions.html#ps">ps() (built-in function)</a>
</li> </li>
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>

@ -110,6 +110,7 @@ secrets that you've been searching for.</p>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#exit">exit</a></li> <li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#exit">exit</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#scp">scp</a></li> <li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#scp">scp</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#ls">ls</a></li> <li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#ls">ls</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#ps">ps</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#hasrootaccess">hasRootAccess</a></li> <li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#hasrootaccess">hasRootAccess</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#gethostname">getHostname</a></li> <li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#gethostname">getHostname</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#gethackinglevel">getHackingLevel</a></li> <li class="toctree-l3"><a class="reference internal" href="netscriptfunctions.html#gethackinglevel">getHackingLevel</a></li>
@ -268,7 +269,9 @@ secrets that you've been searching for.</p>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html"> Changelog</a><ul> <li class="toctree-l1"><a class="reference internal" href="changelog.html"> Changelog</a><ul>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-37-1">v0.37.1</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-38-0-6-12-2018">v0.38.0 - 6/12/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-37-2-6-2-2018">v0.37.2 - 6/2/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-37-1-5-22-2018">v0.37.1 - 5/22/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-37-0-5-20-2018">v0.37.0 - 5/20/2018</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-37-0-5-20-2018">v0.37.0 - 5/20/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-36-1-5-11-2018">v0.36.1 - 5/11/2018</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-36-1-5-11-2018">v0.36.1 - 5/11/2018</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-36-0-5-2-2018">v0.36.0 - 5/2/2018</a></li> <li class="toctree-l2"><a class="reference internal" href="changelog.html#v0-36-0-5-2-2018">v0.36.0 - 5/2/2018</a></li>

@ -111,6 +111,7 @@ to reach out to the developer!</p>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#exit">exit</a></li> <li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#exit">exit</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#scp">scp</a></li> <li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#scp">scp</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#ls">ls</a></li> <li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#ls">ls</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#ps">ps</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#hasrootaccess">hasRootAccess</a></li> <li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#hasrootaccess">hasRootAccess</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#gethostname">getHostname</a></li> <li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#gethostname">getHostname</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#gethackinglevel">getHackingLevel</a></li> <li class="toctree-l2"><a class="reference internal" href="netscriptfunctions.html#gethackinglevel">getHackingLevel</a></li>
@ -249,6 +250,7 @@ to reach out to the developer!</p>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li> <li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li> <li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html"> Changelog</a></li>
</ul> </ul>
<div role="search"> <div role="search">

@ -671,6 +671,46 @@ then this function will return true if at least one of the files in the array is
is sorted in alphabetic order</p> is sorted in alphabetic order</p>
</dd></dl> </dd></dl>
</div>
<div class="section" id="ps">
<h2>ps<a class="headerlink" href="#ps" title="Permalink to this headline"></a></h2>
<dl class="function">
<dt>
<code class="descname">ps</code><span class="sig-paren">(</span><em>hostname/ip=current ip</em><span class="sig-paren">)</span></dt>
<dd><table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Arguments:</th><td class="field-body"><ul class="first last simple">
<li><strong>ip</strong> (<em>string</em>) -- Hostname or IP address of the target server.
If not specified, it will be the current server's IP by default</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Returns an array with general information about all scripts running on the specified
target server. The information for each server is given in an object with
the following structure:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="n">filename</span><span class="p">:</span> <span class="n">Script</span> <span class="n">name</span><span class="p">,</span>
<span class="n">threads</span><span class="p">:</span> <span class="n">Number</span> <span class="n">of</span> <span class="n">threads</span> <span class="n">script</span> <span class="ow">is</span> <span class="n">running</span> <span class="k">with</span><span class="p">,</span>
<span class="n">args</span><span class="p">:</span> <span class="n">Script</span><span class="s1">&#39;s arguments</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Example usage (using <a class="reference internal" href="netscriptjs.html"><span class="doc">NetscriptJS (Netscript 2.0)</span></a>):</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">export</span> <span class="k">async</span> <span class="n">function</span> <span class="n">main</span><span class="p">(</span><span class="n">ns</span><span class="p">)</span> <span class="p">{</span>
<span class="n">const</span> <span class="n">ps</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">ps</span><span class="p">(</span><span class="s2">&quot;home&quot;</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="n">let</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">ps</span><span class="o">.</span><span class="n">length</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ns</span><span class="o">.</span><span class="n">tprint</span><span class="p">(</span><span class="n">ps</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">filename</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="n">ps</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">threads</span><span class="p">);</span>
<span class="n">ns</span><span class="o">.</span><span class="n">tprint</span><span class="p">(</span><span class="n">ps</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">args</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</dd></dl>
</div> </div>
<div class="section" id="hasrootaccess"> <div class="section" id="hasrootaccess">
<h2>hasRootAccess<a class="headerlink" href="#hasrootaccess" title="Permalink to this headline"></a></h2> <h2>hasRootAccess<a class="headerlink" href="#hasrootaccess" title="Permalink to this headline"></a></h2>
@ -1648,6 +1688,7 @@ you create in functions such as <a class="reference external" href="https://deve
<li class="toctree-l3"><a class="reference internal" href="#exit">exit</a></li> <li class="toctree-l3"><a class="reference internal" href="#exit">exit</a></li>
<li class="toctree-l3"><a class="reference internal" href="#scp">scp</a></li> <li class="toctree-l3"><a class="reference internal" href="#scp">scp</a></li>
<li class="toctree-l3"><a class="reference internal" href="#ls">ls</a></li> <li class="toctree-l3"><a class="reference internal" href="#ls">ls</a></li>
<li class="toctree-l3"><a class="reference internal" href="#ps">ps</a></li>
<li class="toctree-l3"><a class="reference internal" href="#hasrootaccess">hasRootAccess</a></li> <li class="toctree-l3"><a class="reference internal" href="#hasrootaccess">hasRootAccess</a></li>
<li class="toctree-l3"><a class="reference internal" href="#gethostname">getHostname</a></li> <li class="toctree-l3"><a class="reference internal" href="#gethostname">getHostname</a></li>
<li class="toctree-l3"><a class="reference internal" href="#gethackinglevel">getHackingLevel</a></li> <li class="toctree-l3"><a class="reference internal" href="#gethackinglevel">getHackingLevel</a></li>
@ -1702,6 +1743,7 @@ you create in functions such as <a class="reference external" href="https://deve
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li> <li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li> <li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html"> Changelog</a></li>
</ul> </ul>
<div role="search"> <div role="search">

@ -52,7 +52,7 @@
<div class="body" role="main"> <div class="body" role="main">
<div class="section" id="netscriptjs-netscript-2-0"> <div class="section" id="netscriptjs-netscript-2-0">
<h1>NetscriptJS (Netscript 2.0)<a class="headerlink" href="#netscriptjs-netscript-2-0" title="Permalink to this headline"></a></h1> <span id="netscriptjs"></span><h1>NetscriptJS (Netscript 2.0)<a class="headerlink" href="#netscriptjs-netscript-2-0" title="Permalink to this headline"></a></h1>
<p>Netscript 2.0, or Netscript JS, is the new and improved version of Netscript that <p>Netscript 2.0, or Netscript JS, is the new and improved version of Netscript that
allows users to write (almost) full-fledged Javascript code in their scripts, while allows users to write (almost) full-fledged Javascript code in their scripts, while
still being able to access the Netscript functions.</p> still being able to access the Netscript functions.</p>
@ -278,6 +278,7 @@ NetscriptJS and report any serious exploits.</p>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li> <li class="toctree-l1"><a class="reference internal" href="terminal.html"> Terminal</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li> <li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html"> Changelog</a></li>
</ul> </ul>
<div role="search"> <div role="search">

Binary file not shown.

File diff suppressed because one or more lines are too long

@ -3,8 +3,49 @@
Changelog Changelog
========= =========
v0.37.1 v0.38.1 - 6/15/2018
------- -------------------
* Bug Fix: Using 'Object.prototype' functions like toLocaleString() or toString() should no longer cause errors in NetscriptJS
* Implemented by Github user hydroflame:
* Accessing the 'window' and 'document' objects in Netscript JS now requires a large amount of RAM (100 GB)
* Added game option to suppress travel confirmation
* Text on buttons can no longer be highlighted
* Bug Fix: Fixed an issue that caused NaN values when exporting Real Estate in Corporations
* Bug Fix: Competition and Demand displays in Corporation are now correct (were reversed before)
* Added ps() Netscript function
* Bug Fix: grow() should no longer return/log a negative value when it runs on a server that's already at max money
* Bug Fix: serverExists() Netscript function should now properly return false for non-existent hostname/ips
* Bug Fix: Sever's security level should now properly increase when its money is grown to max value
v0.38.0 - 6/12/2018
-------------------
* New BitNode: BN-12 The Recursion - Implemented by Github user hydroflame
* Bladeburner Changes:
* Bladeburner progress is no longer reset when installing Augmentations
* The number of successess needed to increase a Contract/Operation's max level now scales with the current max level (gradually gets harder)
* All Bladeburner Augmentations are now slightly more expensive and require more reputation
* Black Operations now give higher rank rewards
* Doubled the base amount of money gained from Contracts
* Increased the amount of experience gained from Contracts/Actions
* Added a new Augmentation: The Blade's Simulacrum
* Bladeburner faction reputation gain is now properly affected by favor
* Hacking is now slightly less profitable in BitNode-3
* Updated Hacknet Nodes UI - Implemented by Github user kopelli
* Bug Fix: Fixed an exploit that allowed calling any Netscript function without incurring any RAM Cost in NetscriptJS
v0.37.2 - 6/2/2018
------------------
* After joining the Bladeburners division, there is now a button to go to the Bladeburner content
in the 'City' page
* You now start with $250m in BitNode-8 (increased from $100m)
* Bug Fix: You can now no longer directly edit Hacknet Node values through NetscriptJS (hopefully)
* Bug Fix: Bladeburners is no longer accessible in BN-8
* Bug Fix: getBitNodeMultipliers() Netscript function now returns a copy rather than the original object
v0.37.1 - 5/22/2018
-------------------
* You now earn money from successfully completing Bladeburner contracts. The amount you earn is based * You now earn money from successfully completing Bladeburner contracts. The amount you earn is based
on the difficulty of the contract. on the difficulty of the contract.
* Completing Field Analysis in Bladeburner now grants 0.1 rank * Completing Field Analysis in Bladeburner now grants 0.1 rank

@ -387,6 +387,34 @@ ls
Returns an array with the filenames of all files on the specified server (as strings). The returned array Returns an array with the filenames of all files on the specified server (as strings). The returned array
is sorted in alphabetic order is sorted in alphabetic order
ps
^^
.. js:function:: ps(hostname/ip=current ip)
:param string ip: Hostname or IP address of the target server.
If not specified, it will be the current server's IP by default
Returns an array with general information about all scripts running on the specified
target server. The information for each server is given in an object with
the following structure::
{
filename: Script name,
threads: Number of threads script is running with,
args: Script's arguments
}
Example usage (using :doc:`netscriptjs`)::
export async function main(ns) {
const ps = ns.ps("home");
for (let i = 0; i < ps.length; ++i) {
ns.tprint(ps[i].filename + ' ' + ps[i].threads);
ns.tprint(ps[i].args);
}
}
hasRootAccess hasRootAccess
^^^^^^^^^^^^^ ^^^^^^^^^^^^^

@ -1,3 +1,5 @@
.. _netscriptjs:
NetscriptJS (Netscript 2.0) NetscriptJS (Netscript 2.0)
=========================== ===========================
Netscript 2.0, or Netscript JS, is the new and improved version of Netscript that Netscript 2.0, or Netscript JS, is the new and improved version of Netscript that

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -3,6 +3,17 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Bitburner</title> <title>Bitburner</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
<link rel="manifest" href="dist/site.webmanifest">
<link rel="mask-icon" href="dist/safari-pinned-tab.svg" color="#000000">
<link rel="shortcut icon" href="favicon.ico">
<meta name="apple-mobile-web-app-title" content="Bitburner">
<meta name="application-name" content="Bitburner">
<meta name="msapplication-TileColor" content="#000000">
<meta name="msapplication-config" content="dist/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" type="text/css" href="css/styles.css" /> <link rel="stylesheet" type="text/css" href="css/styles.css" />
<link rel="stylesheet" type="text/css" href="css/terminal.css" /> <link rel="stylesheet" type="text/css" href="css/terminal.css" />
<link rel="stylesheet" type="text/css" href="css/menupages.css" /> <link rel="stylesheet" type="text/css" href="css/menupages.css" />
@ -23,7 +34,6 @@
ga('create', 'UA-100157497-1', 'auto'); ga('create', 'UA-100157497-1', 'auto');
ga('send', 'pageview'); ga('send', 'pageview');
</script> </script>
</head> </head>
<body> <body>
@ -89,6 +99,9 @@
<li id="options-tab" class="mainmenu-accordion-panel"> <li id="options-tab" class="mainmenu-accordion-panel">
<a id="options-menu-link"> Options </a> <a id="options-menu-link"> Options </a>
</li> </li>
<li id="dev-tab" class="mainmenu-accordion-panel">
<a id="dev-menu-link"> Dev </a>
</li>
</ul> </ul>
</div> </div>
@ -97,7 +110,7 @@
<div id="script-editor-filename-wrapper"> <div id="script-editor-filename-wrapper">
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p> <p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"> </input> <input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
</div> </div>
<div id="javascript-editor"></div> <div id="javascript-editor"></div>
@ -147,9 +160,7 @@
<fieldset> <fieldset>
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label> <label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
<input type="range" max="1000" min="50" value="200" <input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr" />
step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"
</input>
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em> <em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset> </fieldset>
</div> <!-- End script editor options panel --> </div> <!-- End script editor options panel -->
@ -160,8 +171,7 @@
<table id="terminal"> <table id="terminal">
<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" <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
onfocus="this.value = this.value;"/>
</td> </td>
</tr> </tr>
</table> </table>
@ -185,7 +195,7 @@
<!-- Hacknet Nodes --> <!-- Hacknet Nodes -->
<div id="hacknet-nodes-container" class="generic-menupage-container"> <div id="hacknet-nodes-container" class="generic-menupage-container">
<h1 id="hacknet-nodes-title"> Hacknet Nodes </h1> <h1 id="hacknet-nodes-title"> Hacknet Nodes </h1>
<p id="hacknet-nodes-text"> <p id="hacknet-nodes-text" class="menu-page-text">
The Hacknet is a global, decentralized network of machines. It is used by hackers all around The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced. fear of being traced.
@ -199,8 +209,11 @@
</p> </p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a> <a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br> <br>
<div id="hacknet-nodes-money-multipliers-div">" <div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money"> </p> <p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" ></span><br />
<span>Total Hacknet Node Prodution:</span><span id="hacknet-nodes-total-production"></span>
</p>
<span id="hacknet-nodes-multipliers"> <span id="hacknet-nodes-multipliers">
<a id="hacknet-nodes-1x-multiplier" class="a-link-button-inactive"> x1 </a> <a id="hacknet-nodes-1x-multiplier" class="a-link-button-inactive"> x1 </a>
<a id="hacknet-nodes-5x-multiplier" class="a-link-button"> x5 </a> <a id="hacknet-nodes-5x-multiplier" class="a-link-button"> x5 </a>
@ -208,7 +221,7 @@
<a id="hacknet-nodes-max-multiplier" class="a-link-button"> MAX </a> <a id="hacknet-nodes-max-multiplier" class="a-link-button"> MAX </a>
</span> </span>
</div> </div>
<ul id="hacknet-nodes-list" style="list-style : none;"> <ul id="hacknet-nodes-list">
</ul> </ul>
</div> </div>
@ -473,6 +486,58 @@
<p id="tutorial-text"> </p> <p id="tutorial-text"> </p>
</div> </div>
<!-- dev menu -->
<div id="dev-menu-container" class="generic-menupage-container">
<p id='dev-menu-text'>If you see this menu you can pretty much break the game. It's recommended that you use this menu only to setup a save file appropriate to test a new feature or bug fix.</p>
<p id='dev-menu-text'>Generic</p>
<a id="dev-need-money" class="a-link-button">Add $1000t</a>
<a id="dev-need-ram" class="a-link-button">Double home RAM</a>
<p id='dev-menu-text'>Augmentation related: </p>
<!-- gets populated with the list of all augments -->
<select id="dev-menu-aug-dropdown" class="dropdown"></select>
<a id="dev-add-aug" class="a-link-button tooltip">Queue Augmentation<span class="tooltiptext">May require save + reload</span></a>
<input id="dev-sf-n" type="number" class="text-input" placeholder="SourceFile-N"><input id="dev-sf-lvl" type="number" class="text-input" placeholder="SourceFile-Lvl"><a id="dev-add-source-file" class="a-link-button tooltip"> Add/Remove source file <span class="tooltiptext">If Lvl == 0 the sf will be removed, calling it with another level will replace your current source file. You CAN set a source file higher than it's maximum level.</span></a>
<p id='dev-menu-text'>Faction related: </p>
<select id="dev-menu-faction-dropdown" class="dropdown"></select>
<a id="dev-add-faction" class="a-link-button tooltip">Receive invite<span class="tooltiptext">May require save + reload</span></a>
<p id='dev-menu-text'>Program related: </p>
<select id="dev-menu-connect-dropdown" class="dropdown"></select>
<a id="dev-connect" class="a-link-button tooltip">Connect<span class="tooltiptext">Connect to the target server.</span></a>
<select id="dev-menu-add-program-dropdown" class="dropdown"></select>
<a id="dev-add-program" class="a-link-button tooltip">Add Program<span class="tooltiptext">Add this program to the player home server, won't add the same program twice.</span></a>
<a id="dev-bit-flume" class="a-link-button tooltip">Trigger BitFlume<span class="tooltiptext">Quick escape to change BN, does not give SFs</span></a>
<p id='dev-menu-text'>Server related: </p>
<a id="dev-open-all" class="a-link-button tooltip">NUKE + ports all servers<span class="tooltiptext">Opens all ports, nukes all servers, gains root access to everything (still need the appropriate hacking level)</span></a>
<a id="dev-min-security" class="a-link-button tooltip">minimize all servers security<span class="tooltiptext">All servers security will be set to their minimum security</span></a>
<a id="dev-max-money" class="a-link-button tooltip">maximize all servers money<span class="tooltiptext">Set all servers available money to maximum for that server</span></a>
<p id='dev-menu-text'>Exp/stats related: </p>
<input id="dev-hacking-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-hacking" class="a-link-button tooltip">add hacking exp<span class="tooltiptext">Add that many hacking experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-strength-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-strength" class="a-link-button tooltip">add strength exp<span class="tooltiptext">Add that many strength experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-defense-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-defense" class="a-link-button tooltip">add defense exp<span class="tooltiptext">Add that many defense experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-dexterity-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-dexterity" class="a-link-button tooltip">add dexterity exp<span class="tooltiptext">Add that many dexterity experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-agility-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-agility" class="a-link-button tooltip">add agility exp<span class="tooltiptext">Add that many agility experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-charisma-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-charisma" class="a-link-button tooltip">add charisma exp<span class="tooltiptext">Add that many charisma experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-intelligence-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-intelligence" class="a-link-button tooltip">add intelligence exp<span class="tooltiptext">Add that many intelligence experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<a id="dev-enable-intelligence" class="a-link-button tooltip"> enable intelligence<span class="tooltiptext">Enables the intelligence stat</span></a>
<a id="dev-disable-intelligence" class="a-link-button tooltip"> disable intelligence<span class="tooltiptext">Disables the intelligence stat</span></a>
</div>
<!-- Location (visiting a location in World) --> <!-- Location (visiting a location in World) -->
<div id="location-container" class="generic-menupage-container"> <div id="location-container" class="generic-menupage-container">
<a id="location-return-to-world-button" class="a-link-button"> Return to World </a> <a id="location-return-to-world-button" class="a-link-button"> Return to World </a>
@ -654,7 +719,7 @@
<div id="yes-no-text-input-box-container" class="popup-box-container"> <div id="yes-no-text-input-box-container" class="popup-box-container">
<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> <input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<span id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </span> <span id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </span>
<span id="yes-no-text-input-box-no" class="popup-box-button"> No </span> <span id="yes-no-text-input-box-no" class="popup-box-button"> No </span>
</div> </div>
@ -744,9 +809,7 @@
</span> </span>
</label> </label>
<input type ="range" max="250" min="15" <input type ="range" max="250" min="15" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="100" />
step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="100">
</input>
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -760,9 +823,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" <input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50">
</input>
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -776,9 +837,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" <input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50">
</input>
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -790,9 +849,7 @@
</span> </span>
</label> </label>
<input type="range" max="600" min="0" <input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60">
</input>
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em> <em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -819,6 +876,16 @@
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites"> <input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</fieldset> </fieldset>
<!-- Suppress travel confirmation -->
<fieldset>
<label for="settingsSuppressTravelConfirmation" class="tooltip">Suppress Travel Confirmation:
<span class="tooltiptext">
If this is set, the confirmation message before traveling will not show up. You will automatically be deducted the travel cost as soon as you click.
</span>
</label>
<input type="checkbox" name="settingsSuppressTravelConfirmation" id="settingsSuppressTravelConfirmation">
</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:
@ -843,7 +910,7 @@
<div id="game-options-right-panel"> <div id="game-options-right-panel">
<a class="a-link-button" style="display:block;" href="https://bitburner.wikia.com/wiki/Changelog" target="_blank"> Changelog </a> <a class="a-link-button" style="display:block;" href="https://bitburner.wikia.com/wiki/Changelog" target="_blank"> Changelog </a>
<a class="a-link-button" style="display:block;" href="https://bitburner.wikia.com" target="_blank">Wiki</a> <a class="a-link-button" style="display:block;" href="https://bitburner.wikia.com" target="_blank">Wiki</a>
<a class="a-link-button" style="display:block;", href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a> <a class="a-link-button" style="display:block;" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
<a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a> <a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a>
<a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a> <a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a>
<a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a> <a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a>
@ -872,6 +939,6 @@
<div class="loaderspinner"></div> <div class="loaderspinner"></div>
<div class="loaderlabel">Loading Bitburner...</div> <div class="loaderlabel">Loading Bitburner...</div>
</div> </div>
</body>
<script src="dist/engine.bundle.js"></script> <script src="dist/engine.bundle.js"></script>
</body>
</html> </html>

@ -103,7 +103,7 @@ var NetscriptHighlightRules = function(options) {
"JSON|Math|" + // Other "JSON|Math|" + // Other
"this|arguments|prototype|window|document" , // Pseudo "this|arguments|prototype|window|document" , // Pseudo
"keyword": "keyword":
"const|yield|import|get|set|async|await|foop|" + "const|yield|import|get|set|async|await|" +
"break|case|catch|continue|default|delete|do|else|finally|for|function|" + "break|case|catch|continue|default|delete|do|else|finally|for|function|" +
"if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" + "if|in|of|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" +
"__parent__|__count__|escape|unescape|with|__proto__|" + "__parent__|__count__|escape|unescape|with|__proto__|" +

12158
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -10,34 +10,27 @@
"acorn-dynamic-import": "^2.0.0", "acorn-dynamic-import": "^2.0.0",
"ajv": "^5.1.5", "ajv": "^5.1.5",
"ajv-keywords": "^2.0.0", "ajv-keywords": "^2.0.0",
"async": "^2.1.2", "async": "^2.6.1",
"bluebird": "^3.5.1", "bluebird": "^3.5.1",
"brace": "^0.11.1", "brace": "^0.11.1",
"decimal.js": "7.2.3", "decimal.js": "7.2.3",
"enhanced-resolve": "^3.4.0", "enhanced-resolve": "^4.0.0",
"escope": "^3.6.0", "escope": "^3.6.0",
"file-saver": "^1.3.3", "file-saver": "^1.3.8",
"interpret": "^1.0.0", "interpret": "^1.0.0",
"jquery": "^3.3.1", "jquery": "^3.3.1",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"json5": "^0.5.1",
"jsplumb": "^2.6.8", "jsplumb": "^2.6.8",
"jszip": "^3.1.5", "jszip": "^3.1.5",
"loader-runner": "^2.3.0", "loader-runner": "^2.3.0",
"loader-utils": "^1.1.0", "loader-utils": "^1.1.0",
"memory-fs": "~0.4.1", "memory-fs": "~0.4.1",
"mkdirp": "~0.5.0", "numeral": "2.0.6",
"node-libs-browser": "^2.0.0",
"source-map": "^0.5.3",
"sprintf-js": "^1.1.1", "sprintf-js": "^1.1.1",
"supports-color": "^4.2.1", "tapable": "^1.0.0",
"tapable": "^0.2.7", "uglifyjs-webpack-plugin": "^1.2.5",
"uglifyjs-webpack-plugin": "^0.4.6",
"uuid": "^3.2.1", "uuid": "^3.2.1",
"w3c-blob": "0.0.1", "w3c-blob": "0.0.1"
"watchpack": "^1.4.0",
"webpack-sources": "^1.0.1",
"yargs": "^8.0.2"
}, },
"description": "A cyberpunk-themed incremental game", "description": "A cyberpunk-themed incremental game",
"devDependencies": { "devDependencies": {
@ -46,45 +39,36 @@
"bundle-loader": "~0.5.0", "bundle-loader": "~0.5.0",
"chai": "^4.1.2", "chai": "^4.1.2",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"codacy-coverage": "^2.0.1", "css-loader": "^0.28.11",
"codecov.io": "^0.1.2",
"coffee-loader": "~0.7.1",
"coffee-script": "^1.10.0",
"coveralls": "^2.11.2",
"css-loader": "^0.28.3",
"es6-promise-polyfill": "^1.1.1", "es6-promise-polyfill": "^1.1.1",
"eslint": "^4.3.0", "eslint": "^4.19.1",
"eslint-plugin-node": "^5.1.1", "eslint-plugin-node": "^6.0.1",
"express": "~4.13.1", "file-loader": "^1.1.11",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"i18n-webpack-plugin": "^1.0.0", "i18n-webpack-plugin": "^1.0.0",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"jade": "^1.11.0",
"jade-loader": "~0.8.0",
"js-beautify": "^1.5.10", "js-beautify": "^1.5.10",
"less": "^2.5.1", "json5": "^1.0.1",
"less-loader": "^4.0.3", "less": "^3.0.4",
"lodash": "^4.17.4", "less-loader": "^4.1.0",
"lodash": "^4.17.10",
"mkdirp": "^0.5.1",
"mocha": "^3.2.0", "mocha": "^3.2.0",
"mocha-lcov-reporter": "^1.0.0", "mocha-lcov-reporter": "^1.0.0",
"nsp": "^2.6.1", "nsp": "^3.2.1",
"raw-loader": "~0.5.0", "raw-loader": "~0.5.0",
"react": "^15.2.1",
"react-dom": "^15.2.1",
"script-loader": "~0.7.0", "script-loader": "~0.7.0",
"should": "^11.1.1", "should": "^11.1.1",
"simple-git": "^1.65.0", "simple-git": "^1.96.0",
"sinon": "^2.3.2", "sinon": "^2.3.2",
"style-loader": "^0.18.1", "source-map": "^0.7.3",
"url-loader": "~0.5.0", "style-loader": "^0.21.0",
"val-loader": "^1.0.2", "url-loader": "^1.0.1",
"vm-browserify": "~0.0.0", "watchpack": "^1.6.0",
"webpack": "^4.1.1", "webpack": "^4.12.0",
"webpack-cli": "^2.0.12", "webpack-cli": "^3.0.4",
"webpack-dev-middleware": "^1.9.0", "webpack-dev-middleware": "^3.1.3",
"webpack-dev-server": "^3.1.4", "webpack-dev-server": "^3.1.4",
"worker-loader": "^0.8.0" "worker-loader": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=4.3.0 <5.0.0 || >=5.10" "node": ">=4.3.0 <5.0.0 || >=5.10"
@ -97,7 +81,11 @@
"url": "git+https://github.com/danielyxie/bitburner.git" "url": "git+https://github.com/danielyxie/bitburner.git"
}, },
"scripts": { "scripts": {
"start:dev": "webpack-dev-server" "start:dev": "webpack-dev-server",
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development"
}, },
"version": "0.35.1" "version": "0.35.1"
} }

@ -9,7 +9,7 @@ import {printArray, createElement,
createAccordionElement, removeElement, createAccordionElement, removeElement,
removeChildrenFromElement, exceptionAlert} from "../utils/HelperFunctions.js"; removeChildrenFromElement, exceptionAlert} from "../utils/HelperFunctions.js";
import {logBoxCreate} from "../utils/LogBox.js"; import {logBoxCreate} from "../utils/LogBox.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
/* { /* {

@ -184,6 +184,7 @@ let AugmentationNames = {
BladeArmorUnibeam: "BLADE-51b Tesla Armor: Unibeam Upgrade", BladeArmorUnibeam: "BLADE-51b Tesla Armor: Unibeam Upgrade",
BladeArmorOmnibeam: "BLADE-51b Tesla Armor: Omnibeam Upgrade", BladeArmorOmnibeam: "BLADE-51b Tesla Armor: Omnibeam Upgrade",
BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade", BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade",
BladesSimulacrum: "The Blade's Simulacrum",
//Wasteland Augs //Wasteland Augs
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System //PepBoy: "P.E.P-Boy", Plasma Energy Projection System
@ -1552,7 +1553,7 @@ function initAugmentations() {
var BladeburnersFactionName = "Bladeburners"; var BladeburnersFactionName = "Bladeburners";
if (factionExists(BladeburnersFactionName)) { if (factionExists(BladeburnersFactionName)) {
var EsperEyewear = new Augmentation({ var EsperEyewear = new Augmentation({
name:AugmentationNames.EsperEyewear, repCost:400, moneyCost:30e6, name:AugmentationNames.EsperEyewear, repCost:500, moneyCost:33e6,
info:"Ballistic-grade protective and retractable eyewear that was designed specially " + info:"Ballistic-grade protective and retractable eyewear that was designed specially " +
"for Bladeburner units. This " + "for Bladeburner units. This " +
"is implanted by installing a mechanical frame in the skull's orbit. " + "is implanted by installing a mechanical frame in the skull's orbit. " +
@ -1569,7 +1570,7 @@ function initAugmentations() {
resetAugmentation(EsperEyewear); resetAugmentation(EsperEyewear);
var EMS4Recombination = new Augmentation({ var EMS4Recombination = new Augmentation({
name:AugmentationNames.EMS4Recombination, repCost: 800, moneyCost:50e6, name:AugmentationNames.EMS4Recombination, repCost: 1e3, moneyCost:55e6,
info:"A DNA recombination of the EMS-4 Gene. This genetic engineering " + info:"A DNA recombination of the EMS-4 Gene. This genetic engineering " +
"technique was originally used on Bladeburners during the Synthoid uprising " + "technique was originally used on Bladeburners during the Synthoid uprising " +
"to induce wakefulness and concentration, suppress fear, reduce empathy, and " + "to induce wakefulness and concentration, suppress fear, reduce empathy, and " +
@ -1583,7 +1584,7 @@ function initAugmentations() {
resetAugmentation(EMS4Recombination); resetAugmentation(EMS4Recombination);
var OrionShoulder = new Augmentation({ var OrionShoulder = new Augmentation({
name:AugmentationNames.OrionShoulder, repCost:2e3, moneyCost:100e6, name:AugmentationNames.OrionShoulder, repCost:2.5e3, moneyCost:110e6,
info:"A bionic shoulder augmentation for the right shoulder. Using cybernetics, " + info:"A bionic shoulder augmentation for the right shoulder. Using cybernetics, " +
"the ORION-MKIV shoulder enhances the strength and dexterity " + "the ORION-MKIV shoulder enhances the strength and dexterity " +
"of the user's right arm. It also provides protection due to its " + "of the user's right arm. It also provides protection due to its " +
@ -1597,7 +1598,7 @@ function initAugmentations() {
resetAugmentation(OrionShoulder); resetAugmentation(OrionShoulder);
var HyperionV1 = new Augmentation({ var HyperionV1 = new Augmentation({
name:AugmentationNames.HyperionV1, repCost: 4e3, moneyCost:500e6, name:AugmentationNames.HyperionV1, repCost: 5e3, moneyCost:550e6,
info:"A pair of mini plasma cannons embedded into the hands. The Hyperion is capable " + info:"A pair of mini plasma cannons embedded into the hands. The Hyperion is capable " +
"of rapidly firing bolts of high-density plasma. The weapon is meant to " + "of rapidly firing bolts of high-density plasma. The weapon is meant to " +
"be used against augmented enemies as the ionized " + "be used against augmented enemies as the ionized " +
@ -1611,7 +1612,7 @@ function initAugmentations() {
resetAugmentation(HyperionV1); resetAugmentation(HyperionV1);
var HyperionV2 = new Augmentation({ var HyperionV2 = new Augmentation({
name:AugmentationNames.HyperionV2, repCost:8e3, moneyCost:1e9, name:AugmentationNames.HyperionV2, repCost:10e3, moneyCost:1.1e9,
info:"A pair of mini plasma cannons embedded into the hands. This augmentation " + info:"A pair of mini plasma cannons embedded into the hands. This augmentation " +
"is more advanced and powerful than the original V1 model. This V2 model is " + "is more advanced and powerful than the original V1 model. This V2 model is " +
"more power-efficiency, more accurate, and can fire plasma bolts at a much " + "more power-efficiency, more accurate, and can fire plasma bolts at a much " +
@ -1624,7 +1625,7 @@ function initAugmentations() {
resetAugmentation(HyperionV2); resetAugmentation(HyperionV2);
var GolemSerum = new Augmentation({ var GolemSerum = new Augmentation({
name:AugmentationNames.GolemSerum, repCost:10e3, moneyCost:2e9, name:AugmentationNames.GolemSerum, repCost:12.5e3, moneyCost:2.2e9,
info:"A serum that permanently enhances many aspects of a human's capabilities, " + info:"A serum that permanently enhances many aspects of a human's capabilities, " +
"including strength, speed, immune system performance, and mitochondrial efficiency. The " + "including strength, speed, immune system performance, and mitochondrial efficiency. The " +
"serum was originally developed by the Chinese military in an attempt to " + "serum was originally developed by the Chinese military in an attempt to " +
@ -1637,7 +1638,7 @@ function initAugmentations() {
resetAugmentation(GolemSerum); resetAugmentation(GolemSerum);
var VangelisVirus = new Augmentation({ var VangelisVirus = new Augmentation({
name:AugmentationNames.VangelisVirus, repCost:6e3, moneyCost:500e6, name:AugmentationNames.VangelisVirus, repCost:7.5e3, moneyCost:550e6,
info:"A synthetic symbiotic virus that is injected into the human brain tissue. The Vangelis virus " + info:"A synthetic symbiotic virus that is injected into the human brain tissue. The Vangelis virus " +
"heightens the senses and focus of its host, and also enhances its intuition.<br><br>" + "heightens the senses and focus of its host, and also enhances its intuition.<br><br>" +
"This augmentation:<br>" + "This augmentation:<br>" +
@ -1649,7 +1650,7 @@ function initAugmentations() {
resetAugmentation(VangelisVirus); resetAugmentation(VangelisVirus);
var VangelisVirus3 = new Augmentation({ var VangelisVirus3 = new Augmentation({
name:AugmentationNames.VangelisVirus3, repCost:12e3, moneyCost:2e9, name:AugmentationNames.VangelisVirus3, repCost:15e3, moneyCost:2.2e9,
info:"An improved version of Vangelis, a synthetic symbiotic virus that is " + info:"An improved version of Vangelis, a synthetic symbiotic virus that is " +
"injected into the human brain tissue. On top of the benefits of the original " + "injected into the human brain tissue. On top of the benefits of the original " +
"virus, this also grants an accelerated healing factor and enhanced " + "virus, this also grants an accelerated healing factor and enhanced " +
@ -1664,7 +1665,7 @@ function initAugmentations() {
resetAugmentation(VangelisVirus3); resetAugmentation(VangelisVirus3);
var INTERLINKED = new Augmentation({ var INTERLINKED = new Augmentation({
name:AugmentationNames.INTERLINKED, repCost:8e3, moneyCost:1e9, name:AugmentationNames.INTERLINKED, repCost:10e3, moneyCost:1.1e9,
info:"The DNA is genetically modified to enhance the human's body " + info:"The DNA is genetically modified to enhance the human's body " +
"extracellular matrix (ECM). This improves the ECM's ability to " + "extracellular matrix (ECM). This improves the ECM's ability to " +
"structurally support the body and grants heightened strength and " + "structurally support the body and grants heightened strength and " +
@ -1677,7 +1678,7 @@ function initAugmentations() {
resetAugmentation(INTERLINKED); resetAugmentation(INTERLINKED);
var BladeRunner = new Augmentation({ var BladeRunner = new Augmentation({
name:AugmentationNames.BladeRunner, repCost:8e3, moneyCost:1.5e9, name:AugmentationNames.BladeRunner, repCost:8e3, moneyCost:1.65e9,
info:"A cybernetic foot augmentation that was specially created for Bladeburners " + info:"A cybernetic foot augmentation that was specially created for Bladeburners " +
"during the Synthoid Uprising. The organic musculature of the human foot " + "during the Synthoid Uprising. The organic musculature of the human foot " +
"is enhanced with flexible carbon nanotube matrices that are controlled by " + "is enhanced with flexible carbon nanotube matrices that are controlled by " +
@ -1691,7 +1692,7 @@ function initAugmentations() {
resetAugmentation(BladeRunner); resetAugmentation(BladeRunner);
var BladeArmor = new Augmentation({ var BladeArmor = new Augmentation({
name:AugmentationNames.BladeArmor, repCost:4e3, moneyCost:250e6, name:AugmentationNames.BladeArmor, repCost:5e3, moneyCost:275e6,
info:"A powered exoskeleton suit (exosuit) designed as armor for Bladeburner units. This " + info:"A powered exoskeleton suit (exosuit) designed as armor for Bladeburner units. This " +
"exoskeleton is incredibly adaptable and can protect the wearer from blunt, piercing, " + "exoskeleton is incredibly adaptable and can protect the wearer from blunt, piercing, " +
"concussive, thermal, chemical, and electric trauma. It also enhances the user's " + "concussive, thermal, chemical, and electric trauma. It also enhances the user's " +
@ -1705,7 +1706,7 @@ function initAugmentations() {
resetAugmentation(BladeArmor); resetAugmentation(BladeArmor);
var BladeArmorPowerCells = new Augmentation({ var BladeArmorPowerCells = new Augmentation({
name:AugmentationNames.BladeArmorPowerCells, repCost:6e3, moneyCost:500e6, name:AugmentationNames.BladeArmorPowerCells, repCost:7.5e3, moneyCost:550e6,
info:"Upgrades the BLADE-51b Tesla Armor with Ion Power Cells, which are capable of " + info:"Upgrades the BLADE-51b Tesla Armor with Ion Power Cells, which are capable of " +
"more efficiently storing and using power.<br><br>" + "more efficiently storing and using power.<br><br>" +
"This augmentation:<br>" + "This augmentation:<br>" +
@ -1718,7 +1719,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorPowerCells); resetAugmentation(BladeArmorPowerCells);
var BladeArmorEnergyShielding = new Augmentation({ var BladeArmorEnergyShielding = new Augmentation({
name:AugmentationNames.BladeArmorEnergyShielding, repCost:7e3, moneyCost:1e9, name:AugmentationNames.BladeArmorEnergyShielding, repCost:8.5e3, moneyCost:1.1e9,
info:"Upgrades the BLADE-51b Tesla Armor with a plasma energy propulsion system " + info:"Upgrades the BLADE-51b Tesla Armor with a plasma energy propulsion system " +
"that is capable of projecting an energy shielding force field.<br><br>" + "that is capable of projecting an energy shielding force field.<br><br>" +
"This augmentation:<br>" + "This augmentation:<br>" +
@ -1730,7 +1731,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorEnergyShielding); resetAugmentation(BladeArmorEnergyShielding);
var BladeArmorUnibeam = new Augmentation({ var BladeArmorUnibeam = new Augmentation({
name:AugmentationNames.BladeArmorUnibeam, repCost:10e3, moneyCost:3e9, name:AugmentationNames.BladeArmorUnibeam, repCost:12.5e3, moneyCost:3.3e9,
info:"Upgrades the BLADE-51b Tesla Armor with a concentrated deuterium-fluoride laser " + info:"Upgrades the BLADE-51b Tesla Armor with a concentrated deuterium-fluoride laser " +
"weapon. It's precision an accuracy makes it useful for quickly neutralizing " + "weapon. It's precision an accuracy makes it useful for quickly neutralizing " +
"threats while keeping casualties to a minimum.<br><br>" + "threats while keeping casualties to a minimum.<br><br>" +
@ -1742,7 +1743,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorUnibeam); resetAugmentation(BladeArmorUnibeam);
var BladeArmorOmnibeam = new Augmentation({ var BladeArmorOmnibeam = new Augmentation({
name:AugmentationNames.BladeArmorOmnibeam, repCost:20e3, moneyCost:5e9, name:AugmentationNames.BladeArmorOmnibeam, repCost:25e3, moneyCost:5.5e9,
info:"Upgrades the BLADE-51b Tesla Armor Unibeam augmentation to use " + info:"Upgrades the BLADE-51b Tesla Armor Unibeam augmentation to use " +
"multiple-fiber system. The upgraded weapon uses multiple fiber laser " + "multiple-fiber system. The upgraded weapon uses multiple fiber laser " +
"modules that combine together to form a single, more powerful beam of up to " + "modules that combine together to form a single, more powerful beam of up to " +
@ -1755,7 +1756,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorOmnibeam); resetAugmentation(BladeArmorOmnibeam);
var BladeArmorIPU = new Augmentation({ var BladeArmorIPU = new Augmentation({
name:AugmentationNames.BladeArmorIPU, repCost: 5e3, moneyCost:200e6, name:AugmentationNames.BladeArmorIPU, repCost: 6e3, moneyCost:220e6,
info:"Upgrades the BLADE-51b Tesla Armor with an AI Information Processing " + info:"Upgrades the BLADE-51b Tesla Armor with an AI Information Processing " +
"Unit that was specially designed to analyze Synthoid related data and " + "Unit that was specially designed to analyze Synthoid related data and " +
"information.<br><br>" + "information.<br><br>" +
@ -1766,6 +1767,19 @@ function initAugmentations() {
}); });
BladeArmorIPU.addToFactions([BladeburnersFactionName]); BladeArmorIPU.addToFactions([BladeburnersFactionName]);
resetAugmentation(BladeArmorIPU); resetAugmentation(BladeArmorIPU);
var BladesSimulacrum = new Augmentation({
name:AugmentationNames.BladesSimulacrum, repCost:6e3, moneyCost:75e9,
info:"A highly-advanced matter phase-shifter module that is embedded " +
"in the brainstem and cerebellum. This augmentation allows " +
"the user to project and control a holographic simulacrum within an " +
"extremely large radius. These specially-modified holograms were specially " +
"weaponized by Bladeburner units to be used against Synthoids.<br><br>" +
"This augmentation allows you to perform Bladeburner actions and other " +
"actions (such as working, commiting crimes, etc.) at the same time."
});
BladesSimulacrum.addToFactions([BladeburnersFactionName]);
resetAugmentation(BladesSimulacrum);
} }
//Update costs based on how many have been purchased //Update costs based on how many have been purchased
@ -1777,8 +1791,6 @@ function initAugmentations() {
} }
Player.reapplyAllAugmentations(); Player.reapplyAllAugmentations();
} }
//Resets an Augmentation during (re-initizliation) //Resets an Augmentation during (re-initizliation)
@ -2350,6 +2362,8 @@ function applyAugmentation(aug, reapply=false) {
Player.bladeburner_analysis_mult *= 1.15; Player.bladeburner_analysis_mult *= 1.15;
Player.bladeburner_success_chance_mult *= 1.02; Player.bladeburner_success_chance_mult *= 1.02;
break; break;
case AugmentationNames.BladesSimulacrum: //No multiplier effect
break;
default: default:
throw new Error("ERROR: No such augmentation!"); throw new Error("ERROR: No such augmentation!");
return; return;
@ -2594,8 +2608,9 @@ function displaySourceFiles(listElement, sourceFiles) {
console.log("ERROR: Invalid source file number: " + sourceFiles[i].n); console.log("ERROR: Invalid source file number: " + sourceFiles[i].n);
continue; continue;
} }
const maxLevel = sourceFiles[i].n == 12 ? "∞" : "3";
var accordion = createAccordionElement({ var accordion = createAccordionElement({
hdrText:sourceFileObject.name + "<br>" + "Level " + (sourceFiles[i].lvl) + " / 3", hdrText:sourceFileObject.name + "<br>" + "Level " + (sourceFiles[i].lvl) + " / "+maxLevel,
panelText:sourceFileObject.info panelText:sourceFileObject.info
}); });

@ -54,7 +54,7 @@ function initBitNodes() {
"The starting and maximum amount of money on servers is reduced by 75%<br>" + "The starting and maximum amount of money on servers is reduced by 75%<br>" +
"Server growth rate is reduced by 80%<br>" + "Server growth rate is reduced by 80%<br>" +
"You will start out with $150b so that you can start your corporation<br>" + "You will start out with $150b so that you can start your corporation<br>" +
"You now only need 75 reputation with a faction in order to donate to it, rather than 150<br><br>" + "You now only need 75 favour with a faction in order to donate to it, rather than 150<br><br>" +
"Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will " + "Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will " +
"upgrade its level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although " + "upgrade its level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although " +
"some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" + "some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" +
@ -156,10 +156,13 @@ function initBitNodes() {
"Level 1: 24%<br>" + "Level 1: 24%<br>" +
"Level 2: 36%<br>" + "Level 2: 36%<br>" +
"Level 3: 42%"); "Level 3: 42%");
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
"To iterate is human, to recurse divine.<br><br>" +
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give your Souce-File 12, or " +
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
"of Source-File 12 will increase all of your multipliers by 1%.");
//Books: Frontera, Shiner //Books: Frontera, Shiner
BitNodes["BitNode12"] = new BitNode(12, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode13"] = new BitNode(13, "", "COMING SOON");
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON"); BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON"); BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON"); BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON");
@ -232,10 +235,10 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.RepToDonateToFaction = 0.5; BitNodeMultipliers.RepToDonateToFaction = 0.5;
BitNodeMultipliers.AugmentationRepCost = 3; BitNodeMultipliers.AugmentationRepCost = 3;
BitNodeMultipliers.AugmentationMoneyCost = 3; BitNodeMultipliers.AugmentationMoneyCost = 3;
BitNodeMultipliers.ServerMaxMoney = 0.25; BitNodeMultipliers.ServerMaxMoney = 0.2;
BitNodeMultipliers.ServerStartingMoney = 0.25; BitNodeMultipliers.ServerStartingMoney = 0.2;
BitNodeMultipliers.ServerGrowthRate = 0.20; BitNodeMultipliers.ServerGrowthRate = 0.2;
BitNodeMultipliers.ScriptHackMoney = 0.25; BitNodeMultipliers.ScriptHackMoney = 0.2;
BitNodeMultipliers.CompanyWorkMoney = 0.25; BitNodeMultipliers.CompanyWorkMoney = 0.25;
BitNodeMultipliers.CrimeMoney = 0.25; BitNodeMultipliers.CrimeMoney = 0.25;
BitNodeMultipliers.HacknetNodeMoney = 0.25; BitNodeMultipliers.HacknetNodeMoney = 0.25;
@ -304,10 +307,56 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.InfiltrationRep = 2.5; BitNodeMultipliers.InfiltrationRep = 2.5;
BitNodeMultipliers.CorporationValuation = 0.01; BitNodeMultipliers.CorporationValuation = 0.01;
break; break;
case 12: //The Recursion
let sf12Lvl = 0;
for (let i = 0; i < Player.sourceFiles.length; i++) {
if (Player.sourceFiles[i].n === 12) {
sf12Lvl = Player.sourceFiles[i].lvl;
}
}
const inc = Math.pow(1.01, sf12Lvl);
const dec = Math.pow(0.99, sf12Lvl);
BitNodeMultipliers.HackingLevelMultiplier = dec;
BitNodeMultipliers.ServerMaxMoney = dec;
BitNodeMultipliers.ServerStartingMoney = dec;
BitNodeMultipliers.ServerGrowthRate = dec;
BitNodeMultipliers.ServerWeakenRate = dec;
//Does not scale, otherwise security might start at 300+
BitNodeMultipliers.ServerStartingSecurity = 1.5;
BitNodeMultipliers.ManualHackMoney = dec;
BitNodeMultipliers.ScriptHackMoney = dec;
BitNodeMultipliers.CompanyWorkMoney = dec;
BitNodeMultipliers.CrimeMoney = dec;
BitNodeMultipliers.HacknetNodeMoney = dec;
BitNodeMultipliers.CompanyWorkExpGain = dec;
BitNodeMultipliers.ClassGymExpGain = dec;
BitNodeMultipliers.FactionWorkExpGain = dec;
BitNodeMultipliers.HackExpGain = dec;
BitNodeMultipliers.CrimeExpGain = dec;
BitNodeMultipliers.FactionWorkRepGain = dec;
BitNodeMultipliers.FactionPassiveRepGain = dec;
BitNodeMultipliers.RepToDonateToFaction = inc;
BitNodeMultipliers.AugmentationRepCost = inc;
BitNodeMultipliers.AugmentationMoneyCost = inc;
BitNodeMultipliers.InfiltrationMoney = dec;
BitNodeMultipliers.InfiltrationRep = dec;
BitNodeMultipliers.CorporationValuation = dec;
default: default:
console.log("WARNING: Player.bitNodeN invalid"); console.log("WARNING: Player.bitNodeN invalid");
break; break;
} }
} }
export {initBitNodes, BitNode, BitNodes, BitNodeMultipliers, initBitNodeMultipliers}; export {initBitNodes,
BitNode,
BitNodes,
BitNodeMultipliers,
initBitNodeMultipliers};

@ -1,10 +1,11 @@
import {Augmentations, AugmentationNames} from "./Augmentations.js";
import {CONSTANTS} from "./Constants.js"; import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js"; import {Engine} from "./engine.js";
import {Faction, Factions, factionExists, import {Faction, Factions, factionExists,
joinFaction, displayFactionContent} from "./Faction.js"; joinFaction, displayFactionContent} from "./Faction.js";
import {Locations} from "./Location.js"; import {Locations} from "./Location.js";
import {Player} from "./Player.js"; import {Player} from "./Player.js";
import {hackWorldDaemon} from "./RedPill.js"; import {hackWorldDaemon, redPillFlag} from "./RedPill.js";
import {KEY} from "./Terminal.js"; import {KEY} from "./Terminal.js";
import {dialogBoxCreate} from "../utils/DialogBox.js"; import {dialogBoxCreate} from "../utils/DialogBox.js";
@ -15,7 +16,7 @@ import {getRandomInt, addOffset, clearObject,
createProgressBarText} from "../utils/HelperFunctions.js"; createProgressBarText} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
@ -29,10 +30,16 @@ var MaxStaminaToGainFactor = 70000; //Max Stamina is divided by this to get
var DifficultyToTimeFactor = 10; //Action Difficulty divided by this to get base action time var DifficultyToTimeFactor = 10; //Action Difficulty divided by this to get base action time
//The difficulty multiplier affects stamina loss and hp loss of an action. Its formula is: //The difficulty multiplier affects stamina loss and hp loss of an action. Also affects
//experience gain. Its formula is:
//difficulty ^ exponentialFactor + difficulty / linearFactor //difficulty ^ exponentialFactor + difficulty / linearFactor
var DiffMultExponentialFactor = 0.28; var DiffMultExponentialFactor = 0.28;
var DiffMultLinearFactor = 670; var DiffMultLinearFactor = 650;
var EffAgiLinearFactor = 90e3;
var EffDexLinearFactor = 90e3;
var EffAgiExponentialFactor = 0.031;
var EffDexExponentialFactor = 0.03;
var BaseRecruitmentTimeNeeded = 300; //Base time needed (s) to complete a Recruitment action var BaseRecruitmentTimeNeeded = 300; //Base time needed (s) to complete a Recruitment action
@ -45,13 +52,14 @@ var BaseIntGain = 0.001; //Base intelligence stat gain
var ActionCountGrowthPeriod = 300; //Time (s) it takes for action count to grow by its specified value var ActionCountGrowthPeriod = 300; //Time (s) it takes for action count to grow by its specified value
var RankToFactionRepFactor = 2; //Delta Faction Rep = this * Delta Rank var RankToFactionRepFactor = 2; //Delta Faction Rep = this * Delta Rank
var RankNeededForFaction = 25;
var ContractSuccessesPerLevel = 15; //How many successes you need to level up a contract var ContractSuccessesPerLevel = 3; //How many successes you need to level up a contract
var OperationSuccessesPerLevel = 10; //How many successes you need to level up an op var OperationSuccessesPerLevel = 2.5; //How many successes you need to level up an op
var RanksPerSkillPoint = 4; //How many ranks needed to get 1 Skill Point var RanksPerSkillPoint = 4; //How many ranks needed to get 1 Skill Point
var ContractBaseMoneyGain = 5e3; //Base Money Gained per contract var ContractBaseMoneyGain = 10e3; //Base Money Gained per contract
//DOM related variables //DOM related variables
var ActiveActionCssClass = "bladeburner-active-action"; var ActiveActionCssClass = "bladeburner-active-action";
@ -518,7 +526,10 @@ Action.prototype.getActionTime = function(inst) {
var effAgility = Player.agility * inst.skillMultipliers.effAgi; var effAgility = Player.agility * inst.skillMultipliers.effAgi;
var effDexterity = Player.dexterity * inst.skillMultipliers.effDex; var effDexterity = Player.dexterity * inst.skillMultipliers.effDex;
var statFac = 0.5 * (Math.pow(effAgility, 0.03) + Math.pow(effDexterity, 0.03)); //Always > 1 var statFac = 0.5 * (Math.pow(effAgility, EffAgiExponentialFactor) +
Math.pow(effDexterity, EffDexExponentialFactor) +
(effAgility / EffAgiLinearFactor) +
(effDexterity / EffDexLinearFactor)); //Always > 1
baseTime = Math.max(1, baseTime * skillFac / statFac); baseTime = Math.max(1, baseTime * skillFac / statFac);
@ -533,6 +544,16 @@ Action.prototype.getActionTime = function(inst) {
} }
} }
Action.prototype.getSuccessesNeededForNextLevel = function(baseSuccessesPerLevel) {
return Math.ceil((0.5) * (this.maxLevel) * (2 * baseSuccessesPerLevel + (this.maxLevel-1)));
}
Action.prototype.setMaxLevel = function(baseSuccessesPerLevel) {
if (this.successes >= this.getSuccessesNeededForNextLevel(baseSuccessesPerLevel)) {
++this.maxLevel;
}
}
Action.prototype.toJSON = function() { Action.prototype.toJSON = function() {
return Generic_toJSON("Action", this); return Generic_toJSON("Action", this);
} }
@ -684,6 +705,14 @@ function Bladeburner(params={}) {
if (params.new) {this.create();} if (params.new) {this.create();}
} }
Bladeburner.prototype.prestige = function() {
this.resetAction();
var bladeburnerFac = Factions["Bladeburners"];
if (this.rank >= RankNeededForFaction) {
joinFaction(bladeburnerFac);
}
}
Bladeburner.prototype.create = function() { Bladeburner.prototype.create = function() {
this.contracts["Tracking"] = new Contract({ this.contracts["Tracking"] = new Contract({
name:"Tracking", name:"Tracking",
@ -804,8 +833,13 @@ Bladeburner.prototype.storeCycles = function(numCycles=1) {
} }
Bladeburner.prototype.process = function() { Bladeburner.prototype.process = function() {
//Extreme condition...if Operation Daedalus is complete trigger the BitNode
if (redPillFlag === false && this.blackops.hasOwnProperty("Operation Daedalus")) {
return hackWorldDaemon(Player.bitNodeN);
}
//If the Player starts doing some other actions, set action to idle and alert //If the Player starts doing some other actions, set action to idle and alert
if (Player.isWorking) { if (Augmentations[AugmentationNames.BladesSimulacrum].owned === false && Player.isWorking) {
if (this.action.type !== ActionTypes["Idle"]) { if (this.action.type !== ActionTypes["Idle"]) {
dialogBoxCreate("Your Bladeburner action was cancelled because you started " + dialogBoxCreate("Your Bladeburner action was cancelled because you started " +
"doing something else"); "doing something else");
@ -909,7 +943,8 @@ Bladeburner.prototype.changeRank = function(change) {
throw new Error("Could not properly get Bladeburner Faction object in Bladeburner UI Overview Faction button"); throw new Error("Could not properly get Bladeburner Faction object in Bladeburner UI Overview Faction button");
} }
if (bladeburnerFac.isMember) { if (bladeburnerFac.isMember) {
bladeburnerFac.playerReputation += (RankToFactionRepFactor * change * Player.faction_rep_mult); var favorBonus = 1 + (bladeburnerFac.favor / 100);
bladeburnerFac.playerReputation += (RankToFactionRepFactor * change * Player.faction_rep_mult * favorBonus);
} }
} }
@ -1021,6 +1056,7 @@ Bladeburner.prototype.resetAction = function() {
} }
Bladeburner.prototype.startAction = function(actionId) { Bladeburner.prototype.startAction = function(actionId) {
if (actionId == null) {return;}
this.action = actionId; this.action = actionId;
this.actionTimeCurrent = 0; this.actionTimeCurrent = 0;
switch (actionId.type) { switch (actionId.type) {
@ -1067,10 +1103,7 @@ Bladeburner.prototype.startAction = function(actionId) {
this.actionTimeToComplete = 30; this.actionTimeToComplete = 30;
break; break;
case ActionTypes["Recruitment"]: case ActionTypes["Recruitment"]:
var effCharisma = Player.charisma * this.skillMultipliers.effCha; this.actionTimeToComplete = this.getRecruitmentTime();
var charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
var time = Math.max(10, Math.round(BaseRecruitmentTimeNeeded - charismaFactor));
this.actionTimeToComplete = time;
break; break;
case ActionTypes["FieldAnalysis"]: case ActionTypes["FieldAnalysis"]:
case ActionTypes["Field Analysis"]: case ActionTypes["Field Analysis"]:
@ -1130,9 +1163,9 @@ Bladeburner.prototype.completeAction = function() {
} }
if (isOperation) { if (isOperation) {
action.maxLevel = Math.floor(action.successes / OperationSuccessesPerLevel) + 1; action.setMaxLevel(OperationSuccessesPerLevel);
} else { } else {
action.maxLevel = Math.floor(action.successes / ContractSuccessesPerLevel) + 1; action.setMaxLevel(ContractSuccessesPerLevel);
} }
if (action.rankGain) { if (action.rankGain) {
var gain = addOffset(action.rankGain * rewardMultiplier, 10); var gain = addOffset(action.rankGain * rewardMultiplier, 10);
@ -1301,7 +1334,7 @@ Bladeburner.prototype.completeAction = function() {
this.startAction(this.action); //Repeat action this.startAction(this.action); //Repeat action
break; break;
case ActionTypes["Recruitment"]: case ActionTypes["Recruitment"]:
var successChance = Math.pow(Player.charisma, 0.45) / (this.teamSize + 1); var successChance = this.getRecruitmentSuccessChance();
console.log("Bladeburner recruitment success chance: " + successChance); console.log("Bladeburner recruitment success chance: " + successChance);
if (Math.random() < successChance) { if (Math.random() < successChance) {
var expGain = 2 * BaseStatGain * this.actionTimeToComplete; var expGain = 2 * BaseStatGain * this.actionTimeToComplete;
@ -1437,6 +1470,16 @@ Bladeburner.prototype.completeOperation = function(success) {
} }
} }
Bladeburner.prototype.getRecruitmentTime = function() {
var effCharisma = Player.charisma * this.skillMultipliers.effCha;
var charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
return Math.max(10, Math.round(BaseRecruitmentTimeNeeded - charismaFactor));
}
Bladeburner.prototype.getRecruitmentSuccessChance = function() {
return Math.pow(Player.charisma, 0.45) / (this.teamSize + 1);
}
//Process stat gains from Contracts, Operations, and Black Operations //Process stat gains from Contracts, Operations, and Black Operations
//@action(Action obj) - Derived action class //@action(Action obj) - Derived action class
//@success(bool) - Whether action was successful //@success(bool) - Whether action was successful
@ -1445,7 +1488,7 @@ Bladeburner.prototype.gainActionStats = function(action, success) {
//Gain multiplier based on difficulty. If this changes then the //Gain multiplier based on difficulty. If this changes then the
//same variable calculated in completeAction() needs to change too //same variable calculated in completeAction() needs to change too
var difficultyMult = Math.pow(difficulty, 0.21); var difficultyMult = Math.pow(difficulty, DiffMultExponentialFactor) + difficulty / DiffMultLinearFactor;
var time = this.actionTimeToComplete; var time = this.actionTimeToComplete;
var successMult = success ? 1 : 0.5; var successMult = success ? 1 : 0.5;
@ -1621,6 +1664,7 @@ Bladeburner.prototype.initializeDomElementRefs = function() {
operations: {}, operations: {},
blackops: {}, blackops: {},
skills: {}, skills: {},
skillPointsDisplay: null,
}; };
} }
@ -1682,6 +1726,7 @@ Bladeburner.prototype.createContent = function() {
document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv); document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv);
this.postToConsole("Bladeburner Console BETA"); this.postToConsole("Bladeburner Console BETA");
this.postToConsole("Type 'help' to see console commands");
DomElems.consoleInput.focus(); DomElems.consoleInput.focus();
} }
@ -1836,7 +1881,7 @@ Bladeburner.prototype.createOverviewContent = function() {
})); }));
//Faction button //Faction button
var bladeburnersFactionName = "Bladeburners"; const bladeburnersFactionName = "Bladeburners";
if (factionExists(bladeburnersFactionName)) { if (factionExists(bladeburnersFactionName)) {
var bladeburnerFac = Factions[bladeburnersFactionName]; var bladeburnerFac = Factions[bladeburnersFactionName];
if (!(bladeburnerFac instanceof Faction)) { if (!(bladeburnerFac instanceof Faction)) {
@ -1850,7 +1895,7 @@ Bladeburner.prototype.createOverviewContent = function() {
Engine.loadFactionContent(); Engine.loadFactionContent();
displayFactionContent(bladeburnersFactionName); displayFactionContent(bladeburnersFactionName);
} else { } else {
if (this.rank >= 25) { if (this.rank >= RankNeededForFaction) {
joinFaction(bladeburnerFac); joinFaction(bladeburnerFac);
dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction"); dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction");
removeChildrenFromElement(DomElems.overviewDiv); removeChildrenFromElement(DomElems.overviewDiv);
@ -2112,9 +2157,10 @@ Bladeburner.prototype.createSkillsContent = function() {
} }
//Skill Points //Skill Points
DomElems.actionAndSkillsDiv.appendChild(createElement("p", { DomElems.skillPointsDisplay = createElement("p", {
innerHTML:"<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>" innerHTML:"<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>"
})); });
DomElems.actionAndSkillsDiv.appendChild(DomElems.skillPointsDisplay);
//UI Element for each skill //UI Element for each skill
for (var skillName in Skills) { for (var skillName in Skills) {
@ -2226,6 +2272,8 @@ Bladeburner.prototype.updateActionAndSkillsContent = function() {
} }
break; break;
case "skills": case "skills":
DomElems.skillPointsDisplay.innerHTML = "<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>";
var skillElems = Object.keys(DomElems.skills); var skillElems = Object.keys(DomElems.skills);
for (var i = 0; i < skillElems.length; ++i) { for (var i = 0; i < skillElems.length; ++i) {
var skillElem = DomElems.skills[skillElems[i]]; var skillElem = DomElems.skills[skillElems[i]];
@ -2321,7 +2369,9 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
appendLineBreaks(el, 2); appendLineBreaks(el, 2);
el.appendChild(createElement("pre", { el.appendChild(createElement("pre", {
display:"inline-block", display:"inline-block",
innerText:"Level: " + action.level + " / " + action.maxLevel innerText:"Level: " + action.level + " / " + action.maxLevel,
tooltip:action.getSuccessesNeededForNextLevel(ContractSuccessesPerLevel) + " successes " +
"needed for next level"
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;", class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@ -2453,7 +2503,9 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
appendLineBreaks(el, 2); appendLineBreaks(el, 2);
el.appendChild(createElement("pre", { el.appendChild(createElement("pre", {
display:"inline-block", display:"inline-block",
innerText:"Level: " + action.level + " / " + action.maxLevel innerText:"Level: " + action.level + " / " + action.maxLevel,
tooltip:action.getSuccessesNeededForNextLevel(OperationSuccessesPerLevel) + " successes " +
"needed for next level"
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;", class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@ -2632,6 +2684,7 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
class: canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive", class: canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive",
margin:"3px", padding:"3px", margin:"3px", padding:"3px",
clickListener:()=>{ clickListener:()=>{
if (this.skillPoints < pointCost) {return;}
this.skillPoints -= pointCost; this.skillPoints -= pointCost;
this.upgradeSkill(skill); this.upgradeSkill(skill);
this.createActionAndSkillsContent(); this.createActionAndSkillsContent();
@ -3142,6 +3195,397 @@ Bladeburner.prototype.executeStartConsoleCommand = function(args) {
} }
} }
Bladeburner.prototype.getActionIdFromTypeAndName = function(type="", name="") {
if (type === "" || name === "") {return null;}
var action = new ActionIdentifier();
var convertedType = type.toLowerCase().trim();
var convertedName = name.toLowerCase().trim();
switch (convertedType) {
case "contract":
case "contracts":
action.type = ActionTypes["Contract"];
if (this.contracts.hasOwnProperty(name)) {
action.name = name;
return action;
} else {
return null;
}
case "operation":
case "operations":
case "op":
case "ops":
action.type = ActionTypes["Operation"];
if (this.operations.hasOwnProperty(name)) {
action.name = name;
return action;
} else {
return null;
}
case "blackoperation":
case "black operation":
case "black operations":
case "black op":
case "black ops":
case "blackop":
case "blackops":
action.type = ActionTypes["BlackOp"];
if (BlackOperations.hasOwnProperty(name)) {
action.name = name;
return action;
} else {
return null;
}
case "general":
case "general action":
case "gen":
break;
default:
return null;
}
if (convertedType.startsWith("gen")) {
switch (convertedName) {
case "training":
action.type = ActionTypes["Training"];
break;
case "recruitment":
case "recruit":
action.type = ActionTypes["Recruitment"];
break;
case "field analysis":
case "fieldanalysis":
action.type = ActionTypes["Field Analysis"];
break;
default:
return null;
}
return action;
}
}
Bladeburner.prototype.isContractNameNetscriptFn = function(name) {
return this.contracts.hasOwnProperty(name);
}
Bladeburner.prototype.isOperationNameNetscriptFn = function(name) {
return this.operations.hasOwnProperty(name);
}
Bladeburner.prototype.isBlackOpNameNetscriptFn = function(name) {
return BlackOperations.hasOwnProperty(name);
}
Bladeburner.prototype.isGeneralActionNameNetscriptFn = function(name) {
return GeneralActions.hasOwnProperty(name);
}
Bladeburner.prototype.isSkillNameNetscriptFn = function(name) {
return Skills.hasOwnProperty(name);
}
Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript) {
var errorLogText = "ERROR: Bladeburner.startAction() failed due to an invalid action specified. " +
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
"name of the operation is case-sensitive.";
var actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
workerScript.log(errorLogText);
return false;
}
try {
this.startAction(actionId);
if (workerScript.shouldLog("startAction")) {
workerScript.scriptRef.log("Starting Bladeburner action with type " + type + " and name " + name);
}
return true;
} catch(e) {
this.resetAction();
workerScript.scriptRef.log("ERROR: Bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
"Note that this name is case-sensitive and whitespace-sensitive");
return false;
}
}
Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScript) {
var errorLogText = "ERROR: Bladeburner.getActionTime() failed due to an invalid action specified. " +
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
"name of the operation is case-sensitive.";
var actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
workerScript.log(errorLogText);
return -1;
}
var actionObj = this.getActionObject(actionId);
if (actionObj == null) {
workerScript.log(errorLogText);
return -1;
}
switch (actionId.type) {
case ActionTypes["Contract"]:
case ActionTypes["Operation"]:
case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]:
return actionObj.getActionTime(this);
case ActionTypes["Training"]:
case ActionTypes["Field Analysis"]:
case ActionTypes["FieldAnalysis"]:
return 30;
case ActionTypes["Recruitment"]:
return this.getRecruitmentTime();
default:
workerScript.log(errorLogText);
return -1;
}
}
Bladeburner.prototype.getActionEstimatedSuccessChanceNetscriptFn = function(type, name, workerScript) {
var errorLogText = "ERROR: Bladeburner.getActionEstimatedSuccessChance() failed due to an invalid action specified. " +
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
"name of the operation is case-sensitive.";
var actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
workerScript.log(errorLogText);
return -1;
}
var actionObj = this.getActionObject(actionId);
if (actionObj == null) {
workerScript.log(errorLogText);
return -1;
}
switch (actionId.type) {
case ActionTypes["Contract"]:
case ActionTypes["Operation"]:
case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]:
return actionObj.getSuccessChance(this);
case ActionTypes["Training"]:
case ActionTypes["Field Analysis"]:
case ActionTypes["FieldAnalysis"]:
return 1;
case ActionTypes["Recruitment"]:
return this.getRecruitmentSuccessChance();
default:
workerScript.log(errorLogText);
return -1;
}
}
Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name, workerScript) {
var errorLogText = "ERROR: Bladeburner.getActionCountRemaining() failed due to an invalid action specified. " +
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
"name of the operation is case-sensitive.";
var actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
workerScript.log(errorLogText);
return -1;
}
var actionObj = this.getActionObject(actionId);
if (actionObj == null) {
workerScript.log(errorLogText);
return -1;
}
switch (actionId.type) {
case ActionTypes["Contract"]:
case ActionTypes["Operation"]:
case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]:
return actionObj.count;
case ActionTypes["Training"]:
case ActionTypes["Field Analysis"]:
case ActionTypes["FieldAnalysis"]:
return Infinity;
default:
workerScript.log(errorLogText);
return -1;
}
}
Bladeburner.prototype.getSkillLevelNetscriptFn = function(skillName, workerScript) {
var errorLogText = "ERROR: Bladeburner.getSkillLevel() failed due to an invalid skill specified: " +
skillName + ". Note that the name of the skill is case-sensitive";
if (skillName === "") {
//If skill name isn't specified, return an object with all of the player's skill levels
let copy = Object.assign({}, this.Skills);
return copy;
}
if (!Skills.hasOwnProperty(skillName)) {
workerScript.log(errorLogText);
return -1;
}
return Skills[skillName];
}
Bladeburner.prototype.upgradeSkillNetscriptFn = function(skillName, workerScript) {
var errorLogText = "ERROR: Bladeburner.upgradeSkill() failed due to an invalid skill specified: " +
skillName + ". Note that the name of the skill is case-sensitive";
if (!Skills.hasOwnProperty(skillName)) {
workerScript.log(errorLogText);
return false;
}
var skill = Skills[skillName];
var currentLevel = 0;
if (this.skills[skillName] && !isNaN(this.skills[skillName])) {
currentLevel = this.skills[skillName];
}
var cost = skill.baseCost + (currentLevel * skill.costInc);
if (this.skillPoints < cost) {
if (workerScript.shouldLog("upgradeSkill")) {
workerScript.log("Bladeburner.upgradeSkill() failed because you do not have enough " +
"skill points to upgrade " + skillName + " (You have " +
this.skillPoints + ", you need " + cost + ")");
}
return false;
}
this.skillPoints -= cost;
this.upgradeSkill(skill);
if (Engine.currentPage === Engine.Page.Bladeburner && DomElems.currentTab.toLowerCase() === "skills") {
this.createActionAndSkillsContent();
}
if (workerScript.shouldLog("upgradeSkill")) {
workerScript.log(skillName + " successfully upgraded to level " + this.skills[skillName]);
}
return true;
}
Bladeburner.prototype.getTeamSizeNetscriptFn = function(type, name, workerScript) {
if (type === "" && name === "") {
return this.teamSize;
}
var errorLogText = "ERROR: Bladeburner.getTeamSize() failed due to an invalid action specified. " +
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
"name of the operation is case-sensitive.";
var actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
workerScript.log(errorLogText);
return -1;
}
var actionObj = this.getActionObject(actionId);
if (actionObj == null) {
workerScript.log(errorLogText);
return -1;
}
if (actionId.type === ActionTypes["Operation"] ||
actionId.type === ActionTypes["BlackOp"] ||
actionId.type === ActionTypes["BlackOperation"]) {
return actionObj.teamCount;
} else {
return 0;
}
}
Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, workerScript) {
var errorLogText = "ERROR: Bladeburner.setTeamSize() failed due to an invalid action specified. " +
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
"name of the operation is case-sensitive.";
var actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
workerScript.log(errorLogText);
return -1;
}
if (actionId.type !== ActionTypes["Operation"] ||
actionId.type !== ActionTypes["BlackOp"] ||
actionId.type !== ActionTypes["BlackOperation"]) {
workerScript.log("ERROR: Bladeburner.setTeamSize() failed. This function " +
"only works for Operations and BlackOps");
return -1;
}
var actionObj = this.getActionObject(actionId);
if (actionObj == null) {
workerScript.log(errorLogText);
return -1;
}
var sanitizedSize = Math.round(size);
if (isNaN(sanitizedSize)) {
workerScript.log("ERROR: Bladeburner.setTeamSize() failed due to an invalid 'size' argument: " + size);
return -1;
}
if (this.teamSize < sanitizedSize) {sanitizedSize = this.teamSize;}
actionObj.teamCount = sanitizedSize;
if (workerScript.shouldLog("setTeamSize")) {
workerScript.log("Team size for " + name + " set to " + sanitizedSize);
}
return sanitizedSize;
}
Bladeburner.prototype.getCityEstimatedPopulationNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: Bladeburner.getCityEstimatedPopulation() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return -1;
}
return this.cities[cityName].popEst;
}
Bladeburner.prototype.getCityEstimatedCommunitiesNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: Bladeburner.getCityEstimatedCommunities() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return -1;
}
return this.cities[cityName].commsEst;
}
Bladeburner.prototype.getCityChaosNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: Bladeburner.getCityChaos() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return -1;
}
return this.cities[cityName].chaos;
}
Bladeburner.prototype.switchCityNetscriptFn = function(cityName, workerScript) {
if (!this.cities.hasOwnProperty(cityName)) {
workerScript.log("ERROR: Bladeburner.switchCity() failed because the specified " +
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
return false;
}
this.city = cityName;
return true;
}
Bladeburner.prototype.joinBladeburnerFactionNetscriptFn = function(workerScript) {
var bladeburnerFac = Factions["Bladeburners"];
if (bladeburnerFac.isMember) {
return true;
} else if (this.rank >= RankNeededForFaction) {
joinFaction(bladeburnerFac);
if (workerScript.shouldLog("joinBladeburnerFaction")) {
workerScript.log("Joined Bladeburners Faction");
}
if (Engine.currentPage === Engine.Page.Bladeburner) {
removeChildrenFromElement(DomElems.overviewDiv);
this.createOverviewContent();
}
return true;
} else {
if (workerScript.shouldLog("joinBladeburnerFaction")) {
workerScript.log("Failed to join Bladeburners Faction because " +
"you do not have the required " + RankNeededForFaction + " rank");
}
return false;
}
}
Bladeburner.prototype.toJSON = function() { Bladeburner.prototype.toJSON = function() {
return Generic_toJSON("Bladeburner", this); return Generic_toJSON("Bladeburner", this);
@ -3185,7 +3629,7 @@ function initBladeburner() {
Skills[SkillNames.Overclock] = new Skill({ Skills[SkillNames.Overclock] = new Skill({
name:SkillNames.Overclock, name:SkillNames.Overclock,
desc:"Each level of this skill decreases the time it takes " + desc:"Each level of this skill decreases the time it takes " +
"to attempt a contract or operation by 1% (Max Level: 99)", "to attempt a contract or operation by 1% (Max Level: 95)",
baseCost:5, costInc:1, maxLvl:95, baseCost:5, costInc:1, maxLvl:95,
actionTime:1 actionTime:1
}); });
@ -3271,7 +3715,7 @@ function initBladeburner() {
"Zenyatta and RedWater by any means necessary. After the task " + "Zenyatta and RedWater by any means necessary. After the task " +
"is completed, the actions must be covered up from the general public.", "is completed, the actions must be covered up from the general public.",
baseDifficulty:2000, reqdRank:2.5e3, baseDifficulty:2000, reqdRank:2.5e3,
rankGain:25, rankLoss:10, hpLoss:100, rankGain:50, rankLoss:10, hpLoss:100,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3288,7 +3732,7 @@ function initBladeburner() {
"fabricated as a last resort. Be warned that AeroCorp has some of " + "fabricated as a last resort. Be warned that AeroCorp has some of " +
"the most advanced security measures in the world.", "the most advanced security measures in the world.",
baseDifficulty:2500, reqdRank:5e3, baseDifficulty:2500, reqdRank:5e3,
rankGain:30, rankLoss:15, hpLoss:50, rankGain:60, rankLoss:15, hpLoss:50,
weights:{hack:0.2,str:0.15,def:0.15,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.2,str:0.15,def:0.15,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true isStealth:true
@ -3307,7 +3751,7 @@ function initBladeburner() {
"investigate the sewer systems, and eliminate Samizdat. They must " + "investigate the sewer systems, and eliminate Samizdat. They must " +
"never publish anything again.", "never publish anything again.",
baseDifficulty:3000, reqdRank:7.5e3, baseDifficulty:3000, reqdRank:7.5e3,
rankGain:30, rankLoss:15, hpLoss:100, rankGain:75, rankLoss:15, hpLoss:100,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3325,7 +3769,7 @@ function initBladeburner() {
"also to destroy any information or research at the facility that " + "also to destroy any information or research at the facility that " +
"is relevant to the Synthoids and their goals.", "is relevant to the Synthoids and their goals.",
baseDifficulty:4000, reqdRank:10e3, baseDifficulty:4000, reqdRank:10e3,
rankGain:40, rankLoss:20, hpLoss:100, rankGain:100, rankLoss:20, hpLoss:100,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3339,7 +3783,7 @@ function initBladeburner() {
"that this deal does not happen.<br><br>" + "that this deal does not happen.<br><br>" +
"Your task is to intercept the deal. Leave no survivors.", "Your task is to intercept the deal. Leave no survivors.",
baseDifficulty:5000, reqdRank:12.5e3, baseDifficulty:5000, reqdRank:12.5e3,
rankGain:40, rankLoss:20, hpLoss:200, rankGain:125, rankLoss:20, hpLoss:200,
weights:{hack:0,str:0.25,def:0.25,dex:0.25,agi:0.25,cha:0, int:0}, weights:{hack:0,str:0.25,def:0.25,dex:0.25,agi:0.25,cha:0, int:0},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3354,7 +3798,7 @@ function initBladeburner() {
"the Red Rabbit brothel. Try to limit the number of other casualties, " + "the Red Rabbit brothel. Try to limit the number of other casualties, " +
"but do what you must to complete the mission.", "but do what you must to complete the mission.",
baseDifficulty:7500, reqdRank:15e3, baseDifficulty:7500, reqdRank:15e3,
rankGain:50, rankLoss:20, hpLoss:25, rankGain:200, rankLoss:20, hpLoss:25,
weights:{hack:0,str:0.2,def:0.2,dex:0.3,agi:0.3,cha:0, int:0}, weights:{hack:0,str:0.2,def:0.2,dex:0.3,agi:0.3,cha:0, int:0},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true, isKill:true,
@ -3371,7 +3815,7 @@ function initBladeburner() {
"have thus enlisted our help.<br><br>" + "have thus enlisted our help.<br><br>" +
"Your mission is to eradicate Juggernaut and his followers.", "Your mission is to eradicate Juggernaut and his followers.",
baseDifficulty:10e3, reqdRank:20e3, baseDifficulty:10e3, reqdRank:20e3,
rankGain:75, rankLoss:40, hpLoss:300, rankGain:300, rankLoss:40, hpLoss:300,
weights:{hack:0,str:0.25,def:0.25,dex:0.25,agi:0.25,cha:0, int:0}, weights:{hack:0,str:0.25,def:0.25,dex:0.25,agi:0.25,cha:0, int:0},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true, isKill:true,
@ -3387,7 +3831,7 @@ function initBladeburner() {
"in Los Angeles. Intelligence tells us that their base houses " + "in Los Angeles. Intelligence tells us that their base houses " +
"one of their Synthoid manufacturing units.", "one of their Synthoid manufacturing units.",
baseDifficulty:12.5e3, reqdRank:25e3, baseDifficulty:12.5e3, reqdRank:25e3,
rankGain:100, rankLoss:50, hpLoss:500, rankGain:500, rankLoss:50, hpLoss:500,
weights:{hack:0.05,str:0.2,def:0.2,dex:0.25,agi:0.25,cha:0, int:0.05}, weights:{hack:0.05,str:0.2,def:0.2,dex:0.25,agi:0.25,cha:0, int:0.05},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true, isKill:true,
@ -3407,7 +3851,7 @@ function initBladeburner() {
"operation. Your goal is to destroy this technology and eliminate" + "operation. Your goal is to destroy this technology and eliminate" +
"anyone who was involved in its creation.", "anyone who was involved in its creation.",
baseDifficulty:15e3, reqdRank:30e3, baseDifficulty:15e3, reqdRank:30e3,
rankGain:120, rankLoss:60, hpLoss:1000, rankGain:750, rankLoss:60, hpLoss:1000,
weights:{hack:0.05,str:0.2,def:0.2,dex:0.25,agi:0.25,cha:0, int:0.05}, weights:{hack:0.05,str:0.2,def:0.2,dex:0.25,agi:0.25,cha:0, int:0.05},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3422,7 +3866,7 @@ function initBladeburner() {
"The goal of Operation Deckard is to hunt down these Synthoids and retire " + "The goal of Operation Deckard is to hunt down these Synthoids and retire " +
"them. I don't need to tell you how critical this mission is.", "them. I don't need to tell you how critical this mission is.",
baseDifficulty:20e3, reqdRank:40e3, baseDifficulty:20e3, reqdRank:40e3,
rankGain:150, rankLoss:75, hpLoss:200, rankGain:1e3, rankLoss:75, hpLoss:200,
weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04}, weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true, isKill:true,
@ -3438,7 +3882,7 @@ function initBladeburner() {
"with Augmentations. Your task is to hunt down the associated Dark Army " + "with Augmentations. Your task is to hunt down the associated Dark Army " +
"members and eliminate them.", "members and eliminate them.",
baseDifficulty:25e3, reqdRank:50e3, baseDifficulty:25e3, reqdRank:50e3,
rankGain:200, rankLoss:100, hpLoss:500, rankGain:1.5e3, rankLoss:100, hpLoss:500,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true, isKill:true,
@ -3457,7 +3901,7 @@ function initBladeburner() {
"The goal of Operation Wallace is to destroy the Dark Army and " + "The goal of Operation Wallace is to destroy the Dark Army and " +
"Syndicate factions in Aevum immediately. Leave no survivors.", "Syndicate factions in Aevum immediately. Leave no survivors.",
baseDifficulty:30e3, reqdRank:75e3, baseDifficulty:30e3, reqdRank:75e3,
rankGain:500, rankLoss:150, hpLoss:1500, rankGain:2e3, rankLoss:150, hpLoss:1500,
weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04}, weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3473,7 +3917,7 @@ function initBladeburner() {
"successfully return. In the event of failure, all of the operation's " + "successfully return. In the event of failure, all of the operation's " +
"team members must not let themselves be captured alive.", "team members must not let themselves be captured alive.",
baseDifficulty:35e3, reqdRank:100e3, baseDifficulty:35e3, reqdRank:100e3,
rankGain:1e3, rankLoss:500, hpLoss:1500, rankGain:2.5e3, rankLoss:500, hpLoss:1500,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true isStealth:true
@ -3495,7 +3939,7 @@ function initBladeburner() {
"Infiltrate the compound, delete and destroy the work, and then find and kill the " + "Infiltrate the compound, delete and destroy the work, and then find and kill the " +
"project lead.", "project lead.",
baseDifficulty:40e3, reqdRank:125e3, baseDifficulty:40e3, reqdRank:125e3,
rankGain:2e3, rankLoss:1e3, hpLoss:500, rankGain:3e3, rankLoss:1e3, hpLoss:500,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1}, weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true
@ -3512,7 +3956,7 @@ function initBladeburner() {
"The mission is to destroy this broadcast tower. Speed and " + "The mission is to destroy this broadcast tower. Speed and " +
"stealth are of the upmost important for this.", "stealth are of the upmost important for this.",
baseDifficulty:45e3, reqdRank:150e3, baseDifficulty:45e3, reqdRank:150e3,
rankGain:5e3, rankLoss:1e3, hpLoss:100, rankGain:4e3, rankLoss:1e3, hpLoss:100,
weights:{hack:0.05,str:0.15,def:0.15,dex:0.3,agi:0.3,cha:0, int:0.05}, weights:{hack:0.05,str:0.15,def:0.15,dex:0.3,agi:0.3,cha:0, int:0.05},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true isStealth:true
@ -3541,7 +3985,7 @@ function initBladeburner() {
"'The Covenant'. We have no prior intelligence about this " + "'The Covenant'. We have no prior intelligence about this " +
"organization, so you are going in blind.", "organization, so you are going in blind.",
baseDifficulty:55e3, reqdRank:200e3, baseDifficulty:55e3, reqdRank:200e3,
rankGain:5e3, rankLoss:1e3, hpLoss:10e3, rankGain:7.5e3, rankLoss:1e3, hpLoss:10e3,
weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04}, weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75}, decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true isKill:true

@ -13,7 +13,7 @@ import {getRandomInt, removeElementById,
clearSelector} from "../utils/HelperFunctions.js"; clearSelector} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber, isString, generateRandomString} from "../utils/StringHelperFunctions.js"; import {formatNumber, isString, generateRandomString} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate, import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton, yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -231,7 +231,8 @@ let MaterialSizes = {
Chemicals: 0.05, Chemicals: 0.05,
Drugs: 0.02, Drugs: 0.02,
Robots: 0.5, Robots: 0.5,
"AICores": 0.1 AICores: 0.1,
RealEstate: 0,
} }
function Product(params={}) { function Product(params={}) {
@ -2334,10 +2335,10 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
//If Market Research upgrades are unlocked, add competition and demand info //If Market Research upgrades are unlocked, add competition and demand info
var cmpAndDmdText = ""; var cmpAndDmdText = "";
if (company.unlockUpgrades[2] === 1) { if (company.unlockUpgrades[2] === 1) {
cmpAndDmdText += "<br>Competition: " + formatNumber(mat.cmp, 3); cmpAndDmdText += "<br>Demand: " + formatNumber(mat.dmd, 3);
} }
if (company.unlockUpgrades[3] === 1) { if (company.unlockUpgrades[3] === 1) {
cmpAndDmdText += "<br>Demand: " + formatNumber(mat.dmd, 3); cmpAndDmdText += "<br>Competition: " + formatNumber(mat.cmp, 3);
} }
var innerTxt = "<p class='tooltip'>" + mat.name + ": " + formatNumber(mat.qty, 3) + var innerTxt = "<p class='tooltip'>" + mat.name + ": " + formatNumber(mat.qty, 3) +
"(" + formatNumber(totalGain, 3) + "/s)" + "(" + formatNumber(totalGain, 3) + "/s)" +
@ -2430,8 +2431,9 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
}); });
//Select industry and city to export to //Select industry and city to export to
var citySelector = createElement("select"); var citySelector = createElement("select", {class: "dropdown"});
var industrySelector = createElement("select", { var industrySelector = createElement("select", {
class: "dropdown",
changeListener:()=>{ changeListener:()=>{
var industryName = industrySelector.options[industrySelector.selectedIndex].value; var industryName = industrySelector.options[industrySelector.selectedIndex].value;
for (var foo = 0; foo < company.divisions.length; ++foo) { for (var foo = 0; foo < company.divisions.length; ++foo) {
@ -2474,6 +2476,7 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
//Select amount to export //Select amount to export
var exportAmount = createElement("input", { var exportAmount = createElement("input", {
class: "text-input",
placeholder:"Export amount / s" placeholder:"Export amount / s"
}); });
@ -2695,11 +2698,12 @@ Warehouse.prototype.createProductUI = function(product, parentRefs) {
//Completed products //Completed products
var cmpAndDmdText = ""; var cmpAndDmdText = "";
if (company.unlockUpgrades[2] === 1) { if (company.unlockUpgrades[2] === 1) {
cmpAndDmdText += "<br>Competition: " + formatNumber(product.cmp, 3);
}
if (company.unlockUpgrades[3] === 1) {
cmpAndDmdText += "<br>Demand: " + formatNumber(product.dmd, 3); cmpAndDmdText += "<br>Demand: " + formatNumber(product.dmd, 3);
} }
if (company.unlockUpgrades[3] === 1) {
cmpAndDmdText += "<br>Competition: " + formatNumber(product.cmp, 3);
}
var totalGain = product.data[city][1] - product.data[city][2]; //Production - sale var totalGain = product.data[city][1] - product.data[city][2]; //Production - sale
div.appendChild(createElement("p", { div.appendChild(createElement("p", {
innerHTML: "<p class='tooltip'>" + product.name + ": " + formatNumber(product.data[city][0], 3) + //Quantity innerHTML: "<p class='tooltip'>" + product.name + ": " + formatNumber(product.data[city][0], 3) + //Quantity
@ -3421,15 +3425,14 @@ Corporation.prototype.updateUIHeaderTabs = function() {
innerHTML: "Create a new division to expand into a new industry:", innerHTML: "Create a new division to expand into a new industry:",
}); });
var selector = createElement("select", { var selector = createElement("select", {
class:"cmpy-mgmt-industry-select" class:"dropdown"
}); });
var industryDescription = createElement("p", {}); var industryDescription = createElement("p", {});
var yesBtn; var yesBtn;
var nameInput = createElement("input", { var nameInput = createElement("input", {
type:"text", type:"text",
id:"cmpy-mgmt-expand-industry-name-input", id:"cmpy-mgmt-expand-industry-name-input",
color:"white", class: "text-input",
backgroundColor:"black",
display:"block", display:"block",
maxLength: 30, maxLength: 30,
pattern:"[a-zA-Z0-9-_]", pattern:"[a-zA-Z0-9-_]",
@ -4067,7 +4070,7 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
innerText: "Would you like to expand into a new city by opening an office? " + innerText: "Would you like to expand into a new city by opening an office? " +
"This would cost " + numeral(OfficeInitialCost).format('$0.000a'), "This would cost " + numeral(OfficeInitialCost).format('$0.000a'),
}); });
var citySelector = createElement("select", {margin:"5px"}); var citySelector = createElement("select", {class: "dropdown", margin:"5px"});
for (var cityName in division.offices) { for (var cityName in division.offices) {
if (division.offices.hasOwnProperty(cityName)) { if (division.offices.hasOwnProperty(cityName)) {
if (!(division.offices[cityName] instanceof OfficeSpace)) { if (!(division.offices[cityName] instanceof OfficeSpace)) {

@ -1,5 +1,5 @@
let CONSTANTS = { let CONSTANTS = {
Version: "0.37.1", Version: "0.38.1",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience //Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -14,6 +14,8 @@ let CONSTANTS = {
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
BaseCostFor1GBOfRamHacknetNode: 30000, BaseCostFor1GBOfRamHacknetNode: 30000,
TravelCost: 200000,
BaseCostForHacknetNode: 1000, BaseCostForHacknetNode: 1000,
BaseCostForHacknetNodeCore: 500000, BaseCostForHacknetNodeCore: 500000,
@ -41,6 +43,7 @@ let CONSTANTS = {
/* Netscript Constants */ /* Netscript Constants */
//RAM Costs for different commands //RAM Costs for different commands
ScriptBaseRamCost: 1.4, ScriptBaseRamCost: 1.4,
ScriptDomRamCost: 100,
ScriptWhileRamCost: 0.2, ScriptWhileRamCost: 0.2,
ScriptForRamCost: 0.2, ScriptForRamCost: 0.2,
ScriptIfRamCost: 0.15, ScriptIfRamCost: 0.15,
@ -79,6 +82,8 @@ let CONSTANTS = {
ScriptSingularityFn2RamCost: 2, ScriptSingularityFn2RamCost: 2,
ScriptSingularityFn3RamCost: 3, ScriptSingularityFn3RamCost: 3,
ScriptBladeburnerApiBaseRamCost: 4,
MultithreadingRAMCost: 1, MultithreadingRAMCost: 1,
NumNetscriptPorts: 20, NumNetscriptPorts: 20,
@ -484,16 +489,19 @@ let CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>", "World Stock Exchange account and TIX API Access<br>",
LatestUpdate: LatestUpdate:
"v0.37.1<br>" + "v0.38.1<br>" +
"* You now earn money from successfully completing Bladeburner contracts. The amount you earn is based " + "* Bug Fix: Using 'Object.prototype' functions like toLocaleString() or toString() should no longer cause errors in NetscriptJS<br>" +
"on the difficulty of the contract.<br>" + "* Implemented by Github user hydroflame:<br>" +
"* Completing Field Analysis in Bladeburner now grants 0.1 rank<br>" + "*** Accessing the 'window' and 'document' objects in Netscript JS now requires a large amount of RAM (100 GB)<br>" +
"* The maximum RAM you can get on a purchased server is now 1,048,576GB (2^20)<br>" + "*** Added game option to suppress travel confirmation<br>" +
"* Bug Fix: Fixed Netscript syntax highlighting issues with the new NetscriptJS<br>" + "*** Text on buttons can no longer be highlighted<br>" +
"* Bug Fix: Netscript Functions now properly incur RAM costs in NetscriptJS<br>" + "*** Bug Fix: Fixed an issue that caused NaN values when exporting Real Estate in Corporations<br>" +
"* Bug Fix: deleteServer() now fails if its called on the server you are currently connected to<br>" + "*** Bug Fix: Competition and Demand displays in Corporation are now correct (were reversed before)<br>" +
"* Removed in-game Netscript documentation, since it was outdated and difficult to maintain.<br>" + "*** Added ps() Netscript function<br>" +
"* Bug Fix: Updated the gymWorkout() Singularity function with the new exp/cost values for gyms<br>" "*** Bug Fix: grow() should no longer return/log a negative value when it runs on a server that's already at max money<br>" +
"*** Bug Fix: serverExists() Netscript function should now properly return false for non-existent hostname/ips<br>" +
"*** Bug Fix: Sever's security level should now properly increase when its money is grown to max value"
} }
export {CONSTANTS}; export {CONSTANTS};

@ -2,146 +2,235 @@ import {CONSTANTS} from "./Constants.js";
import {Player} from "./Player.js"; import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js"; import {dialogBoxCreate} from "../utils/DialogBox.js";
/* Crimes.js */
function commitShopliftCrime(div=1, singParams=null) { function Crime(name, type, time, money, difficulty, karma, params) {
if (div <= 0) {div = 1;} this.name = name;
Player.crimeType = CONSTANTS.CrimeShoplift; this.type = type;
var time = 2000; this.time = time;
Player.startCrime(0, 0, 0, 2/div, 2/div, 0, 15000/div, time, singParams); //$7500/s, 1 exp/s this.money = money;
return time; this.difficulty = difficulty;
this.karma = karma;
this.hacking_success_weight = params.hacking_success_weight ? params.hacking_success_weight : 0;
this.strength_success_weight = params.strength_success_weight ? params.strength_success_weight : 0;
this.defense_success_weight = params.defense_success_weight ? params.defense_success_weight : 0;
this.dexterity_success_weight = params.dexterity_success_weight ? params.dexterity_success_weight : 0;
this.agility_success_weight = params.agility_success_weight ? params.agility_success_weight : 0;
this.charisma_success_weight = params.charisma_success_weight ? params.charisma_success_weight : 0;
this.hacking_exp = params.hacking_exp ? params.hacking_exp : 0;
this.strength_exp = params.strength_exp ? params.strength_exp : 0;
this.defense_exp = params.defense_exp ? params.defense_exp : 0;
this.dexterity_exp = params.dexterity_exp ? params.dexterity_exp : 0;
this.agility_exp = params.agility_exp ? params.agility_exp : 0;
this.charisma_exp = params.charisma_exp ? params.charisma_exp : 0;
this.intelligence_exp = params.intelligence_exp ? params.intelligence_exp : 0;
this.kills = params.kills ? params.kills : 0;
} }
function commitRobStoreCrime(div=1, singParams=null) { Crime.prototype.commit = function(div=1, singParams=null) {
if (div <= 0) {div = 1;} if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeRobStore; Player.crimeType = this.type;
var time = 60000; Player.startCrime(
Player.startCrime(30/div, 0, 0, 45/div, 45/div, 0, 400000/div, time, singParams); //$6666,6/2, 0.5exp/s, 0.75exp/s this.hacking_exp/div,
return time; this.strength_exp/div,
this.defense_exp/div,
this.dexterity_exp/div,
this.agility_exp/div,
this.charisma_exp/div,
this.money/div, this.time, singParams);
return this.time;
} }
function commitMugCrime(div=1, singParams=null) { Crime.prototype.successRate = function() {
if (div <= 0) {div = 1;} var chance = (this.hacking_success_weight * Player.hacking_skill +
Player.crimeType = CONSTANTS.CrimeMug; this.strength_success_weight * Player.strength +
var time = 4000; this.defense_success_weight * Player.defense +
Player.startCrime(0, 3/div, 3/div, 3/div, 3/div, 0, 36000/div, time, singParams); //$9000/s, .66 exp/s this.dexterity_success_weight * Player.dexterity +
return time; this.agility_success_weight * Player.agility +
this.charisma_success_weight * Player.charisma +
CONSTANTS.IntelligenceCrimeWeight * Player.intelligence);
chance /= CONSTANTS.MaxSkillLevel;
chance /= this.difficulty;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
} }
function commitLarcenyCrime(div=1, singParams=null) { const Crimes = {
if (div <= 0) {div = 1;} Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1/20, 0.1, {
Player.crimeType = CONSTANTS.CrimeLarceny; dexterity_success_weight: 1,
var time = 90000; agility_success_weight: 1,
Player.startCrime(45/div, 0, 0, 60/div, 60/div, 0, 800000/div, time, singParams) // $8888.88/s, .5 exp/s, .66 exp/s
return time;
}
function commitDealDrugsCrime(div=1, singParams=null) { dexterity_exp: 2,
if (div <= 0) {div = 1;} agility_exp: 2,
Player.crimeType = CONSTANTS.CrimeDrugs; }),
var time = 10000;
Player.startCrime(0, 0, 0, 5/div, 5/div, 10/div, 120000/div, time, singParams); //$12000/s, .5 exp/s, 1 exp/s
return time;
}
function commitBondForgeryCrime(div=1, singParams=null) { RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1/5, 0.5, {
if (div <= 0) {div = 1;} hacking_exp: 30,
Player.crimeType = CONSTANTS.CrimeBondForgery; dexterity_exp: 45,
var time = 300000; agility_exp: 45,
Player.startCrime(100/div, 0, 0, 150/div, 0, 15/div, 4500000/div, time, singParams); //$15000/s, 0.33 hack exp/s, .5 dex exp/s, .05 cha exp
return time;
}
function commitTraffickArmsCrime(div=1, singParams=null) { hacking_success_weight: 0.5 ,
if (div <= 0) {div = 1;} dexterity_success_weight: 2,
Player.crimeType = CONSTANTS.CrimeTraffickArms; agility_success_weight: 1,
var time = 40000;
Player.startCrime(0, 20/div, 20/div, 20/div, 20/div, 40/div, 600000/div, time, singParams); //$15000/s, .5 combat exp/s, 1 cha exp/s
return time;
}
function commitHomicideCrime(div=1, singParams=null) { intelligence_exp: 0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain,
if (div <= 0) {div = 1;} }),
Player.crimeType = CONSTANTS.CrimeHomicide;
var time = 3000;
Player.startCrime(0, 2/div, 2/div, 2/div, 2/div, 0, 45000/div, time, singParams); //$15000/s, 0.66 combat exp/s
return time;
}
function commitGrandTheftAutoCrime(div=1, singParams=null) { Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1/5, 0.25, {
if (div <= 0) {div = 1;} strength_exp: 3,
Player.crimeType = CONSTANTS.CrimeGrandTheftAuto; defense_exp: 3,
var time = 80000; dexterity_exp: 3,
Player.startCrime(0, 20/div, 20/div, 20/div, 80/div, 40/div, 1600000/div, time, singParams); //$20000/s, .25 exp/s, 1 exp/s, .5 exp/s agility_exp: 3,
return time;
}
function commitKidnapCrime(div=1, singParams=null) { strength_success_weight: 1.5,
if (div <= 0) {div = 1;} defense_success_weight: 0.5,
Player.crimeType = CONSTANTS.CrimeKidnap; dexterity_success_weight: 1.5,
var time = 120000; agility_success_weight: 0.5,
Player.startCrime(0, 80/div, 80/div, 80/div, 80/div, 80/div, 3600000/div, time, singParams); //$30000/s. .66 exp/s }),
return time;
}
function commitAssassinationCrime(div=1, singParams=null) { Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1/3, 1.5, {
if (div <= 0) {div = 1;} hacking_exp: 45,
Player.crimeType = CONSTANTS.CrimeAssassination; dexterity_exp: 60,
var time = 300000; agility_exp: 60,
Player.startCrime(0, 300/div, 300/div, 300/div, 300/div, 0, 12000000/div, time, singParams); //$40000/s, 1 exp/s
return time;
}
function commitHeistCrime(div=1, singParams=null) { hacking_skill_success_weight: 0.5,
if (div <= 0) {div = 1;} dexterity_success_weight: 1,
Player.crimeType = CONSTANTS.CrimeHeist; agility_success_weight: 1,
var time = 600000;
Player.startCrime(450/div, 450/div, 450/div, 450/div, 450/div, 450/div, 120000000/div, time, singParams); //$200000/s, .75exp/s
return time;
}
function determineCrimeSuccess(crime, moneyGained) { intelligence_exp: 0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
dexterity_exp: 5,
agility_exp: 5,
charisma_exp: 10,
charisma_success_weight: 3,
dexterity_success_weight: 2,
agility_success_weight: 1,
}),
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1/2, 0.1, {
hacking_exp: 100,
dexterity_exp: 150,
charisma_exp: 15,
hacking_skill_success_weight: 0.05,
dexterity_success_weight: 1.25,
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
agility_exp: 20,
charisma_exp: 40,
charisma_success_weight: 1,
strength_success_weight: 1,
defense_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
}),
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
strength_exp: 2,
defense_exp: 2,
dexterity_exp: 2,
agility_exp: 2,
strength_success_weight: 2,
defense_success_weight: 2,
dexterity_success_weight: 0.5,
agility_success_weight: 0.5,
kills: 1,
}),
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
strength_exp: 20,
defense_exp: 20,
dexterity_exp: 20,
agility_exp: 80,
charisma_exp: 40,
hacking_skill_success_weight: 1,
strength_success_weight: 1,
dexterity_success_weight: 4,
agility_success_weight: 2,
charisma_success_weight: 2,
intelligence_exp: CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
strength_exp: 80,
defense_exp: 80,
dexterity_exp: 80,
agility_exp: 80,
charisma_exp: 80,
charisma_success_weight: 1,
strength_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
strength_exp: 300,
defense_exp: 300,
dexterity_exp: 300,
agility_exp: 300,
strength_success_weight: 1,
dexterity_success_weight: 2,
agility_success_weight: 1,
intelligence_exp: 5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
kills: 1,
}),
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
hacking_exp: 450,
strength_exp: 450,
defense_exp: 450,
dexterity_exp: 450,
agility_exp: 450,
charisma_exp: 450,
hacking_skill_success_weight: 1,
strength_success_weight: 1,
defense_success_weight: 1,
dexterity_success_weight: 1,
agility_success_weight: 1,
charisma_success_weight: 1,
intelligence_exp: 10 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
};
function determineCrimeSuccess(type, moneyGained) {
var chance = 0; var chance = 0;
switch (crime) { var found = false;
case CONSTANTS.CrimeShoplift: for(const i in Crimes) {
chance = determineCrimeChanceShoplift(); const crime = Crimes[i];
break; if(crime.type == type) {
case CONSTANTS.CrimeRobStore: chance = crime.successRate();
chance = determineCrimeChanceRobStore(); found = true;
break; break;
case CONSTANTS.CrimeMug: }
chance = determineCrimeChanceMug(); }
break; if(!found) {
case CONSTANTS.CrimeLarceny: console.log(crime);
chance = determineCrimeChanceLarceny(); dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
break; return;
case CONSTANTS.CrimeDrugs:
chance = determineCrimeChanceDealDrugs();
break;
case CONSTANTS.CrimeBondForgery:
chance = determineCrimeChanceBondForgery();
break;
case CONSTANTS.CrimeTraffickArms:
chance = determineCrimeChanceTraffickArms();
break;
case CONSTANTS.CrimeHomicide:
chance = determineCrimeChanceHomicide();
break;
case CONSTANTS.CrimeGrandTheftAuto:
chance = determineCrimeChanceGrandTheftAuto();
break;
case CONSTANTS.CrimeKidnap:
chance = determineCrimeChanceKidnap();
break;
case CONSTANTS.CrimeAssassination:
chance = determineCrimeChanceAssassination();
break;
case CONSTANTS.CrimeHeist:
chance = determineCrimeChanceHeist();
break;
default:
console.log(crime);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
return;
} }
if (Math.random() <= chance) { if (Math.random() <= chance) {
@ -154,134 +243,33 @@ function determineCrimeSuccess(crime, moneyGained) {
} }
} }
let intWgt = CONSTANTS.IntelligenceCrimeWeight; function findCrime(roughName) {
let maxLvl = CONSTANTS.MaxSkillLevel; if (roughName.includes("shoplift")) {
return Crimes.Shoplift;
function determineCrimeChanceShoplift() { } else if (roughName.includes("rob") && roughName.includes("store")) {
var chance = (Player.dexterity / maxLvl + return Crimes.RobStore;
Player.agility / maxLvl + } else if (roughName.includes("mug")) {
intWgt * Player.intelligence / maxLvl) * 20; return Crimes.Mug;
chance *= Player.crime_success_mult; } else if (roughName.includes("larceny")) {
return Math.min(chance, 1); return Crimes.Larceny;
} else if (roughName.includes("drugs")) {
return Crimes.DealDrugs;
} else if (roughName.includes("bond") && roughName.includes("forge")) {
return Crimes.BondForgery;
} else if (roughName.includes("traffick") && roughName.includes("arms")) {
return Crimes.TraffickArms;
} else if (roughName.includes("homicide")) {
return Crimes.Homicide;
} else if (roughName.includes("grand") && roughName.includes("auto")) {
return Crimes.GrandTheftAuto;
} else if (roughName.includes("kidnap")) {
return Crimes.Kidnap;
} else if (roughName.includes("assassinate")) {
return Crimes.Assassination;
} else if (roughName.includes("heist")) {
return Crimes.Heist;
}
return null;
} }
function determineCrimeChanceRobStore() { export {determineCrimeSuccess,findCrime,Crimes};
var chance = (0.5 * Player.hacking_skill / maxLvl +
2 * Player.dexterity / maxLvl +
1 * Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 5;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceMug() {
var chance = (1.5 * Player.strength / maxLvl +
0.5 * Player.defense / maxLvl +
1.5 * Player.dexterity / maxLvl +
0.5 * Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 5;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceLarceny() {
var chance = (0.5 * Player.hacking_skill / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 3;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceDealDrugs() {
var chance = (3*Player.charisma / maxLvl +
2*Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl);
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceBondForgery() {
var chance = (0.1*Player.hacking_skill / maxLvl +
2.5*Player.dexterity / maxLvl +
2*intWgt*Player.intelligence / maxLvl);
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceTraffickArms() {
var chance = (Player.charisma / maxLvl +
Player.strength / maxLvl +
Player.defense / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) / 2;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceHomicide() {
var chance = (2 * Player.strength / maxLvl +
2 * Player.defense / maxLvl +
0.5 * Player.dexterity / maxLvl +
0.5 * Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl);
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceGrandTheftAuto() {
var chance = (Player.hacking_skill / maxLvl +
Player.strength / maxLvl +
4 * Player.dexterity / maxLvl +
2 * Player.agility / maxLvl +
2 * Player.charisma / maxLvl +
intWgt * Player.intelligence / maxLvl) / 8;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceKidnap() {
var chance = (Player.charisma / maxLvl +
Player.strength / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) / 5;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceAssassination() {
var chance = (Player.strength / maxLvl +
2 * Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) / 8;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceHeist() {
var chance = (Player.hacking_skill / maxLvl +
Player.strength / maxLvl +
Player.defense / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
Player.charisma / maxLvl +
intWgt * Player.intelligence / maxLvl) / 18;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
export {commitShopliftCrime, commitRobStoreCrime, commitMugCrime,
commitLarcenyCrime, commitDealDrugsCrime, commitBondForgeryCrime,
commitTraffickArmsCrime,
commitHomicideCrime, commitGrandTheftAutoCrime, commitKidnapCrime,
commitAssassinationCrime, commitHeistCrime, determineCrimeSuccess,
determineCrimeChanceShoplift, determineCrimeChanceRobStore,
determineCrimeChanceMug, determineCrimeChanceLarceny,
determineCrimeChanceDealDrugs, determineCrimeChanceBondForgery,
determineCrimeChanceTraffickArms,
determineCrimeChanceHomicide, determineCrimeChanceGrandTheftAuto,
determineCrimeChanceKidnap, determineCrimeChanceAssassination,
determineCrimeChanceHeist};

@ -19,7 +19,6 @@ function checkIfConnectedToDarkweb() {
"to purchase an item"); "to purchase an item");
} }
} }
} }
//Handler for dark web commands. The terminal's executeCommand() function will pass //Handler for dark web commands. The terminal's executeCommand() function will pass
@ -49,150 +48,68 @@ function executeDarkwebTerminalCommand(commandArray) {
} }
function listAllDarkwebItems() { function listAllDarkwebItems() {
for (var item in DarkWebItems) { for(const key in DarkWebItems) {
if (DarkWebItems.hasOwnProperty(item)) { const item = DarkWebItems[key];
var item = DarkWebItems[item]; post(item.toString());
//Convert string using toLocaleString
var split = item.split(" - ");
if (split.length == 3 && split[1].charAt(0) == '$') {
split[1] = split[1].slice(1);
split[1] = split[1].replace(/,/g, '');
var price = parseFloat(split[1]);
if (isNaN(price)) {
post(item);
return;
}
price = formatNumber(price, 0);
split[1] = "$" + price.toString();
post(split.join(" - "));
} else {
post(item);
}
}
}
var priceString = split[1];
//Check for errors
if (priceString.length == 0 || priceString.charAt(0) != '$') {
return -1;
} }
//Remove dollar sign and commas
priceString = priceString.slice(1);
priceString = priceString.replace(/,/g, '');
//Convert string to numeric
var price = parseFloat(priceString);
if (isNaN(price)) {return -1;}
else {return price;}
} }
function buyDarkwebItem(itemName) { function buyDarkwebItem(itemName) {
if (itemName.toLowerCase() == Programs.BruteSSHProgram.name.toLowerCase()) { itemName = itemName.toLowerCase();
var price = parseDarkwebItemPrice(DarkWebItems.BruteSSHProgram);
if (price > 0 && Player.money.gt(price)) { // find the program that matches, if any
Player.loseMoney(price); let item = null;
Player.getHomeComputer().programs.push(Programs.BruteSSHProgram.name); for(const key in DarkWebItems) {
post("You have purchased the BruteSSH.exe program. The new program " + const i = DarkWebItems[key];
"can be found on your home computer."); if(i.program.toLowerCase() == itemName) {
} else { item = i;
post("Not enough money to purchase " + itemName);
} }
} else if (itemName.toLowerCase() == Programs.FTPCrackProgram.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.FTPCrackProgram);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.FTPCrackProgram.name);
post("You have purchased the FTPCrack.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
}
} else if (itemName.toLowerCase() == Programs.RelaySMTPProgram.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.RelaySMTPProgram);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.RelaySMTPProgram.name);
post("You have purchased the relaySMTP.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
}
} else if (itemName.toLowerCase() == Programs.HTTPWormProgram.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.HTTPWormProgram);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.HTTPWormProgram.name);
post("You have purchased the HTTPWorm.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
}
} else if (itemName.toLowerCase() == Programs.SQLInjectProgram.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.SQLInjectProgram);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.SQLInjectProgram.name);
post("You have purchased the SQLInject.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
}
} else if (itemName.toLowerCase() == Programs.DeepscanV1.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.DeepScanV1Program);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.DeepscanV1.name);
post("You have purchased the DeepscanV1.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
}
} else if (itemName.toLowerCase() == Programs.DeepscanV2.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.DeepScanV2Program);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.DeepscanV2.name);
post("You have purchased the DeepscanV2.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
}
} else {
post("Unrecognized item");
} }
}
function parseDarkwebItemPrice(itemDesc) { // return if invalid
var split = itemDesc.split(" - "); if(item === null) {
if (split.length == 3) { post("Unrecognized item: "+itemName);
var priceString = split[1]; return;
//Check for errors
if (priceString.length == 0 || priceString.charAt(0) != '$') {
return -1;
}
//Remove dollar sign and commas
priceString = priceString.slice(1);
priceString = priceString.replace(/,/g, '');
//Convert string to numeric
var price = parseFloat(priceString);
if (isNaN(price)) {return -1;}
else {return price;}
} else {
return -1;
} }
// return if the player already has it.
if(Player.hasProgram(item.program)) {
post('You already have the '+item.program+' program');
return;
}
// return if the player doesn't have enough money
if(Player.money.lt(item.price)) {
post("Not enough money to purchase " + item.program);
return;
}
// buy and push
Player.loseMoney(item.price);
Player.getHomeComputer().programs.push(item.program);
post('You have purchased the '+item.program+' program. The new program can be found on your home computer.');
} }
let DarkWebItems = { function DarkWebItem(program, price, description) {
BruteSSHProgram: "BruteSSH.exe - $500,000 - Opens up SSH Ports", this.program = program;
FTPCrackProgram: "FTPCrack.exe - $1,500,000 - Opens up FTP Ports", this.price = price;
RelaySMTPProgram: "relaySMTP.exe - $5,000,000 - Opens up SMTP Ports", this.description = description;
HTTPWormProgram: "HTTPWorm.exe - $30,000,000 - Opens up HTTP Ports",
SQLInjectProgram: "SQLInject.exe - $250,000,000 - Opens up SQL Ports",
DeepScanV1Program: "DeepscanV1.exe - $500,000 - Enables 'scan-analyze' with a depth up to 5",
DeepScanV2Program: "DeepscanV2.exe - $25,000,000 - Enables 'scan-analyze' with a depth up to 10",
} }
export {checkIfConnectedToDarkweb, executeDarkwebTerminalCommand, // formats the item for the terminal (eg. "BruteSSH.exe - $500,000 - Opens up SSH Ports")
listAllDarkwebItems, buyDarkwebItem, parseDarkwebItemPrice, DarkWebItem.prototype.toString = function() {
DarkWebItems}; return [this.program, "$"+formatNumber(this.price), this.description].join(' - ');
}
const DarkWebItems = {
BruteSSHProgram: new DarkWebItem(Programs.BruteSSHProgram, 500000, "Opens up SSH Ports"),
FTPCrackProgram: new DarkWebItem(Programs.FTPCrackProgram, 1500000, "Opens up FTP Ports"),
RelaySMTPProgram: new DarkWebItem(Programs.RelaySMTPProgram, 5000000, "Opens up SMTP Ports"),
HTTPWormProgram: new DarkWebItem(Programs.HTTPWormProgram, 30000000, "Opens up HTTP Ports"),
SQLInjectProgram: new DarkWebItem(Programs.SQLInjectProgram, 250000000, "Opens up SQL Ports"),
DeepscanV1: new DarkWebItem(Programs.DeepscanV1, 500000, "Enables 'scan-analyze' with a depth up to 5"),
DeepscanV2: new DarkWebItem(Programs.DeepscanV2, 25000000, "Enables 'scan-analyze' with a depth up to 10"),
};
export {checkIfConnectedToDarkweb, executeDarkwebTerminalCommand, DarkWebItems};

@ -3,7 +3,7 @@ import {Augmentations, AugmentationNames,
import {BitNodeMultipliers} from "./BitNode.js"; import {BitNodeMultipliers} from "./BitNode.js";
import {CONSTANTS} from "./Constants.js"; import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js"; import {Engine} from "./engine.js";
import {FactionInfo} from "./FactionInfo.js"; import {FactionInfos} from "./FactionInfo.js";
import {Locations} from "./Location.js"; import {Locations} from "./Location.js";
import {HackingMission, setInMission} from "./Missions.js"; import {HackingMission, setInMission} from "./Missions.js";
import {Player} from "./Player.js"; import {Player} from "./Player.js";
@ -15,7 +15,7 @@ import {clearEventListeners, createElement,
removeChildrenFromElement} from "../utils/HelperFunctions.js"; removeChildrenFromElement} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoBoxGetYesButton, import {yesNoBoxCreate, yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js"; yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js";
@ -23,7 +23,6 @@ import {yesNoBoxCreate, yesNoBoxGetYesButton,
function Faction(name="") { function Faction(name="") {
this.name = name; this.name = name;
this.augmentations = []; //Name of augmentation only this.augmentations = []; //Name of augmentation only
this.info = ""; //Introductory/informational text about the faction
//Player-related properties for faction //Player-related properties for faction
this.isMember = false; //Whether player is member this.isMember = false; //Whether player is member
@ -31,22 +30,17 @@ function Faction(name="") {
this.playerReputation = 0; //"Reputation" within faction this.playerReputation = 0; //"Reputation" within faction
this.alreadyInvited = false; this.alreadyInvited = false;
//Multipliers for unlocking and purchasing augmentations
this.augmentationPriceMult = 1;
this.augmentationRepRequirementMult = 1;
//Faction favor //Faction favor
this.favor = 0; this.favor = 0;
this.rolloverRep = 0; this.rolloverRep = 0;
}; };
Faction.prototype.setAugmentationMultipliers = function(price, rep) { Faction.prototype.getInfo = function() {
this.augmentationPriceMult = price; const info = FactionInfos[this.name];
this.augmentationRepRequirementMult = rep; if(info == null) {
} throw new Error("Missing faction from FactionInfos: " + this.name+" this probably means the faction got corrupted somehow");
}
Faction.prototype.setInfo = function(inf) { return info;
this.info = inf;
} }
Faction.prototype.gainFavor = function() { Faction.prototype.gainFavor = function() {
@ -119,142 +113,9 @@ function factionExists(name) {
//TODO Augmentation price and rep requirement mult are 1 for everything right now, //TODO Augmentation price and rep requirement mult are 1 for everything right now,
// This might change in the future for balance // This might change in the future for balance
function initFactions() { function initFactions() {
//Endgame for(const name in FactionInfos) {
var Illuminati = new Faction("Illuminati"); resetFaction(new Faction(name));
Illuminati.setInfo(FactionInfo.IlluminatiInfo); }
resetFaction(Illuminati);
var Daedalus = new Faction("Daedalus");
Daedalus.setInfo(FactionInfo.DaedalusInfo);
resetFaction(Daedalus);
var Covenant = new Faction("The Covenant");
Covenant.setInfo(FactionInfo.CovenantInfo);
resetFaction(Covenant);
//Megacorporations, each forms its own faction
var ECorp = new Faction("ECorp");
ECorp.setInfo(FactionInfo.ECorpInfo);
resetFaction(ECorp);
var MegaCorp = new Faction("MegaCorp");
MegaCorp.setInfo(FactionInfo.MegaCorpInfo);
resetFaction(MegaCorp);
var BachmanAndAssociates = new Faction("Bachman & Associates");
BachmanAndAssociates.setInfo(FactionInfo.BachmanAndAssociatesInfo);
resetFaction(BachmanAndAssociates);
var BladeIndustries = new Faction("Blade Industries");
BladeIndustries.setInfo(FactionInfo.BladeIndustriesInfo);
resetFaction(BladeIndustries);
var NWO = new Faction("NWO");
NWO.setInfo(FactionInfo.NWOInfo);
resetFaction(NWO);
var ClarkeIncorporated = new Faction("Clarke Incorporated");
ClarkeIncorporated.setInfo(FactionInfo.ClarkeIncorporatedInfo);
resetFaction(ClarkeIncorporated);
var OmniTekIncorporated = new Faction("OmniTek Incorporated");
OmniTekIncorporated.setInfo(FactionInfo.OmniTekIncorporatedInfo);
resetFaction(OmniTekIncorporated);
var FourSigma = new Faction("Four Sigma");
FourSigma.setInfo(FactionInfo.FourSigmaInfo);
resetFaction(FourSigma);
var KuaiGongInternational = new Faction("KuaiGong International");
KuaiGongInternational.setInfo(FactionInfo.KuaiGongInternationalInfo);
resetFaction(KuaiGongInternational);
//Other corporations
var FulcrumTechnologies = new Faction("Fulcrum Secret Technologies");
FulcrumTechnologies.setInfo(FactionInfo.FulcrumSecretTechnologiesInfo);
resetFaction(FulcrumTechnologies);
//Hacker groups
var BitRunners = new Faction("BitRunners");
BitRunners.setInfo(FactionInfo.BitRunnersInfo);
resetFaction(BitRunners);
var BlackHand = new Faction("The Black Hand");
BlackHand.setInfo(FactionInfo.BlackHandInfo);
resetFaction(BlackHand);
var NiteSec = new Faction("NiteSec");
NiteSec.setInfo(FactionInfo.NiteSecInfo);
resetFaction(NiteSec);
//City factions, essentially governments
var Chongqing = new Faction("Chongqing");
Chongqing.setInfo(FactionInfo.ChongqingInfo);
resetFaction(Chongqing);
var Sector12 = new Faction("Sector-12");
Sector12.setInfo(FactionInfo.Sector12Info);
resetFaction(Sector12);
var NewTokyo = new Faction("New Tokyo");
NewTokyo.setInfo(FactionInfo.NewTokyoInfo);
resetFaction(NewTokyo);
var Aevum = new Faction("Aevum");
Aevum.setInfo(FactionInfo.AevumInfo);
resetFaction(Aevum);
var Ishima = new Faction("Ishima");
Ishima.setInfo(FactionInfo.Ishima);
resetFaction(Ishima);
var Volhaven = new Faction("Volhaven");
Volhaven.setInfo(FactionInfo.VolhavenInfo);
resetFaction(Volhaven);
//Criminal Organizations/Gangs
var SpeakersForTheDead = new Faction("Speakers for the Dead");
SpeakersForTheDead.setInfo(FactionInfo.SpeakersForTheDeadInfo);
resetFaction(SpeakersForTheDead);
var DarkArmy = new Faction("The Dark Army");
DarkArmy.setInfo(FactionInfo.DarkArmyInfo);
resetFaction(DarkArmy);
var TheSyndicate = new Faction("The Syndicate");
TheSyndicate.setInfo(FactionInfo.TheSyndicateInfo);
resetFaction(TheSyndicate);
var Silhouette = new Faction("Silhouette");
Silhouette.setInfo(FactionInfo.SilhouetteInfo);
resetFaction(Silhouette);
var Tetrads = new Faction("Tetrads"); //Low-medium level asian crime gang
Tetrads.setInfo(FactionInfo.TetradsInfo);
resetFaction(Tetrads);
var SlumSnakes = new Faction("Slum Snakes"); //Low level crime gang
SlumSnakes.setInfo(FactionInfo.SlumSnakesInfo);
resetFaction(SlumSnakes);
//Earlygame factions - factions the player will prestige with early on that don't
//belong in other categories
var Netburners = new Faction("Netburners");
Netburners.setInfo(FactionInfo.NetburnersInfo);
resetFaction(Netburners);
var TianDiHui = new Faction("Tian Di Hui"); //Society of the Heaven and Earth
TianDiHui.setInfo(FactionInfo.TianDiHuiInfo);
resetFaction(TianDiHui);
var CyberSec = new Faction("CyberSec");
CyberSec.setInfo(FactionInfo.CyberSecInfo);
resetFaction(CyberSec);
//Special Factions
var Bladeburners = new Faction("Bladeburners");
Bladeburners.setInfo(FactionInfo.BladeburnersInfo);
resetFaction(Bladeburners);
} }
//Resets a faction during (re-)initialization. Saves the favor in the new //Resets a faction during (re-)initialization. Saves the favor in the new
@ -287,36 +148,12 @@ function inviteToFaction(faction) {
function joinFaction(faction) { function joinFaction(faction) {
faction.isMember = true; faction.isMember = true;
Player.factions.push(faction.name); Player.factions.push(faction.name);
const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction //Determine what factions you are banned from now that you have joined this faction
if (faction.name == "Chongqing") { for(const i in factionInfo.enemies) {
Factions["Sector-12"].isBanned = true; const enemy = factionInfo.enemies[i];
Factions["Aevum"].isBanned = true; Factions[enemy].isBanned = true;
Factions["Volhaven"].isBanned = true;
} else if (faction.name == "Sector-12") {
Factions["Chongqing"].isBanned = true;
Factions["New Tokyo"].isBanned = true;
Factions["Ishima"].isBanned = true;
Factions["Volhaven"].isBanned = true;
} else if (faction.name == "New Tokyo") {
Factions["Sector-12"].isBanned = true;
Factions["Aevum"].isBanned = true;
Factions["Volhaven"].isBanned = true;
} else if (faction.name == "Aevum") {
Factions["Chongqing"].isBanned = true;
Factions["New Tokyo"].isBanned = true;
Factions["Ishima"].isBanned = true;
Factions["Volhaven"].isBanned = true;
} else if (faction.name == "Ishima") {
Factions["Sector-12"].isBanned = true;
Factions["Aevum"].isBanned = true;
Factions["Volhaven"].isBanned = true;
} else if (faction.name == "Volhaven") {
Factions["Chongqing"].isBanned = true;
Factions["Sector-12"].isBanned = true;
Factions["New Tokyo"].isBanned = true;
Factions["Aevum"].isBanned = true;
Factions["Ishima"].isBanned = true;
} }
} }
@ -326,6 +163,8 @@ function displayFactionContent(factionName) {
if (faction == null) { if (faction == null) {
throw new Error("Invalid factionName passed into displayFactionContent: " + factionName); throw new Error("Invalid factionName passed into displayFactionContent: " + factionName);
} }
var factionInfo = faction.getInfo();
removeChildrenFromElement(Engine.Display.factionContent); removeChildrenFromElement(Engine.Display.factionContent);
var elements = []; var elements = [];
@ -334,7 +173,7 @@ function displayFactionContent(factionName) {
innerText:factionName innerText:factionName
})); }));
elements.push(createElement("pre", { elements.push(createElement("pre", {
innerHTML:"<i>" + faction.info + "</i>" innerHTML:"<i>" + factionInfo.infoText + "</i>"
})); }));
elements.push(createElement("p", { elements.push(createElement("p", {
innerText:"---------------", innerText:"---------------",
@ -346,14 +185,14 @@ function displayFactionContent(factionName) {
favorGain = favorGain[0]; favorGain = favorGain[0];
elements.push(createElement("p", { elements.push(createElement("p", {
innerText: "Reputation: " + formatNumber(faction.playerReputation, 4), innerText: "Reputation: " + formatNumber(faction.playerReputation, 4),
tooltip:"You will earn " + formatNumber(favorGain, 4) + tooltip:"You will earn " + formatNumber(favorGain, 0) +
" faction favor upon resetting after installing an Augmentation" " faction favor upon resetting after installing an Augmentation"
})) }))
elements.push(createElement("p", { elements.push(createElement("p", {
innerText:"---------------", innerText:"---------------",
})); }));
elements.push(createElement("p", { elements.push(createElement("p", {
innerText:"Faction Favor: " + formatNumber(faction.favor, 4), innerText:"Faction Favor: " + formatNumber(faction.favor, 0),
tooltip:"Faction favor increases the rate at which " + tooltip:"Faction favor increases the rate at which " +
"you earn reputation for this faction by 1% per favor. Faction favor " + "you earn reputation for this faction by 1% per favor. Faction favor " +
"is gained whenever you reset after installing an Augmentation. The amount of " + "is gained whenever you reset after installing an Augmentation. The amount of " +
@ -583,214 +422,17 @@ function displayFactionContent(factionName) {
return; return;
} }
if (faction.isMember) { if (!faction.isMember) {
if (faction.favor >= (150 * BitNodeMultipliers.RepToDonateToFaction)) {
donateDiv.style.display = "inline";
} else {
donateDiv.style.display = "none";
}
switch(faction.name) {
case "Illuminati":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "none";
break;
case "Daedalus":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "none";
break;
case "The Covenant":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "none";
break;
case "ECorp":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "MegaCorp":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Bachman & Associates":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Blade Industries":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "NWO":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Clarke Incorporated":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "OmniTek Incorporated":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Four Sigma":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "KuaiGong International":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Fulcrum Secret Technologies":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "inline";
break;
case "BitRunners":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "none";
break;
case "The Black Hand":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "none";
break;
case "NiteSec":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "none";
break;
case "Chongqing":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Sector-12":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "New Tokyo":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Aevum":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Ishima":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Volhaven":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Speakers for the Dead":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "The Dark Army":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "none";
break;
case "The Syndicate":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Silhouette":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "none";
break;
case "Tetrads":
hackMissionDiv.style.display = "none";
hackDiv.style.display = "none";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Slum Snakes":
hackMissionDiv.style.display = "none";
hackDiv.style.display = "none";
fieldWorkDiv.style.display = "inline";
securityWorkDiv.style.display = "inline";
break;
case "Netburners":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "none";
break;
case "Tian Di Hui":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "inline";
break;
case "CyberSec":
hackMissionDiv.style.display = "inline";
hackDiv.style.display = "inline";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "none";
break;
case "Bladeburners":
hackMissionDiv.style.display = "none";
hackDiv.style.display = "none";
fieldWorkDiv.style.display = "none";
securityWorkDiv.style.display = "none";
break;
default:
console.log("Faction does not exist");
break;
}
} else {
throw new Error("Not a member of this faction, cannot display faction information"); throw new Error("Not a member of this faction, cannot display faction information");
} }
donateDiv.style.display = faction.favor >= (150 * BitNodeMultipliers.RepToDonateToFaction) ? "inline" : "none";
hackMissionDiv.style.display = factionInfo.offerHackingMission ? "inline": "none";
hackDiv.style.display = factionInfo.offerHackingWork ? "inline" : "none";
fieldWorkDiv.style.display = factionInfo.offerFieldWork ? "inline" : "none";
securityWorkDiv.style.display = factionInfo.offerSecurityWork ? "inline" : "none";
//Display all elements //Display all elements
for (var i = 0; i < elements.length; ++i) { for (var i = 0; i < elements.length; ++i) {
Engine.Display.factionContent.appendChild(elements[i]); Engine.Display.factionContent.appendChild(elements[i]);
@ -915,6 +557,8 @@ function displayFactionAugmentations(factionName) {
// @augs Array of Aug names // @augs Array of Aug names
// @faction Faction for which to display Augmentations // @faction Faction for which to display Augmentations
function createFactionAugmentationDisplayElements(augmentationsList, augs, faction) { function createFactionAugmentationDisplayElements(augmentationsList, augs, faction) {
const factionInfo = faction.getInfo();
for (var i = 0; i < augs.length; ++i) { for (var i = 0; i < augs.length; ++i) {
(function () { (function () {
var aug = Augmentations[augs[i]]; var aug = Augmentations[augs[i]];
@ -955,7 +599,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
var pElem = createElement("p", { var pElem = createElement("p", {
display:"inline", display:"inline",
}) })
var req = aug.baseRepRequirement * faction.augmentationRepRequirementMult; var req = aug.baseRepRequirement * factionInfo.augmentationRepRequirementMult;
var hasPrereqs = hasAugmentationPrereqs(aug); var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) { if (!hasPrereqs) {
aElem.setAttribute("class", "a-link-button-inactive"); aElem.setAttribute("class", "a-link-button-inactive");
@ -966,10 +610,10 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
pElem.innerHTML = "ALREADY OWNED"; pElem.innerHTML = "ALREADY OWNED";
} else if (faction.playerReputation >= req) { } else if (faction.playerReputation >= req) {
aElem.setAttribute("class", "a-link-button"); aElem.setAttribute("class", "a-link-button");
pElem.innerHTML = "UNLOCKED - " + numeral(aug.baseCost * faction.augmentationPriceMult).format("$0.000a"); pElem.innerHTML = "UNLOCKED - " + numeral(aug.baseCost * factionInfo.augmentationPriceMult).format("$0.000a");
} else { } else {
aElem.setAttribute("class", "a-link-button-inactive"); aElem.setAttribute("class", "a-link-button-inactive");
pElem.innerHTML = "LOCKED (Requires " + formatNumber(req, 1) + " faction reputation) - " + numeral(aug.baseCost * faction.augmentationPriceMult).format("$0.000a"); pElem.innerHTML = "LOCKED (Requires " + formatNumber(req, 1) + " faction reputation) - " + numeral(aug.baseCost * factionInfo.augmentationPriceMult).format("$0.000a");
pElem.style.color = "red"; pElem.style.color = "red";
} }
aDiv.appendChild(aElem); aDiv.appendChild(aElem);
@ -982,6 +626,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
} }
function purchaseAugmentationBoxCreate(aug, fac) { function purchaseAugmentationBoxCreate(aug, fac) {
const factionInfo = fac.getInfo();
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Purchase"; yesBtn.innerHTML = "Purchase";
noBtn.innerHTML = "Cancel"; noBtn.innerHTML = "Cancel";
@ -995,7 +640,7 @@ function purchaseAugmentationBoxCreate(aug, fac) {
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" + yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
aug.info + "<br><br>" + aug.info + "<br><br>" +
"<br>Would you like to purchase the " + aug.name + " Augmentation for $" + "<br>Would you like to purchase the " + aug.name + " Augmentation for $" +
formatNumber(aug.baseCost * fac.augmentationPriceMult, 2) + "?"); formatNumber(aug.baseCost * factionInfo.augmentationPriceMult, 2) + "?");
} }
//Returns a boolean indicating whether the player has the prerequisites for the //Returns a boolean indicating whether the player has the prerequisites for the
@ -1026,12 +671,13 @@ function hasAugmentationPrereqs(aug) {
} }
function purchaseAugmentation(aug, fac, sing=false) { function purchaseAugmentation(aug, fac, sing=false) {
const factionInfo = fac.getInfo();
var hasPrereqs = hasAugmentationPrereqs(aug); var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) { if (!hasPrereqs) {
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " + var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
"purchase this one."; "purchase this one.";
if (sing) {return txt;} else {dialogBoxCreate(txt);} if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (Player.money.lt(aug.baseCost * fac.augmentationPriceMult)) { } else if (Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
let txt = "You don't have enough money to purchase " + aug.name; let txt = "You don't have enough money to purchase " + aug.name;
if (sing) {return txt;} if (sing) {return txt;}
dialogBoxCreate(txt); dialogBoxCreate(txt);
@ -1039,7 +685,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
let txt = "You don't have enough faction reputation to purchase " + aug.name; let txt = "You don't have enough faction reputation to purchase " + aug.name;
if (sing) {return txt;} if (sing) {return txt;}
dialogBoxCreate(txt); dialogBoxCreate(txt);
} else if (Player.money.gte(aug.baseCost * fac.augmentationPriceMult)) { } else if (Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
if (Player.firstAugPurchased === false) { if (Player.firstAugPurchased === false) {
Player.firstAugPurchased = true; Player.firstAugPurchased = true;
document.getElementById("augmentations-tab").style.display = "list-item"; document.getElementById("augmentations-tab").style.display = "list-item";
@ -1053,7 +699,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
} }
Player.queuedAugmentations.push(queuedAugmentation); Player.queuedAugmentations.push(queuedAugmentation);
Player.loseMoney((aug.baseCost * fac.augmentationPriceMult)); Player.loseMoney((aug.baseCost * factionInfo.augmentationPriceMult));
//If you just purchased Neuroflux Governor, recalculate the cost //If you just purchased Neuroflux Governor, recalculate the cost
if (aug.name == AugmentationNames.NeuroFluxGovernor) { if (aug.name == AugmentationNames.NeuroFluxGovernor) {

@ -1,68 +1,81 @@
//Contains the "information" property for all the Factions, which is just a description //Contains the "information" property for all the Factions, which is just a description
//of each faction //of each faction
let FactionInfo = { function FactionInfo(infoText, enemies, offerHackingMission, offerHackingWork, offerFieldWork, offerSecurityWork) {
this.infoText = infoText;
this.enemies = enemies;
this.offerHackingMission = offerHackingMission;
this.offerHackingWork = offerHackingWork;
this.offerFieldWork = offerFieldWork;
this.offerSecurityWork = offerSecurityWork;
// these are always all 1 for now.
this.augmentationPriceMult = 1;
this.augmentationRepRequirementMult = 1;
}
const FactionInfos = {
//Endgame //Endgame
IlluminatiInfo: "Humanity never changes. No matter how civilized society becomes, it will eventually fall back " + "Illuminati": new FactionInfo("Humanity never changes. No matter how civilized society becomes, it will eventually fall back " +
"into chaos. And from this chaos, we are the Invisible hand that guides them to order. ", "into chaos. And from this chaos, we are the Invisible hand that guides them to order. ", [], true, true, true, false),
DaedalusInfo: "Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.", "Daedalus": new FactionInfo("Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.", [], true, true, true, false),
CovenantInfo: "Surrender yourself. Give up your empty individuality to become part of something great, something eternal. " + "The Covenant": new FactionInfo("Surrender yourself. Give up your empty individuality to become part of something great, something eternal. " +
"Become a slave. Submit your mind, body, and soul. Only then can you set yourself free.<br><br> " + "Become a slave. Submit your mind, body, and soul. Only then can you set yourself free.<br><br> " +
"Only then can you discover immortality.", "Only then can you discover immortality.", [], true, true, true, false),
//Megacorporations, each forms its own faction //Megacorporations, each forms its own faction
ECorpInfo: "ECorp's mission is simple: to connect the world of today with the technology of tomorrow. " + "ECorp": new FactionInfo("ECorp's mission is simple: to connect the world of today with the technology of tomorrow. " +
"With our wide range of Internet-related software and commercial hardware, ECorp makes the world's " + "With our wide range of Internet-related software and commercial hardware, ECorp makes the world's " +
"information universally accessible.", "information universally accessible.", [], true, true, true, true),
MegaCorpInfo: "MegaCorp does things that others don't. We imagine. We create. We invent. We build things that " + "MegaCorp": new FactionInfo("MegaCorp does things that others don't. We imagine. We create. We invent. We build things that " +
"others have never even dreamed of. Our work fills the world's needs for food, water, power, and " + "others have never even dreamed of. Our work fills the world's needs for food, water, power, and " +
"transporation on an unprecendented scale, in ways that no other company can.<br><br>" + "transporation on an unprecendented scale, in ways that no other company can.<br><br>" +
"In our labs and factories and on the ground with customers, MegaCorp is ushering in a new era for the world.", "In our labs and factories and on the ground with customers, MegaCorp is ushering in a new era for the world.", [], true, true, true, true),
BachmanAndAssociatesInfo: "Where Law and Business meet - thats where we are. <br><br>" + "Bachman & Associates": new FactionInfo("Where Law and Business meet - thats where we are. <br><br>" +
"Legal Insight - Business Instinct - Experience Innovation", "Legal Insight - Business Instinct - Experience Innovation", [], true, true, true, true),
BladeIndustriesInfo: "Augmentation is salvation", "Blade Industries": new FactionInfo("Augmentation is salvation", [], true, true, true, true),
NWOInfo: "The human being does not truly desire freedom. It wants " + "NWO": new FactionInfo("The human being does not truly desire freedom. It wants " +
"to be observed, understood, and judged. It wants to be given purpose and " + "to be observed, understood, and judged. It wants to be given purpose and " +
"direction in its life. That is why humans created God. " + "direction in its life. That is why humans created God. " +
"And that is why humans created civilization - " + "And that is why humans created civilization - " +
"not because of willingness, " + "not because of willingness, " +
"but because of a need to be incorporated into higher orders of structure and meaning.", "but because of a need to be incorporated into higher orders of structure and meaning.", [], true, true, true, true),
ClarkeIncorporatedInfo: "Unlocking the power of the genome", "Clarke Incorporated": new FactionInfo("Unlocking the power of the genome", [], true, true, true, true),
OmniTekIncorporatedInfo: "Simply put, our mission is to design and build robots that make a difference", "OmniTek Incorporated": new FactionInfo("Simply put, our mission is to design and build robots that make a difference", [], true, true, true, true),
FourSigmaInfo: "The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by " + "Four Sigma": new FactionInfo("The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by " +
"deep learning and innovative ideas. And improved by iteration. That's Four Sigma.", "deep learning and innovative ideas. And improved by iteration. That's Four Sigma.", [], true, true, true, true),
KuaiGongInternationalInfo: "Dream big. Work hard. Make history.", "KuaiGong International": new FactionInfo("Dream big. Work hard. Make history.", [], true, true, true, true),
//Other Corporations //Other Corporations
FulcrumSecretTechnologiesInfo: "The human organism has an innate desire to worship. " + "Fulcrum Secret Technologies": new FactionInfo("The human organism has an innate desire to worship. " +
"That is why they created gods. If there were no gods, " + "That is why they created gods. If there were no gods, " +
"it would be necessary to create them. And now we can.", "it would be necessary to create them. And now we can.", [], true, true, false, true),
//Hacker groups //Hacker groups
BitRunnersInfo: "Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. "+ "BitRunners": new FactionInfo("Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. "+
"It's all transformed into bits, stored in bits, communicated through bits. Its impossible for any person " + "It's all transformed into bits, stored in bits, communicated through bits. Its impossible for any person " +
"to move, to live, to operate at any level without the use of bits. " + "to move, to live, to operate at any level without the use of bits. " +
"And when a person moves, lives, and operates, they leave behind their bits, mere traces of seemingly " + "And when a person moves, lives, and operates, they leave behind their bits, mere traces of seemingly " +
"meaningless fragments of information. But these bits can be reconstructed. Transformed. Used.<br><br>" + "meaningless fragments of information. But these bits can be reconstructed. Transformed. Used.<br><br>" +
"Those who run the bits, run the world", "Those who run the bits, run the world", [], true, true, false, false),
BlackHandInfo: "The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power. " + "The Black Hand": new FactionInfo("The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power. " +
"Technological power. " + "Technological power. " +
"And those at the top rule with an invisible hand. They built a society where the rich get richer, " + "And those at the top rule with an invisible hand. They built a society where the rich get richer, " +
"and everyone else suffers.<br><br>" + "and everyone else suffers.<br><br>" +
"So much pain. So many lives. Their darkness must end.", "So much pain. So many lives. Their darkness must end.", [], true, true, true, false),
NiteSecInfo: "NiteSec": new FactionInfo(
" __..__ <br>" + " __..__ <br>" +
" _.nITESECNIt. <br>" + " _.nITESECNIt. <br>" +
" .-'NITESECNITESEc. <br>" + " .-'NITESECNITESEc. <br>" +
@ -97,47 +110,47 @@ let FactionInfo = {
" / .d$$$$; , ; <br>" + " / .d$$$$; , ; <br>" +
" d .dNITESEC $ | <br>" + " d .dNITESEC $ | <br>" +
" :bp.__.gNITESEC$$ :$ ; <br>" + " :bp.__.gNITESEC$$ :$ ; <br>" +
" NITESECNITESECNIT $$b : <br>", " NITESECNITESECNIT $$b : <br>", [], true, true, false, false),
//City factions, essentially governments //City factions, essentially governments
ChongqingInfo: "Serve the people", "Chongqing": new FactionInfo("Serve the people", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
Sector12Info: "The City of the Future", "Sector-12": new FactionInfo("The City of the Future", ["Chongqing", "New Tokyo", "Ishima", "Volhaven"], true, true, true, true),
HongKongInfo: "Asia's World City", "New Tokyo": new FactionInfo("Asia's World City", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
AevumInfo: "The Silicon City", "Aevum": new FactionInfo("The Silicon City", ["Chongqing", "New Tokyo", "Ishima", "Volhaven"], true, true, true, true),
IshimaInfo: "The East Asian Order of the Future", "Ishima": new FactionInfo("The East Asian Order of the Future", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
VolhavenInfo: "Benefit, Honour, and Glory", "Volhaven": new FactionInfo("Benefit, Honour, and Glory", ["Chongqing", "Sector-12", "New Tokyo", "Aevum", "Ishima"], true, true, true, true),
//Criminal Organizations/Gangs //Criminal Organizations/Gangs
SpeakersForTheDeadInfo: "It is better to reign in hell than to serve in heaven.", "Speakers for the Dead": new FactionInfo("It is better to reign in hell than to serve in heaven.", [], true, true, true, true),
DarkArmyInfo: "The World doesn't care about right or wrong. It's all about power.", "The Dark Army": new FactionInfo("The World doesn't care about right or wrong. It's all about power.", [], true, true, true, false),
TheSyndicateInfo: "Honor holds you back", "The Syndicate": new FactionInfo("Honor holds you back", [], true, true, true, true),
SilhouetteInfo: "Corporations have filled the void of power left behind by the collapse of Western government. The issue is they've become so big " + "Silhouette": new FactionInfo("Corporations have filled the void of power left behind by the collapse of Western government. The issue is they've become so big " +
"that you don't know who they're working for. And if you're employed at one of these corporations, you don't even know who you're working " + "that you don't know who they're working for. And if you're employed at one of these corporations, you don't even know who you're working " +
"for.\n\n" + "for.\n\n" +
"That's terror. Terror, fear, and corruption. All born into the system, all propagated by the system.", "That's terror. Terror, fear, and corruption. All born into the system, all propagated by the system.", [], true, true, true, false),
TetradsInfo: "Following the Mandate of Heaven and Carrying out the Way", "Tetrads": new FactionInfo("Following the Mandate of Heaven and Carrying out the Way", [], false, false, true, true),
SlumSnakesInfo: "Slum Snakes rule!", "Slum Snakes": new FactionInfo("Slum Snakes rule!", [], false, false, true, true),
//Earlygame factions - factions the player will prestige with early on that don't //Earlygame factions - factions the player will prestige with early on that don't
//belong in other categories //belong in other categories
NetburnersInfo: "~~//*>H4CK|\|3T 8URN3R5**>?>\\~~", "Netburners": new FactionInfo("~~//*>H4CK|\|3T 8URN3R5**>?>\\~~", [], true, true, false, false),
TianDiHuiInfo: "Obey Heaven and Work Righteousness", "Tian Di Hui": new FactionInfo("Obey Heaven and Work Righteousness", [], true, true, false, true),
CyberSecInfo: "The Internet is the first thing that humanity has built that humanity doesnt understand, " + "CyberSec": new FactionInfo("The Internet is the first thing that humanity has built that humanity doesnt understand, " +
"the largest experiment in anarchy that we have ever had. And as the world becomes increasingly " + "the largest experiment in anarchy that we have ever had. And as the world becomes increasingly " +
"dominated by the internet, society approaches the brink of total chaos. " + "dominated by the internet, society approaches the brink of total chaos. " +
"We serve only to protect society, to protect humanity, to protect the world from its imminent collapse.", "We serve only to protect society, to protect humanity, to protect the world from its imminent collapse.", [], true, true, false, false),
//Special Factions //Special Factions
BladeburnersInfo: "It's too bad they won't live. But then again, who does?<br><br>" + "Bladeburners": new FactionInfo("It's too bad they won't live. But then again, who does?<br><br>" +
"Note that for this faction, reputation can only be gained through Bladeburner actions. Completing " + "Note that for this faction, reputation can only be gained through Bladeburner actions. Completing " +
"Bladeburner contracts/operations will increase your reputation.", "Bladeburner contracts/operations will increase your reputation.", [], false, false, false, false),
} }
export {FactionInfo}; export {FactionInfos};

@ -10,7 +10,7 @@ import {getRandomInt, createElement,
removeChildrenFromElement, removeChildrenFromElement,
createAccordionElement, createPopup, createAccordionElement, createPopup,
removeElementById, removeElement} from "../utils/HelperFunctions.js"; removeElementById, removeElement} from "../utils/HelperFunctions.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate, import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton, yesNoBoxGetYesButton, yesNoBoxGetNoButton,

@ -5,42 +5,48 @@ import {iTutorialSteps, iTutorialNextStep,
iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js"; iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js";
import {Player} from "./Player.js"; import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js"; import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners} from "../utils/HelperFunctions.js"; import {clearEventListeners, createElement,
getElementById} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
/**
* Overwrites the inner text of the specified HTML element if it is different from what currently exists.
* @param {string} elementId The HTML ID to find the first instance of.
* @param {string} text The inner text that should be set.
*/
function updateText(elementId, text) {
var el = getElementById(elementId);
if (el.innerText != text) {
el.innerText = text;
}
};
/* HacknetNode.js */ /* HacknetNode.js */
function hacknetNodesInit() { function hacknetNodesInit() {
var mult1x = document.getElementById("hacknet-nodes-1x-multiplier"); var performMapping = function(x) {
mult1x.addEventListener("click", function() { getElementById("hacknet-nodes-" + x.id + "-multiplier")
hacknetNodePurchaseMultiplier = 1; .addEventListener("click", function() {
updateHacknetNodesMultiplierButtons(); hacknetNodePurchaseMultiplier = x.multiplier;
updateHacknetNodesContent(); updateHacknetNodesMultiplierButtons();
return false; updateHacknetNodesContent();
}); return false;
var mult5x = document.getElementById("hacknet-nodes-5x-multiplier"); });
mult5x.addEventListener("click", function() { };
hacknetNodePurchaseMultiplier = 5;
updateHacknetNodesMultiplierButtons(); var mappings = [
updateHacknetNodesContent(); { id: "1x", multiplier: 1 },
return false; { id: "5x", multiplier: 5 },
}); { id: "10x", multiplier: 10 },
var mult10x = document.getElementById("hacknet-nodes-10x-multiplier"); { id: "max", multiplier: 0 }
mult10x.addEventListener("click", function() { ];
hacknetNodePurchaseMultiplier = 10; for (var elem of mappings) {
updateHacknetNodesMultiplierButtons(); // Encapsulate in a function so that the appropriate scope is kept in the click handler.
updateHacknetNodesContent(); performMapping(elem);
return false; }
});
var multMax = document.getElementById("hacknet-nodes-max-multiplier");
multMax.addEventListener("click", function() {
hacknetNodePurchaseMultiplier = 0;
updateHacknetNodesMultiplierButtons();
updateHacknetNodesContent();
return false;
});
} }
document.addEventListener("DOMContentLoaded", hacknetNodesInit, false); document.addEventListener("DOMContentLoaded", hacknetNodesInit, false);
function HacknetNode(name) { function HacknetNode(name) {
@ -56,6 +62,7 @@ function HacknetNode(name) {
this.moneyGainRatePerSecond = 0; this.moneyGainRatePerSecond = 0;
} }
HacknetNode.prototype.updateMoneyGainRate = function() { HacknetNode.prototype.updateMoneyGainRate = function() {
//How much extra $/s is gained per level //How much extra $/s is gained per level
var gainPerLevel = CONSTANTS.HacknetNodeMoneyGainPerLevel; var gainPerLevel = CONSTANTS.HacknetNodeMoneyGainPerLevel;
@ -75,7 +82,10 @@ HacknetNode.prototype.updateMoneyGainRate = function() {
HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) { HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) {
levels = Math.round(levels); levels = Math.round(levels);
if (isNaN(levels) || levels < 1) {return 0;} if (isNaN(levels) || levels < 1) {
return 0;
}
var mult = CONSTANTS.HacknetNodeUpgradeLevelMult; var mult = CONSTANTS.HacknetNodeUpgradeLevelMult;
var totalMultiplier = 0; //Summed var totalMultiplier = 0; //Summed
var currLevel = this.level; var currLevel = this.level;
@ -83,6 +93,7 @@ HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) {
totalMultiplier += Math.pow(mult, currLevel); totalMultiplier += Math.pow(mult, currLevel);
++currLevel; ++currLevel;
} }
return CONSTANTS.BaseCostForHacknetNode / 2 * totalMultiplier * Player.hacknet_node_level_cost_mult; return CONSTANTS.BaseCostForHacknetNode / 2 * totalMultiplier * Player.hacknet_node_level_cost_mult;
} }
@ -94,12 +105,19 @@ HacknetNode.prototype.getLevelUpgradeCost = function(levels=1) {
HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) { HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) {
levels = Math.round(levels); levels = Math.round(levels);
var cost = this.calculateLevelUpgradeCost(levels); var cost = this.calculateLevelUpgradeCost(levels);
if (isNaN(cost) || levels < 0) {return false;} if (isNaN(cost) || levels < 0) {
return false;
}
if (this.level + levels > CONSTANTS.HacknetNodeMaxLevel) { if (this.level + levels > CONSTANTS.HacknetNodeMaxLevel) {
var diff = Math.max(0, CONSTANTS.HacknetNodeMaxLevel - this.level); var diff = Math.max(0, CONSTANTS.HacknetNodeMaxLevel - this.level);
return this.purchaseLevelUpgrade(diff); return this.purchaseLevelUpgrade(diff);
} }
if (Player.money.lt(cost)) {return false;}
if (Player.money.lt(cost)) {
return false;
}
Player.loseMoney(cost); Player.loseMoney(cost);
this.level += levels; this.level += levels;
this.updateMoneyGainRate(); this.updateMoneyGainRate();
@ -108,7 +126,9 @@ HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) {
//Wrapper function for Netscript //Wrapper function for Netscript
HacknetNode.prototype.upgradeLevel = function(levels=1) { HacknetNode.prototype.upgradeLevel = function(levels=1) {
return this.purchaseLevelUpgrade(levels); let res = this.purchaseLevelUpgrade(levels);
createPlayerHacknetNodeWrappers();
return res;
} }
HacknetNode.prototype.calculateRamUpgradeCost = function() { HacknetNode.prototype.calculateRamUpgradeCost = function() {
@ -128,9 +148,18 @@ HacknetNode.prototype.getRamUpgradeCost = function() {
HacknetNode.prototype.purchaseRamUpgrade = function() { HacknetNode.prototype.purchaseRamUpgrade = function() {
var cost = this.calculateRamUpgradeCost(); var cost = this.calculateRamUpgradeCost();
if (isNaN(cost)) {return false;} if (isNaN(cost)) {
if (Player.money.lt(cost)) {return false;} return false;
if (this.ram >= CONSTANTS.HacknetNodeMaxRam) {return false;} }
if (Player.money.lt(cost)) {
return false;
}
if (this.ram >= CONSTANTS.HacknetNodeMaxRam) {
return false;
}
Player.loseMoney(cost); Player.loseMoney(cost);
this.ram *= 2; //Ram is always doubled this.ram *= 2; //Ram is always doubled
this.updateMoneyGainRate(); this.updateMoneyGainRate();
@ -139,25 +168,38 @@ HacknetNode.prototype.purchaseRamUpgrade = function() {
//Wrapper function for Netscript //Wrapper function for Netscript
HacknetNode.prototype.upgradeRam = function() { HacknetNode.prototype.upgradeRam = function() {
return this.purchaseRamUpgrade(); let res = this.purchaseRamUpgrade();
createPlayerHacknetNodeWrappers();
return res;
} }
HacknetNode.prototype.calculateCoreUpgradeCost = function() { HacknetNode.prototype.calculateCoreUpgradeCost = function() {
var coreBaseCost = CONSTANTS.BaseCostForHacknetNodeCore; var coreBaseCost = CONSTANTS.BaseCostForHacknetNodeCore;
var mult = CONSTANTS.HacknetNodeUpgradeCoreMult; var mult = CONSTANTS.HacknetNodeUpgradeCoreMult;
return coreBaseCost * Math.pow(mult, this.cores-1) * Player.hacknet_node_core_cost_mult; return coreBaseCost * Math.pow(mult, this.cores - 1) * Player.hacknet_node_core_cost_mult;
} }
//Wrapper function for Netscript //Wrapper function for Netscript
HacknetNode.prototype.getCoreUpgradeCost = function() { HacknetNode.prototype.getCoreUpgradeCost = function() {
return this.calculateCoreUpgradeCost(); let res = this.calculateCoreUpgradeCost();
createPlayerHacknetNodeWrappers();
return res;
} }
HacknetNode.prototype.purchaseCoreUpgrade = function() { HacknetNode.prototype.purchaseCoreUpgrade = function() {
var cost = this.calculateCoreUpgradeCost(); var cost = this.calculateCoreUpgradeCost();
if (isNaN(cost)) {return false;} if (isNaN(cost)) {
if (Player.money.lt(cost)) {return false;} return false;
if (this.cores >= CONSTANTS.HacknetNodeMaxCores) {return false;} }
if (Player.money.lt(cost)) {
return false;
}
if (this.cores >= CONSTANTS.HacknetNodeMaxCores) {
return false;
}
Player.loseMoney(cost); Player.loseMoney(cost);
++this.cores; ++this.cores;
this.updateMoneyGainRate(); this.updateMoneyGainRate();
@ -180,6 +222,36 @@ HacknetNode.fromJSON = function(value) {
Reviver.constructors.HacknetNode = HacknetNode; Reviver.constructors.HacknetNode = HacknetNode;
var HacknetNodeWrapper = function(hacknetNodeObj) {
var _node = hacknetNodeObj;
return {
name : _node.name,
level : _node.level,
ram : _node.ram,
cores : _node.cores,
totalMoneyGenerated : _node.totalMoneyGenerated,
onlineTimeSeconds : _node.onlineTimeSeconds,
moneyGainRatePerSecond : _node.moneyGainRatePerSecond,
upgradeLevel : function(n) {
return _node.upgradeLevel(n);
},
upgradeRam : function() {
return _node.upgradeRam();
},
upgradeCore : function() {
return _node.upgradeCore();
},
getLevelUpgradeCost : function(n) {
return _node.getLevelUpgradeCost(n);
},
getRamUpgradeCost : function() {
return _node.getRamUpgradeCost();
},
getCoreUpgradeCost : function() {
return _node.getCoreUpgradeCost();
}
}
}
function purchaseHacknet() { function purchaseHacknet() {
/* INTERACTIVE TUTORIAL */ /* INTERACTIVE TUTORIAL */
@ -194,7 +266,10 @@ function purchaseHacknet() {
/* END INTERACTIVE TUTORIAL */ /* END INTERACTIVE TUTORIAL */
var cost = getCostOfNextHacknetNode(); var cost = getCostOfNextHacknetNode();
if (isNaN(cost)) {throw new Error("Cost is NaN"); return;} if (isNaN(cost)) {
throw new Error("Cost is NaN");
}
if (Player.money.lt(cost)) { if (Player.money.lt(cost)) {
//dialogBoxCreate("You cannot afford to purchase a Hacknet Node!"); //dialogBoxCreate("You cannot afford to purchase a Hacknet Node!");
return false; return false;
@ -209,7 +284,10 @@ function purchaseHacknet() {
Player.loseMoney(cost); Player.loseMoney(cost);
Player.hacknetNodes.push(node); Player.hacknetNodes.push(node);
displayHacknetNodesContent(); if (Engine.currentPage === Engine.Page.HacknetNodes) {
displayHacknetNodesContent();
}
createPlayerHacknetNodeWrappers();
updateTotalHacknetProduction(); updateTotalHacknetProduction();
return numOwned; return numOwned;
} }
@ -259,9 +337,12 @@ function updateHacknetNodesMultiplierButtons() {
//Calculate the maximum number of times the Player can afford to upgrade //Calculate the maximum number of times the Player can afford to upgrade
//a Hacknet Node's level" //a Hacknet Node's level"
function getMaxNumberLevelUpgrades(nodeObj) { function getMaxNumberLevelUpgrades(nodeObj) {
if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1))) {return 0;} if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1))) {
return 0;
}
var min = 1; var min = 1;
var max = CONSTANTS.HacknetNodeMaxLevel-1; var max = CONSTANTS.HacknetNodeMaxLevel - 1;
var levelsToMax = CONSTANTS.HacknetNodeMaxLevel - nodeObj.level; var levelsToMax = CONSTANTS.HacknetNodeMaxLevel - nodeObj.level;
if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax))) { if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax))) {
return levelsToMax; return levelsToMax;
@ -271,7 +352,7 @@ function getMaxNumberLevelUpgrades(nodeObj) {
var curr = (min + max) / 2 | 0; var curr = (min + max) / 2 | 0;
if (curr != CONSTANTS.HacknetNodeMaxLevel && if (curr != CONSTANTS.HacknetNodeMaxLevel &&
Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr)) && Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr)) &&
Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr+1))) { Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1))) {
return Math.min(levelsToMax, curr); return Math.min(levelsToMax, curr);
} else if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr))) { } else if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr))) {
max = curr - 1; max = curr - 1;
@ -298,7 +379,7 @@ function displayHacknetNodesContent() {
//Remove all old hacknet Node DOM elements //Remove all old hacknet Node DOM elements
var hacknetNodesList = document.getElementById("hacknet-nodes-list"); var hacknetNodesList = document.getElementById("hacknet-nodes-list");
while (hacknetNodesList.firstChild) { while (hacknetNodesList.firstChild) {
hacknetNodesList.removeChild(hacknetNodesList.firstChild); hacknetNodesList.removeChild(hacknetNodesList.firstChild);
} }
@ -306,6 +387,7 @@ function displayHacknetNodesContent() {
for (var i = 0; i < Player.hacknetNodes.length; ++i) { for (var i = 0; i < Player.hacknetNodes.length; ++i) {
createHacknetNodeDomElement(Player.hacknetNodes[i]); createHacknetNodeDomElement(Player.hacknetNodes[i]);
} }
updateHacknetNodesContent(); updateHacknetNodesContent();
} }
@ -313,8 +395,11 @@ function displayHacknetNodesContent() {
function updateHacknetNodesContent() { function updateHacknetNodesContent() {
//Set purchase button to inactive if not enough money, and update its price display //Set purchase button to inactive if not enough money, and update its price display
var cost = getCostOfNextHacknetNode(); var cost = getCostOfNextHacknetNode();
var purchaseButton = document.getElementById("hacknet-nodes-purchase-button"); var purchaseButton = getElementById("hacknet-nodes-purchase-button");
purchaseButton.innerHTML = "Purchase Hacknet Node - $" + formatNumber(cost, 2); var formattedCost = formatNumber(cost, 2);
updateText("hacknet-nodes-purchase-button", "Purchase Hacknet Node - $" + formattedCost);
if (Player.money.lt(cost)) { if (Player.money.lt(cost)) {
purchaseButton.setAttribute("class", "a-link-button-inactive"); purchaseButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -322,9 +407,8 @@ function updateHacknetNodesContent() {
} }
//Update player's money //Update player's money
var moneyElem = document.getElementById("hacknet-nodes-money"); updateText("hacknet-nodes-player-money", "$" + formatNumber(Player.money.toNumber(), 2));
moneyElem.innerHTML = "Money: $" + formatNumber(Player.money.toNumber(), 2) + "<br>" + updateText("hacknet-nodes-total-production", "$" + formatNumber(Player.totalHacknetNodeProduction, 2) + " / second");
"Total production from all Hacknet Nodes: $" + formatNumber(Player.totalHacknetNodeProduction, 2) + " / second";
//Update information in each owned hacknet node //Update information in each owned hacknet node
for (var i = 0; i < Player.hacknetNodes.length; ++i) { for (var i = 0; i < Player.hacknetNodes.length; ++i) {
@ -336,61 +420,75 @@ function updateHacknetNodesContent() {
function createHacknetNodeDomElement(nodeObj) { function createHacknetNodeDomElement(nodeObj) {
var nodeName = nodeObj.name; var nodeName = nodeObj.name;
var listItem = document.createElement("li"); var nodeLevelContainer = createElement("div", {
listItem.setAttribute("class", "hacknet-node"); class: "hacknet-node-level-container row",
innerHTML: "<p>Level:</p><span class=\"text upgradable-info\" id=\"hacknet-node-level-" + nodeName + "\"></span>"
});
var span = document.createElement("span"); var nodeRamContainer = createElement("div", {
span.style.display = "inline"; class: "hacknet-node-ram-container row",
innerHTML: "<p>RAM:</p><span class=\"text upgradable-info\" id=\"hacknet-node-ram-" + nodeName + "\"></span>"
});
var buttonDiv = document.createElement("div"); var nodeCoresContainer = createElement("div", {
buttonDiv.setAttribute("class", "hacknet-node-button-div"); class: "hacknet-node-cores-container row",
innerHTML: "<p>Cores:</p><span class=\"text upgradable-info\" id=\"hacknet-node-cores-" + nodeName + "\"><span>"
})
var containingDiv = createElement("div", {
class: "hacknet-node-container",
innerHTML: "<div class=\"hacknet-node-name-container row\">" +
"<p>Node name:</p>" +
"<span class=\"text\" id=\"hacknet-node-name-" + nodeName + "\"></span>" +
"</div>" +
"<div class=\"hacknet-node-production-container row\">" +
"<p>Production:</p>" +
"<span class=\"text\" id=\"hacknet-node-total-production-" + nodeName + "\"></span>" +
"<span class=\"text\" id=\"hacknet-node-production-rate-" + nodeName + "\"></span>" +
"</div>"
});
containingDiv.appendChild(nodeLevelContainer);
containingDiv.appendChild(nodeRamContainer);
containingDiv.appendChild(nodeCoresContainer);
//Text var listItem = createElement("li", {
var txt = document.createElement("p"); class: "hacknet-node"
//txt.setAttribute("id", "hacknet-node-text-" + nodeName); });
txt.id = "hacknet-node-text-" + nodeName; listItem.appendChild(containingDiv);
//Upgrade buttons //Upgrade buttons
var upgradeLevelButton = document.createElement("a"); nodeLevelContainer.appendChild(createElement("a", {
var upgradeRamButton = document.createElement("a"); id: "hacknet-node-upgrade-level-" + nodeName,
var upgradeCoreButton = document.createElement("a"); class: "a-link-button-inactive",
clickListener: function() {
//upgradeLevelButton.setAttribute("id", "hacknet-node-upgrade-level-" + nodeName); var numUpgrades = hacknetNodePurchaseMultiplier;
upgradeLevelButton.id = "hacknet-node-upgrade-level-" + nodeName; if (hacknetNodePurchaseMultiplier == 0) {
upgradeLevelButton.setAttribute("class", "a-link-button-inactive"); numUpgrades = getMaxNumberLevelUpgrades(nodeObj);
upgradeLevelButton.addEventListener("click", function() { }
var numUpgrades = hacknetNodePurchaseMultiplier; nodeObj.purchaseLevelUpgrade(numUpgrades);
if (hacknetNodePurchaseMultiplier == 0) { updateHacknetNodesContent();
numUpgrades = getMaxNumberLevelUpgrades(nodeObj); return false;
} }
nodeObj.purchaseLevelUpgrade(numUpgrades); }));
updateHacknetNodesContent();
return false;
});
//upgradeRamButton.setAttribute("id", "hacknet-node-upgrade-ram-" + nodeName);
upgradeRamButton.id = "hacknet-node-upgrade-ram-" + nodeName;
upgradeRamButton.setAttribute("class", "a-link-button-inactive");
upgradeRamButton.addEventListener("click", function() {
nodeObj.purchaseRamUpgrade();
updateHacknetNodesContent();
return false;
});
//upgradeCoreButton.setAttribute("id", "hacknet-node-upgrade-core-" + nodeName);
upgradeCoreButton.id = "hacknet-node-upgrade-core-" + nodeName;
upgradeCoreButton.setAttribute("class", "a-link-button-inactive");
upgradeCoreButton.addEventListener("click", function() {
nodeObj.purchaseCoreUpgrade();
updateHacknetNodesContent();
return false;
});
//Put all the components together in the li element nodeRamContainer.appendChild(createElement("a", {
span.appendChild(txt); id: "hacknet-node-upgrade-ram-" + nodeName,
buttonDiv.appendChild(upgradeLevelButton); class: "a-link-button-inactive",
buttonDiv.appendChild(upgradeRamButton); clickListener: function() {
buttonDiv.appendChild(upgradeCoreButton); nodeObj.purchaseRamUpgrade();
span.appendChild(buttonDiv); updateHacknetNodesContent();
listItem.appendChild(span); return false;
}
}));
nodeCoresContainer.appendChild(createElement("a", {
id: "hacknet-node-upgrade-core-" + nodeName,
class: "a-link-button-inactive",
clickListener: function() {
nodeObj.purchaseCoreUpgrade();
updateHacknetNodesContent();
return false;
}
}));
document.getElementById("hacknet-nodes-list").appendChild(listItem); document.getElementById("hacknet-nodes-list").appendChild(listItem);
@ -401,20 +499,19 @@ function createHacknetNodeDomElement(nodeObj) {
//Updates information on a single hacknet node DOM element //Updates information on a single hacknet node DOM element
function updateHacknetNodeDomElement(nodeObj) { function updateHacknetNodeDomElement(nodeObj) {
var nodeName = nodeObj.name; var nodeName = nodeObj.name;
var txt = document.getElementById("hacknet-node-text-" + nodeName);
if (txt == null) {throw new Error("Cannot find text element");} updateText("hacknet-node-name-" + nodeName, nodeName);
txt.innerHTML = "Node name: " + nodeName + "<br>" + updateText("hacknet-node-total-production-" + nodeName, "$" + formatNumber(nodeObj.totalMoneyGenerated, 2));
"Production: $" + formatNumber(nodeObj.totalMoneyGenerated, 2) + updateText("hacknet-node-production-rate-" + nodeName, "($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / second)");
" ($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / second) <br>" + updateText("hacknet-node-level-" + nodeName, nodeObj.level);
"Level: " + nodeObj.level + "<br>" + updateText("hacknet-node-ram-" + nodeName, nodeObj.ram + "GB");
"RAM: " + nodeObj.ram + "GB<br>" + updateText("hacknet-node-cores-" + nodeName, nodeObj.cores);
"Cores: " + nodeObj.cores;
//Upgrade level //Upgrade level
var upgradeLevelButton = document.getElementById("hacknet-node-upgrade-level-" + nodeName); var upgradeLevelButton = getElementById("hacknet-node-upgrade-level-" + nodeName);
if (upgradeLevelButton == null) {throw new Error("Cannot find upgrade level button element");}
if (nodeObj.level >= CONSTANTS.HacknetNodeMaxLevel) { if (nodeObj.level >= CONSTANTS.HacknetNodeMaxLevel) {
upgradeLevelButton.innerHTML = "MAX LEVEL"; updateText("hacknet-node-upgrade-level-" + nodeName, "MAX LEVEL");
upgradeLevelButton.setAttribute("class", "a-link-button-inactive"); upgradeLevelButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
var multiplier = 0; var multiplier = 0;
@ -427,8 +524,7 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
var upgradeLevelCost = nodeObj.calculateLevelUpgradeCost(multiplier); var upgradeLevelCost = nodeObj.calculateLevelUpgradeCost(multiplier);
upgradeLevelButton.innerHTML = "Upgrade Hacknet Node Level x" + multiplier + updateText("hacknet-node-upgrade-level-" + nodeName, "Upgrade x" + multiplier + " - $" + formatNumber(upgradeLevelCost, 2))
" - $" + formatNumber(upgradeLevelCost, 2);
if (Player.money.lt(upgradeLevelCost)) { if (Player.money.lt(upgradeLevelCost)) {
upgradeLevelButton.setAttribute("class", "a-link-button-inactive"); upgradeLevelButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -437,14 +533,14 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
//Upgrade RAM //Upgrade RAM
var upgradeRamButton = document.getElementById("hacknet-node-upgrade-ram-" + nodeName); var upgradeRamButton = getElementById("hacknet-node-upgrade-ram-" + nodeName);
if (upgradeRamButton == null) {throw new Error("Cannot find upgrade ram button element");}
if (nodeObj.ram >= CONSTANTS.HacknetNodeMaxRam) { if (nodeObj.ram >= CONSTANTS.HacknetNodeMaxRam) {
upgradeRamButton.innerHTML = "MAX RAM"; updateText("hacknet-node-upgrade-ram-" + nodeName, "MAX RAM");
upgradeRamButton.setAttribute("class", "a-link-button-inactive"); upgradeRamButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
var upgradeRamCost = nodeObj.calculateRamUpgradeCost(); var upgradeRamCost = nodeObj.calculateRamUpgradeCost();
upgradeRamButton.innerHTML = "Upgrade Hacknet Node RAM - $" + formatNumber(upgradeRamCost, 2); updateText("hacknet-node-upgrade-ram-" + nodeName, "Upgrade - $" + formatNumber(upgradeRamCost, 2));
if (Player.money.lt(upgradeRamCost)) { if (Player.money.lt(upgradeRamCost)) {
upgradeRamButton.setAttribute("class", "a-link-button-inactive"); upgradeRamButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -453,14 +549,14 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
//Upgrade Cores //Upgrade Cores
var upgradeCoreButton = document.getElementById("hacknet-node-upgrade-core-" + nodeName); var upgradeCoreButton = getElementById("hacknet-node-upgrade-core-" + nodeName);
if (upgradeCoreButton == null) {throw new Error("Cannot find upgrade cores button element");}
if (nodeObj.cores >= CONSTANTS.HacknetNodeMaxCores) { if (nodeObj.cores >= CONSTANTS.HacknetNodeMaxCores) {
upgradeCoreButton.innerHTML = "MAX CORES"; updateText("hacknet-node-upgrade-core-" + nodeName, "MAX CORES");
upgradeCoreButton.setAttribute("class", "a-link-button-inactive"); upgradeCoreButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
var upgradeCoreCost = nodeObj.calculateCoreUpgradeCost(); var upgradeCoreCost = nodeObj.calculateCoreUpgradeCost();
upgradeCoreButton.innerHTML = "Purchase additional CPU Core - $" + formatNumber(upgradeCoreCost, 2); updateText("hacknet-node-upgrade-core-" + nodeName, "Upgrade - $" + formatNumber(upgradeCoreCost, 2));
if (Player.money.lt(upgradeCoreCost)) { if (Player.money.lt(upgradeCoreCost)) {
upgradeCoreButton.setAttribute("class", "a-link-button-inactive"); upgradeCoreButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -469,11 +565,39 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
} }
function createPlayerHacknetNodeWrappers() {
Player.hacknetNodeWrappers.length = Player.hacknetNodes.length;
for (var i = 0; i < Player.hacknetNodes.length; ++i) {
Player.hacknetNodeWrappers[i] = new HacknetNodeWrapper(Player.hacknetNodes[i]);
}
}
function updatePlayerHacknetNodeWrappers() {
if (Player.hacknetNodeWrappers.length !== Player.hacknetNodes.length) {
return createPlayerHacknetNodeWrappers();
}
for (var i = 0; i < Player.hacknetNodeWrappers.length; ++i) {
if (!(Player.hacknetNodeWrappers[i] instanceof HacknetNodeWrapper)) {
return createPlayerHacknetNodeWrappers();
}
Player.hacknetNodeWrappers[i].level = Player.hacknetNodes[i].level;
Player.hacknetNodeWrappers[i].ram = Player.hacknetNodes[i].ram;
Player.hacknetNodeWrappers[i].cores = Player.hacknetNodes[i].cores;
Player.hacknetNodeWrappers[i].totalMoneyGenerated = Player.hacknetNodes[i].totalMoneyGenerated;
Player.hacknetNodeWrappers[i].onlineTimeSeconds = Player.hacknetNodes[i].onlineTimeSeconds;
Player.hacknetNodeWrappers[i].moneyGainRatePerSecond = Player.hacknetNodes[i].moneyGainRatePerSecond;
}
}
function processAllHacknetNodeEarnings(numCycles) { function processAllHacknetNodeEarnings(numCycles) {
var total = 0; var total = 0;
updatePlayerHacknetNodeWrappers();
for (var i = 0; i < Player.hacknetNodes.length; ++i) { for (var i = 0; i < Player.hacknetNodes.length; ++i) {
total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]); total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]);
} }
return total; return total;
} }
@ -481,9 +605,10 @@ function processSingleHacknetNodeEarnings(numCycles, nodeObj) {
var cyclesPerSecond = 1000 / Engine._idleSpeed; var cyclesPerSecond = 1000 / Engine._idleSpeed;
var earningPerCycle = nodeObj.moneyGainRatePerSecond / cyclesPerSecond; var earningPerCycle = nodeObj.moneyGainRatePerSecond / cyclesPerSecond;
if (isNaN(earningPerCycle)) { if (isNaN(earningPerCycle)) {
console.log("ERROR: Hacknet Node Calculated earnings is NaN"); console.error("Hacknet Node '" + nodeObj.name + "' Calculated earnings is NaN");
earningPerCycle = 0; earningPerCycle = 0;
} }
var totalEarnings = numCycles * earningPerCycle; var totalEarnings = numCycles * earningPerCycle;
nodeObj.totalMoneyGenerated += totalEarnings; nodeObj.totalMoneyGenerated += totalEarnings;
nodeObj.onlineTimeSeconds += (numCycles * (Engine._idleSpeed / 1000)); nodeObj.onlineTimeSeconds += (numCycles * (Engine._idleSpeed / 1000));
@ -497,10 +622,21 @@ function getHacknetNode(name) {
return Player.hacknetNodes[i]; return Player.hacknetNodes[i];
} }
} }
return null; return null;
} }
export {hacknetNodesInit, HacknetNode, purchaseHacknet, updateTotalHacknetProduction, export {
getCostOfNextHacknetNode, updateHacknetNodesMultiplierButtons, getMaxNumberLevelUpgrades, HacknetNode,
displayHacknetNodesContent, updateHacknetNodesContent, processAllHacknetNodeEarnings, createPlayerHacknetNodeWrappers,
getHacknetNode}; displayHacknetNodesContent,
getCostOfNextHacknetNode,
getHacknetNode,
getMaxNumberLevelUpgrades,
hacknetNodesInit,
processAllHacknetNodeEarnings,
purchaseHacknet,
updateHacknetNodesContent,
updateHacknetNodesMultiplierButtons,
updateTotalHacknetProduction
};

@ -3,18 +3,7 @@ import {CompanyPositions, initCompanies,
Companies, getJobRequirementText} from "./Company.js"; Companies, getJobRequirementText} from "./Company.js";
import {Corporation} from "./CompanyManagement.js"; import {Corporation} from "./CompanyManagement.js";
import {CONSTANTS} from "./Constants.js"; import {CONSTANTS} from "./Constants.js";
import {commitShopliftCrime, commitRobStoreCrime, commitMugCrime, import {Crimes} from "./Crimes.js";
commitLarcenyCrime, commitDealDrugsCrime, commitBondForgeryCrime,
commitTraffickArmsCrime,
commitHomicideCrime, commitGrandTheftAutoCrime, commitKidnapCrime,
commitAssassinationCrime, commitHeistCrime, determineCrimeSuccess,
determineCrimeChanceShoplift, determineCrimeChanceRobStore,
determineCrimeChanceMug, determineCrimeChanceLarceny,
determineCrimeChanceDealDrugs, determineCrimeChanceBondForgery,
determineCrimeChanceTraffickArms,
determineCrimeChanceHomicide, determineCrimeChanceGrandTheftAuto,
determineCrimeChanceKidnap, determineCrimeChanceAssassination,
determineCrimeChanceHeist} from "./Crimes.js";
import {Engine} from "./engine.js"; import {Engine} from "./engine.js";
import {beginInfiltration} from "./Infiltration.js"; import {beginInfiltration} from "./Infiltration.js";
import {hasBladeburnerSF} from "./NetscriptFunctions.js"; import {hasBladeburnerSF} from "./NetscriptFunctions.js";
@ -22,12 +11,13 @@ import {Player} from "./Player.js";
import {Server, AllServers, AddToAllServers} from "./Server.js"; import {Server, AllServers, AddToAllServers} from "./Server.js";
import {purchaseServer, import {purchaseServer,
purchaseRamForHomeComputer} from "./ServerPurchases.js"; purchaseRamForHomeComputer} from "./ServerPurchases.js";
import {Settings} from "./Settings.js";
import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps.js"; import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps.js";
import {dialogBoxCreate} from "../utils/DialogBox.js"; import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners, createElement} from "../utils/HelperFunctions.js"; import {clearEventListeners, createElement} from "../utils/HelperFunctions.js";
import {createRandomIp} from "../utils/IPAddress.js"; import {createRandomIp} from "../utils/IPAddress.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate, import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton, yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -289,7 +279,10 @@ function displayLocationContent() {
purchase256gb.innerHTML = "Purchase 256GB Server - $" + formatNumber(256*CONSTANTS.BaseCostFor1GBOfRamServer, 2); purchase256gb.innerHTML = "Purchase 256GB Server - $" + formatNumber(256*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase512gb.innerHTML = "Purchase 512GB Server - $" + formatNumber(512*CONSTANTS.BaseCostFor1GBOfRamServer, 2); purchase512gb.innerHTML = "Purchase 512GB Server - $" + formatNumber(512*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase1tb.innerHTML = "Purchase 1TB Server - $" + formatNumber(1024*CONSTANTS.BaseCostFor1GBOfRamServer, 2); purchase1tb.innerHTML = "Purchase 1TB Server - $" + formatNumber(1024*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchaseTor.innerHTML = "Purchase TOR Router - $" + formatNumber(CONSTANTS.TorRouterCost, 2); if (!SpecialServerIps.hasOwnProperty("Darkweb Server")) {
purchaseTor.innerHTML = "Purchase TOR Router - $" + formatNumber(CONSTANTS.TorRouterCost, 2);
}
travelAgencyText.style.display = "none"; travelAgencyText.style.display = "none";
travelToAevum.style.display = "none"; travelToAevum.style.display = "none";
@ -337,9 +330,9 @@ function displayLocationContent() {
repGain = repGain[0]; repGain = repGain[0];
jobReputation.innerHTML = "Company reputation: " + formatNumber(company.playerReputation, 4) + jobReputation.innerHTML = "Company reputation: " + formatNumber(company.playerReputation, 4) +
"<span class='tooltiptext'>You will earn " + "<span class='tooltiptext'>You will earn " +
formatNumber(repGain, 4) + formatNumber(repGain, 0) +
" faction favor upon resetting after installing an Augmentation</span>"; " faction favor upon resetting after installing an Augmentation</span>";
companyFavor.innerHTML = "Company Favor: " + formatNumber(company.favor, 4) + companyFavor.innerHTML = "Company Favor: " + formatNumber(company.favor, 0) +
"<span class='tooltiptext'>Company favor increases the rate at which " + "<span class='tooltiptext'>Company favor increases the rate at which " +
"you earn reputation for this company by 1% per favor. Company favor " + "you earn reputation for this company by 1% per favor. Company favor " +
"is gained whenever you reset after installing an Augmentation. The amount of " + "is gained whenever you reset after installing an Augmentation. The amount of " +
@ -726,6 +719,7 @@ function displayLocationContent() {
securityJob.style.display = "block"; securityJob.style.display = "block";
agentJob.style.display = "block"; agentJob.style.display = "block";
if (Player.bitNodeN === 6 || hasBladeburnerSF === true) { if (Player.bitNodeN === 6 || hasBladeburnerSF === true) {
if (Player.bitNodeN === 8) {break;}
if (Player.bladeburner instanceof Bladeburner) { if (Player.bladeburner instanceof Bladeburner) {
//Note: Can't infiltrate NSA when part of bladeburner //Note: Can't infiltrate NSA when part of bladeburner
nsaBladeburner.innerText = "Enter Bladeburner Headquarters"; nsaBladeburner.innerText = "Enter Bladeburner Headquarters";
@ -1057,18 +1051,18 @@ function displayLocationContent() {
case Locations.NewTokyoSlums: case Locations.NewTokyoSlums:
case Locations.IshimaSlums: case Locations.IshimaSlums:
case Locations.VolhavenSlums: case Locations.VolhavenSlums:
var shopliftChance = determineCrimeChanceShoplift(); var shopliftChance = Crimes.Shoplift.successRate();
var robStoreChance = determineCrimeChanceRobStore(); var robStoreChance = Crimes.RobStore.successRate();
var mugChance = determineCrimeChanceMug(); var mugChance = Crimes.Mug.successRate();
var larcenyChance = determineCrimeChanceLarceny(); var larcenyChance = Crimes.Larceny.successRate();
var drugsChance = determineCrimeChanceDealDrugs(); var drugsChance = Crimes.DealDrugs.successRate();
var bondChance = determineCrimeChanceBondForgery(); var bondChance = Crimes.BondForgery.successRate();
var armsChance = determineCrimeChanceTraffickArms(); var armsChance = Crimes.TraffickArms.successRate();
var homicideChance = determineCrimeChanceHomicide(); var homicideChance = Crimes.Homicide.successRate();
var gtaChance = determineCrimeChanceGrandTheftAuto(); var gtaChance = Crimes.GrandTheftAuto.successRate();
var kidnapChance = determineCrimeChanceKidnap(); var kidnapChance = Crimes.Kidnap.successRate();
var assassinateChance = determineCrimeChanceAssassination(); var assassinateChance = Crimes.Assassination.successRate();
var heistChance = determineCrimeChanceHeist(); var heistChance = Crimes.Heist.successRate();
slumsDescText.style.display = "block"; slumsDescText.style.display = "block";
slumsShoplift.style.display = "block"; slumsShoplift.style.display = "block";
@ -1771,16 +1765,8 @@ function initLocationButtons() {
}); });
purchaseHomeRam.addEventListener("click", function() { purchaseHomeRam.addEventListener("click", function() {
//Calculate how many times ram has been upgraded (doubled) const cost = Player.getUpgradeHomeRamCost();
var currentRam = Player.getHomeComputer().maxRam; const ram = Player.getHomeComputer().maxRam;
var newRam = currentRam * 2;
var numUpgrades = Math.log2(currentRam);
//Calculate cost
//Have cost increase by some percentage each time RAM has been upgraded
var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome;
var mult = Math.pow(1.58, numUpgrades);
cost = cost * mult;
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel"; yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel";
@ -1792,8 +1778,8 @@ function initLocationButtons() {
yesNoBoxClose(); yesNoBoxClose();
}); });
yesNoBoxCreate("Would you like to purchase additional RAM for your home computer? <br><br>" + yesNoBoxCreate("Would you like to purchase additional RAM for your home computer? <br><br>" +
"This will upgrade your RAM from " + currentRam + "GB to " + newRam + "GB. <br><br>" + "This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB. <br><br>" +
"This will cost $" + formatNumber(cost, 2)); "This will cost " + numeral(cost).format('$0.000a'));
}); });
purchaseHomeCores.addEventListener("click", function() { purchaseHomeCores.addEventListener("click", function() {
@ -1833,92 +1819,92 @@ function initLocationButtons() {
}); });
travelToAevum.addEventListener("click", function() { travelToAevum.addEventListener("click", function() {
travelBoxCreate(Locations.Aevum, 200000); travelBoxCreate(Locations.Aevum, CONSTANTS.TravelCost);
return false; return false;
}); });
travelToChongqing.addEventListener("click", function() { travelToChongqing.addEventListener("click", function() {
travelBoxCreate(Locations.Chongqing, 200000); travelBoxCreate(Locations.Chongqing, CONSTANTS.TravelCost);
return false; return false;
}); });
travelToSector12.addEventListener("click", function() { travelToSector12.addEventListener("click", function() {
travelBoxCreate(Locations.Sector12, 200000); travelBoxCreate(Locations.Sector12, CONSTANTS.TravelCost);
return false; return false;
}); });
travelToNewTokyo.addEventListener("click", function() { travelToNewTokyo.addEventListener("click", function() {
travelBoxCreate(Locations.NewTokyo, 200000); travelBoxCreate(Locations.NewTokyo, CONSTANTS.TravelCost);
return false; return false;
}); });
travelToIshima.addEventListener("click", function() { travelToIshima.addEventListener("click", function() {
travelBoxCreate(Locations.Ishima, 200000); travelBoxCreate(Locations.Ishima, CONSTANTS.TravelCost);
return false; return false;
}); });
travelToVolhaven.addEventListener("click", function() { travelToVolhaven.addEventListener("click", function() {
travelBoxCreate(Locations.Volhaven, 200000); travelBoxCreate(Locations.Volhaven, CONSTANTS.TravelCost);
return false; return false;
}); });
slumsShoplift.addEventListener("click", function() { slumsShoplift.addEventListener("click", function() {
commitShopliftCrime(); Crimes.Shoplift.commit();
return false; return false;
}); });
slumsRobStore.addEventListener("click", function() { slumsRobStore.addEventListener("click", function() {
commitRobStoreCrime(); Crimes.RobStore.commit();
return false; return false;
}); });
slumsMug.addEventListener("click", function() { slumsMug.addEventListener("click", function() {
commitMugCrime(); Crimes.Mug.commit();
return false; return false;
}); });
slumsLarceny.addEventListener("click", function() { slumsLarceny.addEventListener("click", function() {
commitLarcenyCrime(); Crimes.Larceny.commit();
return false; return false;
}); });
slumsDealDrugs.addEventListener("click", function() { slumsDealDrugs.addEventListener("click", function() {
commitDealDrugsCrime(); Crimes.DealDrugs.commit();
return false; return false;
}); });
slumsBondForgery.addEventListener("click", function() { slumsBondForgery.addEventListener("click", function() {
commitBondForgeryCrime(); Crimes.BondForgery.commit();
return false; return false;
}); });
slumsTrafficArms.addEventListener("click", function() { slumsTrafficArms.addEventListener("click", function() {
commitTraffickArmsCrime(); Crimes.TraffickArms.commit();
return false; return false;
}); });
slumsHomicide.addEventListener("click", function() { slumsHomicide.addEventListener("click", function() {
commitHomicideCrime(); Crimes.Homicide.commit();
return false; return false;
}); });
slumsGta.addEventListener("click", function() { slumsGta.addEventListener("click", function() {
commitGrandTheftAutoCrime(); Crimes.GrandTheftAuto.commit();
return false; return false;
}); });
slumsKidnap.addEventListener("click", function() { slumsKidnap.addEventListener("click", function() {
commitKidnapCrime(); Crimes.Kidnap.commit();
return false; return false;
}); });
slumsAssassinate.addEventListener("click", function() { slumsAssassinate.addEventListener("click", function() {
commitAssassinationCrime(); Crimes.Assassination.commit();
return false; return false;
}); });
slumsHeist.addEventListener("click", function() { slumsHeist.addEventListener("click", function() {
commitHeistCrime(); Crimes.Heist.commit();
return false; return false;
}); });
@ -2020,11 +2006,13 @@ function purchaseTorRouter() {
AddToAllServers(darkweb); AddToAllServers(darkweb);
SpecialServerIps.addIp("Darkweb Server", darkweb.ip); SpecialServerIps.addIp("Darkweb Server", darkweb.ip);
document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button-inactive"); const purchaseTor = document.getElementById("location-purchase-tor");
purchaseTor.setAttribute("class", "a-link-button-bought");
purchaseTor.innerHTML = "TOR Router - Purchased";
Player.getHomeComputer().serversOnNetwork.push(darkweb.ip); Player.getHomeComputer().serversOnNetwork.push(darkweb.ip);
darkweb.serversOnNetwork.push(Player.getHomeComputer().ip); darkweb.serversOnNetwork.push(Player.getHomeComputer().ip);
dialogBoxCreate("You have purchased a Tor router!<br>You now have access to the dark web from your home computer<br>Use the scan/netstat commands to search for the dark web connection."); dialogBoxCreate("You have purchased a Tor router!<br>You now have access to the dark web from your home computer<br>Use the scan/scan-analyze commands to search for the dark web connection.");
} }
function displayUniversityLocationContent(costMult) { function displayUniversityLocationContent(costMult) {
@ -2162,6 +2150,10 @@ function setJobRequirementTooltip(loc, entryPosType, btn) {
} }
function travelBoxCreate(destCityName, cost) { function travelBoxCreate(destCityName, cost) {
if(Settings.SuppressTravelConfirmation) {
travelToCity(destCityName, cost);
return;
}
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Yes"; yesBtn.innerHTML = "Yes";
noBtn.innerHTML = "No"; noBtn.innerHTML = "No";

@ -833,7 +833,9 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
return Promise.resolve(false); return Promise.resolve(false);
} else { } else {
//Able to run script //Able to run script
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads and args: " + printArray(args) + ". May take a few seconds to start up..."); if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.exec == null && workerScript.disableLogs.run == null && workerScript.disableLogs.spawn == null) {
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads and args: " + printArray(args) + ". May take a few seconds to start up...");
}
var runningScriptObj = new RunningScript(script, args); var runningScriptObj = new RunningScript(script, args);
runningScriptObj.threads = threads; runningScriptObj.threads = threads;
server.runningScripts.push(runningScriptObj); //Push onto runningScripts server.runningScripts.push(runningScriptObj); //Push onto runningScripts

File diff suppressed because it is too large Load Diff

@ -31,8 +31,12 @@ function WorkerScript(runningScriptObj) {
this.delay = null; this.delay = null;
this.fnWorker = null; //Workerscript for a function call this.fnWorker = null; //Workerscript for a function call
this.checkingRam = false; this.checkingRam = false;
this.loadedFns = {}; //Stores names of fns that are "loaded" by this script, thus using RAM this.loadedFns = {}; //Stores names of fns that are "loaded" by this script, thus using RAM. Used for static RAM evaluation
this.disableLogs = {}; //Stores names of fns that should have logs disabled this.disableLogs = {}; //Stores names of fns that should have logs disabled
//Properties used for dynamic RAM evaluation
this.dynamicRamUsage = 1.4;
this.dynamicLoadedFns = {};
} }
//Returns the server on which the workerScript is running //Returns the server on which the workerScript is running
@ -52,6 +56,14 @@ WorkerScript.prototype.getScript = function() {
return null; return null;
} }
WorkerScript.prototype.shouldLog = function(fn) {
return (this.disableLogs.ALL == null && this.disableLogs[fn] == null);
}
WorkerScript.prototype.log = function(txt) {
this.scriptRef.log(txt);
}
//Array containing all scripts that are running across all servers, to easily run them all //Array containing all scripts that are running across all servers, to easily run them all
let workerScripts = []; let workerScripts = [];

@ -8,7 +8,7 @@ import {Company, Companies, getNextCompanyPosition,
import {CONSTANTS} from "./Constants.js"; import {CONSTANTS} from "./Constants.js";
import {Corporation} from "./CompanyManagement.js"; import {Corporation} from "./CompanyManagement.js";
import {Programs} from "./CreateProgram.js"; import {Programs} from "./CreateProgram.js";
import {determineCrimeSuccess} from "./Crimes.js"; import {determineCrimeSuccess, Crimes} from "./Crimes.js";
import {Engine} from "./engine.js"; import {Engine} from "./engine.js";
import {Factions, Faction, import {Factions, Faction,
displayFactionContent} from "./Faction.js"; displayFactionContent} from "./Faction.js";
@ -25,7 +25,7 @@ import {clearEventListeners} from "../utils/HelperFunctions.j
import {createRandomIp} from "../utils/IPAddress.js"; import {createRandomIp} from "../utils/IPAddress.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber, import {formatNumber,
convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js"; convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js";
@ -99,6 +99,7 @@ function PlayerObject() {
this.currentServer = ""; //IP address of Server currently being accessed through terminal this.currentServer = ""; //IP address of Server currently being accessed through terminal
this.purchasedServers = []; //IP Addresses of purchased servers this.purchasedServers = []; //IP Addresses of purchased servers
this.hacknetNodes = []; this.hacknetNodes = [];
this.hacknetNodeWrappers = [];
this.totalHacknetNodeProduction = 0; this.totalHacknetNodeProduction = 0;
//Factions //Factions
@ -298,8 +299,6 @@ PlayerObject.prototype.prestigeAugmentation = function() {
this.hacknetNodes.length = 0; this.hacknetNodes.length = 0;
this.totalHacknetNodeProduction = 0; this.totalHacknetNodeProduction = 0;
this.bladeburner = 0;
} }
PlayerObject.prototype.prestigeSourceFile = function() { PlayerObject.prototype.prestigeSourceFile = function() {
@ -390,16 +389,6 @@ PlayerObject.prototype.prestigeSourceFile = function() {
if (this.bitNodeN === 3) {this.money = new Decimal(150e9);} if (this.bitNodeN === 3) {this.money = new Decimal(150e9);}
this.corporation = 0; this.corporation = 0;
//Reset Bladeburner
this.bladeburner = 0;
//BitNode 8: Ghost of Wall Street
if (this.bitNodeN === 8) {this.money = new Decimal(100000000);}
if (this.bitNodeN === 8 || hasWallStreetSF) {
this.hasWseAccount = true;
this.hasTixApiAccess = true;
}
this.playtimeSinceLastAug = 0; this.playtimeSinceLastAug = 0;
this.scriptProdSinceLastAug = 0; this.scriptProdSinceLastAug = 0;
} }
@ -412,6 +401,26 @@ PlayerObject.prototype.getHomeComputer = function() {
return AllServers[this.homeComputer]; return AllServers[this.homeComputer];
} }
PlayerObject.prototype.getUpgradeHomeRamCost = function() {
//Calculate how many times ram has been upgraded (doubled)
const currentRam = Player.getHomeComputer().maxRam;
const numUpgrades = Math.log2(currentRam);
//Calculate cost
//Have cost increase by some percentage each time RAM has been upgraded
const mult = Math.pow(1.58, numUpgrades);
var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult;
return cost;
}
PlayerObject.prototype.receiveInvite = function(factionName) {
if(this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) {
return;
}
this.firstFacInvRecvd = true;
this.factionInvitations.push(factionName);
}
//Calculates skill level based on experience. The same formula will be used for every skill //Calculates skill level based on experience. The same formula will be used for every skill
PlayerObject.prototype.calculateSkill = function(exp) { PlayerObject.prototype.calculateSkill = function(exp) {
return Math.max(Math.floor(32 * Math.log(exp + 534.5) - 200), 1); return Math.max(Math.floor(32 * Math.log(exp + 534.5) - 200), 1);
@ -578,6 +587,9 @@ PlayerObject.prototype.gainHackingExp = function(exp) {
console.log("ERR: NaN passed into Player.gainHackingExp()"); return; console.log("ERR: NaN passed into Player.gainHackingExp()"); return;
} }
this.hacking_exp += exp; this.hacking_exp += exp;
if(this.hacking_exp < 0) {
this.hacking_exp = 0;
}
} }
PlayerObject.prototype.gainStrengthExp = function(exp) { PlayerObject.prototype.gainStrengthExp = function(exp) {
@ -585,6 +597,9 @@ PlayerObject.prototype.gainStrengthExp = function(exp) {
console.log("ERR: NaN passed into Player.gainStrengthExp()"); return; console.log("ERR: NaN passed into Player.gainStrengthExp()"); return;
} }
this.strength_exp += exp; this.strength_exp += exp;
if(this.strength_exp < 0) {
this.strength_exp = 0;
}
} }
PlayerObject.prototype.gainDefenseExp = function(exp) { PlayerObject.prototype.gainDefenseExp = function(exp) {
@ -592,6 +607,9 @@ PlayerObject.prototype.gainDefenseExp = function(exp) {
console.log("ERR: NaN passed into player.gainDefenseExp()"); return; console.log("ERR: NaN passed into player.gainDefenseExp()"); return;
} }
this.defense_exp += exp; this.defense_exp += exp;
if(this.defense_exp < 0) {
this.defense_exp = 0;
}
} }
PlayerObject.prototype.gainDexterityExp = function(exp) { PlayerObject.prototype.gainDexterityExp = function(exp) {
@ -599,6 +617,9 @@ PlayerObject.prototype.gainDexterityExp = function(exp) {
console.log("ERR: NaN passed into Player.gainDexterityExp()"); return; console.log("ERR: NaN passed into Player.gainDexterityExp()"); return;
} }
this.dexterity_exp += exp; this.dexterity_exp += exp;
if(this.dexterity_exp < 0) {
this.dexterity_exp = 0;
}
} }
PlayerObject.prototype.gainAgilityExp = function(exp) { PlayerObject.prototype.gainAgilityExp = function(exp) {
@ -606,6 +627,9 @@ PlayerObject.prototype.gainAgilityExp = function(exp) {
console.log("ERR: NaN passed into Player.gainAgilityExp()"); return; console.log("ERR: NaN passed into Player.gainAgilityExp()"); return;
} }
this.agility_exp += exp; this.agility_exp += exp;
if(this.agility_exp < 0) {
this.agility_exp = 0;
}
} }
PlayerObject.prototype.gainCharismaExp = function(exp) { PlayerObject.prototype.gainCharismaExp = function(exp) {
@ -613,6 +637,9 @@ PlayerObject.prototype.gainCharismaExp = function(exp) {
console.log("ERR: NaN passed into Player.gainCharismaExp()"); return; console.log("ERR: NaN passed into Player.gainCharismaExp()"); return;
} }
this.charisma_exp += exp; this.charisma_exp += exp;
if(this.charisma_exp < 0) {
this.charisma_exp = 0;
}
} }
PlayerObject.prototype.gainIntelligenceExp = function(exp) { PlayerObject.prototype.gainIntelligenceExp = function(exp) {
@ -1525,56 +1552,21 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
var statusText = ""; //TODO, unique message for each crime when you succeed var statusText = ""; //TODO, unique message for each crime when you succeed
if (determineCrimeSuccess(this.crimeType, this.workMoneyGained)) { if (determineCrimeSuccess(this.crimeType, this.workMoneyGained)) {
//Handle Karma and crime statistics //Handle Karma and crime statistics
switch(this.crimeType) { let crime = null;
case CONSTANTS.CrimeShoplift: for(const i in Crimes) {
this.karma -= 0.1; if(Crimes[i].type == this.crimeType) {
crime = Crimes[i];
break; break;
case CONSTANTS.CrimeRobStore: }
this.karma -= 0.5; }
this.gainIntelligenceExp(0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain); if(crime == null) {
break; console.log(this.crimeType);
case CONSTANTS.CrimeMug: dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
this.karma -= 0.25; }
break; this.karma -= crime.karma;
case CONSTANTS.CrimeLarceny: this.numPeopleKilled += crime.kills;
this.karma -= 1.5; if(crime.intelligence_exp > 0) {
this.gainIntelligenceExp(0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain); this.gainIntelligenceExp(crime.intelligence_exp);
break;
case CONSTANTS.CrimeDrugs:
this.karma -= 0.5;
break;
case CONSTANTS.CrimeBondForgery:
this.karma -= 0.1;
this.gainIntelligenceExp(2 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeTraffickArms:
this.karma -= 1;
break;
case CONSTANTS.CrimeHomicide:
++this.numPeopleKilled;
this.karma -= 3;
break;
case CONSTANTS.CrimeGrandTheftAuto:
this.karma -= 5;
this.gainIntelligenceExp(CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeKidnap:
this.karma -= 6;
this.gainIntelligenceExp(2 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeAssassination:
++this.numPeopleKilled;
this.karma -= 10;
this.gainIntelligenceExp(5 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeHeist:
this.karma -= 15;
this.gainIntelligenceExp(10 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
default:
console.log(this.crimeType);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
return;
} }
//On a crime success, gain 2x exp //On a crime success, gain 2x exp
@ -2349,6 +2341,25 @@ PlayerObject.prototype.setBitNodeNumber = function(n) {
this.bitNodeN = n; this.bitNodeN = n;
} }
PlayerObject.prototype.queueAugmentation = function(name) {
for(const i in this.queuedAugmentations) {
if(this.queuedAugmentations[i].name == name) {
console.log('tried to queue '+name+' twice, this may be a bug');
return;
}
}
for(const i in this.augmentations) {
if(this.augmentations[i].name == name) {
console.log('tried to queue '+name+' but we already have that aug');
return;
}
}
this.firstAugPurchased = true;
this.queuedAugmentations.push(new PlayerOwnedAugmentation(name));
}
/* Functions for saving and loading the Player data */ /* Functions for saving and loading the Player data */
function loadPlayer(saveString) { function loadPlayer(saveString) {
Player = JSON.parse(saveString, Reviver); Player = JSON.parse(saveString, Reviver);

@ -2,6 +2,7 @@ import {deleteActiveScriptsItem} from "./ActiveScriptsUI.js";
import {Augmentations, augmentationExists, import {Augmentations, augmentationExists,
initAugmentations, AugmentationNames} from "./Augmentations.js"; initAugmentations, AugmentationNames} from "./Augmentations.js";
import {initBitNodeMultipliers} from "./BitNode.js"; import {initBitNodeMultipliers} from "./BitNode.js";
import {Bladeburner} from "./Bladeburner.js";
import {writeCinematicText} from "./CinematicText.js"; import {writeCinematicText} from "./CinematicText.js";
import {Companies, Company, initCompanies} from "./Company.js"; import {Companies, Company, initCompanies} from "./Company.js";
import {Programs} from "./CreateProgram.js"; import {Programs} from "./CreateProgram.js";
@ -34,6 +35,8 @@ import {createPopup, createElement,
import {yesNoBoxCreate, yesNoBoxGetYesButton, import {yesNoBoxCreate, yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js"; yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js";
let BitNode8StartingMoney = 250e6;
//Prestige by purchasing augmentation //Prestige by purchasing augmentation
function prestigeAugmentation() { function prestigeAugmentation() {
initBitNodeMultipliers(); initBitNodeMultipliers();
@ -123,11 +126,13 @@ function prestigeAugmentation() {
} }
} }
//Reset Bladeburner //Cancel Bladeburner action
Player.bladeburner = null; if (Player.bladeburner instanceof Bladeburner) {
Player.bladeburner.prestige();
}
//BitNode 8: Ghost of Wall Street //BitNode 8: Ghost of Wall Street
if (Player.bitNodeN === 8) {Player.money = new Decimal(100e6);} if (Player.bitNodeN === 8) {Player.money = new Decimal(BitNode8StartingMoney);}
if (Player.bitNodeN === 8 || hasWallStreetSF) { if (Player.bitNodeN === 8 || hasWallStreetSF) {
Player.hasWseAccount = true; Player.hasWseAccount = true;
Player.hasTixApiAccess = true; Player.hasTixApiAccess = true;
@ -305,6 +310,13 @@ function prestigeSourceFile() {
} }
//BitNode 8: Ghost of Wall Street
if (Player.bitNodeN === 8) {Player.money = new Decimal(BitNode8StartingMoney);}
if (Player.bitNodeN === 8 || hasWallStreetSF) {
Player.hasWseAccount = true;
Player.hasTixApiAccess = true;
}
//Gain int exp //Gain int exp
Player.gainIntelligenceExp(5); Player.gainIntelligenceExp(5);
} }

@ -113,7 +113,7 @@ function giveSourceFile(bitNodeNumber) {
} }
if (alreadyOwned && ownedSourceFile) { if (alreadyOwned && ownedSourceFile) {
if (ownedSourceFile.lvl >= 3) { if (ownedSourceFile.lvl >= 3 && ownedSourceFile.n !== 12) {
dialogBoxCreate("The Source-File for the BitNode you just destroyed, " + sourceFile.name + ", " + dialogBoxCreate("The Source-File for the BitNode you just destroyed, " + sourceFile.name + ", " +
"is already at max level!"); "is already at max level!");
} else { } else {
@ -208,7 +208,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
var elemId = "bitnode-" + i.toString(); var elemId = "bitnode-" + i.toString();
var elem = clearEventListeners(elemId); var elem = clearEventListeners(elemId);
if (elem == null) {return;} if (elem == null) {return;}
if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 || i === 6 || i === 8 || i === 11) { if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 || i === 6 || i === 8 || i === 11 || i === 12) {
elem.addEventListener("click", function() { elem.addEventListener("click", function() {
var bitNodeKey = "BitNode" + i; var bitNodeKey = "BitNode" + i;
var bitNode = BitNodes[bitNodeKey]; var bitNode = BitNodes[bitNodeKey];

@ -8,7 +8,8 @@ import {loadFactions, Factions,
processPassiveFactionRepGain} from "./Faction.js"; processPassiveFactionRepGain} from "./Faction.js";
import {FconfSettings, loadFconf} from "./Fconf.js"; import {FconfSettings, loadFconf} from "./Fconf.js";
import {loadAllGangs, AllGangs} from "./Gang.js"; import {loadAllGangs, AllGangs} from "./Gang.js";
import {processAllHacknetNodeEarnings} from "./HacknetNode.js"; import {processAllHacknetNodeEarnings,
createPlayerHacknetNodeWrappers} from "./HacknetNode.js";
import {loadMessages, initMessages, Messages} from "./Message.js"; import {loadMessages, initMessages, Messages} from "./Message.js";
import {Player, loadPlayer} from "./Player.js"; import {Player, loadPlayer} from "./Player.js";
import {loadAllRunningScripts} from "./Script.js"; import {loadAllRunningScripts} from "./Script.js";
@ -227,6 +228,8 @@ function loadGame(saveString) {
} }
} }
//Re-initialize Hacknet Node Wrappers
createPlayerHacknetNodeWrappers();
return true; return true;
} }
@ -443,6 +446,9 @@ function loadImportedGame(saveObj, saveString) {
} }
} }
//Re-initialize Hacknet Node Wrappers
createPlayerHacknetNodeWrappers();
var popupId = "import-game-restart-game-notice"; var popupId = "import-game-restart-game-notice";
var txt = createElement("p", { var txt = createElement("p", {
innerText:"Imported game! I would suggest saving the game and then reloading the page " + innerText:"Imported game! I would suggest saving the game and then reloading the page " +

@ -1,4 +1,5 @@
var ace = require('brace'); var ace = require('brace');
var beautify = require('js-beautify').js_beautify;
require('brace/mode/javascript'); require('brace/mode/javascript');
require('../netscript'); require('../netscript');
require('brace/theme/chaos'); require('brace/theme/chaos');
@ -57,6 +58,15 @@ function scriptEditorInit() {
console.log("Error finding 'script-editor-buttons-wrapper'"); console.log("Error finding 'script-editor-buttons-wrapper'");
return; return;
} }
var beautifyButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerText:"beautify",
clickListener:()=>{
beautifyScript();
return false;
}
});
var closeButton = createElement("a", { var closeButton = createElement("a", {
class:"a-link-button", display:"inline-block", class:"a-link-button", display:"inline-block",
innerText:"Save & Close (Ctrl/Cmd + b)", innerText:"Save & Close (Ctrl/Cmd + b)",
@ -90,6 +100,7 @@ function scriptEditorInit() {
target:"_blank" target:"_blank"
}); });
wrapper.appendChild(beautifyButton);
wrapper.appendChild(closeButton); wrapper.appendChild(closeButton);
wrapper.appendChild(scriptEditorRamText); wrapper.appendChild(scriptEditorRamText);
wrapper.appendChild(scriptEditorRamCheck); wrapper.appendChild(scriptEditorRamCheck);
@ -243,6 +254,13 @@ $(document).keydown(function(e) {
} }
}); });
function beautifyScript() {
var editor = ace.edit('javascript-editor');
var code = editor.getValue();
code = beautify(code, { indent_size: 4 })
editor.setValue(code);
}
function saveAndCloseScriptEditor() { function saveAndCloseScriptEditor() {
var filename = document.getElementById("script-editor-filename").value; var filename = document.getElementById("script-editor-filename").value;
var editor = ace.edit('javascript-editor'); var editor = ace.edit('javascript-editor');
@ -448,6 +466,7 @@ function parseOnlyRamCalculate(server, code, workerScript) {
if (ref == specialReferenceFOR) ram += CONSTANTS.ScriptForRamCost; if (ref == specialReferenceFOR) ram += CONSTANTS.ScriptForRamCost;
if (ref == specialReferenceWHILE) ram += CONSTANTS.ScriptWhileRamCost; if (ref == specialReferenceWHILE) ram += CONSTANTS.ScriptWhileRamCost;
if (ref == "hacknetnodes") ram += CONSTANTS.ScriptHacknetNodesRamCost; if (ref == "hacknetnodes") ram += CONSTANTS.ScriptHacknetNodesRamCost;
if (ref == "document" || ref == "window") ram += CONSTANTS.ScriptDomRamCost;
// Check if this ident is a function in the workerscript env. If it is, then we need to // Check if this ident is a function in the workerscript env. If it is, then we need to
// get its RAM cost. We do this by calling it, which works because the running script // get its RAM cost. We do this by calling it, which works because the running script
@ -508,11 +527,15 @@ function parseOnlyCalculateDeps(code, currentModule) {
s.add(name); // For builtins like hack. s.add(name); // For builtins like hack.
} }
//A list of identifiers that resolve to "native Javascript code"
const objectPrototypeProperties = Object.getOwnPropertyNames(Object.prototype);
// If we discover a dependency identifier, state.key is the dependent identifier. // If we discover a dependency identifier, state.key is the dependent identifier.
// walkDeeper is for doing recursive walks of expressions in composites that we handle. // walkDeeper is for doing recursive walks of expressions in composites that we handle.
function commonVisitors() { function commonVisitors() {
return { return {
Identifier: (node, st, walkDeeper) => { Identifier: (node, st, walkDeeper) => {
if (objectPrototypeProperties.includes(node.name)) {return;}
addRef(st.key, node.name); addRef(st.key, node.name);
}, },
WhileStatement: (node, st, walkDeeper) => { WhileStatement: (node, st, walkDeeper) => {

@ -768,19 +768,31 @@ function initForeignServers() {
} }
} }
function numCycleForGrowth(server, growth) {
let ajdGrowthRate = 1 + (CONSTANTS.ServerBaseGrowthRate - 1) / server.hackDifficulty;
if(ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) {
ajdGrowthRate = CONSTANTS.ServerMaxGrowthRate;
}
const serverGrowthPercentage = server.serverGrowth / 100;
const cycles = Math.log(growth)/(Math.log(ajdGrowthRate)*Player.hacking_grow_mult*serverGrowthPercentage);
return cycles;
}
//Applied server growth for a single server. Returns the percentage growth //Applied server growth for a single server. Returns the percentage growth
function processSingleServerGrowth(server, numCycles) { function processSingleServerGrowth(server, numCycles) {
//Server growth processed once every 450 game cycles //Server growth processed once every 450 game cycles
var numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0); const numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
//Get adjusted growth rate, which accounts for server security //Get adjusted growth rate, which accounts for server security
var growthRate = CONSTANTS.ServerBaseGrowthRate; const growthRate = CONSTANTS.ServerBaseGrowthRate;
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty; var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;} if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
//Calculate adjusted server growth rate based on parameters //Calculate adjusted server growth rate based on parameters
var serverGrowthPercentage = server.serverGrowth / 100; const serverGrowthPercentage = server.serverGrowth / 100;
var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate; const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
//Apply serverGrowth for the calculated number of growth cycles //Apply serverGrowth for the calculated number of growth cycles
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult); var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
@ -789,19 +801,26 @@ function processSingleServerGrowth(server, numCycles) {
serverGrowth = 1; serverGrowth = 1;
} }
var oldMoneyAvailable = server.moneyAvailable; const oldMoneyAvailable = server.moneyAvailable;
server.moneyAvailable *= serverGrowth; server.moneyAvailable *= serverGrowth;
// in case of data corruption
if (server.moneyMax && isNaN(server.moneyAvailable)) { if (server.moneyMax && isNaN(server.moneyAvailable)) {
server.moneyAvailable = server.moneyMax; server.moneyAvailable = server.moneyMax;
} }
// cap at max
if (server.moneyMax && server.moneyAvailable > server.moneyMax) { if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
server.moneyAvailable = server.moneyMax; server.moneyAvailable = server.moneyMax;
return server.moneyAvailable / oldMoneyAvailable;
} }
//Growing increases server security twice as much as hacking // if there was any growth at all, increase security
server.fortify(2 * CONSTANTS.ServerFortifyAmount * numServerGrowthCycles); if(oldMoneyAvailable !== server.moneyAvailable) {
return serverGrowth; //Growing increases server security twice as much as hacking
const usedCycles = numCycleForGrowth(server, server.moneyAvailable / oldMoneyAvailable);
server.fortify(2 * CONSTANTS.ServerFortifyAmount * Math.ceil(usedCycles));
}
return server.moneyAvailable / oldMoneyAvailable;
} }
function prestigeHomeComputer(homeComp) { function prestigeHomeComputer(homeComp) {
@ -873,9 +892,11 @@ function GetServerByHostname(hostname) {
function getServer(s) { function getServer(s) {
if (!isValidIPAddress(s)) { if (!isValidIPAddress(s)) {
return GetServerByHostname(s); return GetServerByHostname(s);
} else { }
if(AllServers[s] !== undefined) {
return AllServers[s]; return AllServers[s];
} }
return null;
} }
//Debugging tool //Debugging tool

@ -7,6 +7,7 @@ let Settings = {
MaxPortCapacity: 50, MaxPortCapacity: 50,
SuppressMessages: false, SuppressMessages: false,
SuppressFactionInvites: false, SuppressFactionInvites: false,
SuppressTravelConfirmation: false,
AutosaveInterval: 60, AutosaveInterval: 60,
DisableHotkeys: false, DisableHotkeys: false,
ThemeHighlightColor: "#ffffff", ThemeHighlightColor: "#ffffff",
@ -26,6 +27,7 @@ function initSettings() {
Settings.MaxPortCapacity = 50; Settings.MaxPortCapacity = 50;
Settings.SuppressMessages = false; Settings.SuppressMessages = false;
Settings.SuppressFactionInvites = false; Settings.SuppressFactionInvites = false;
Settings.SuppressTravelConfirmation = false,
Settings.AutosaveInterval = 60; Settings.AutosaveInterval = 60;
Settings.DisableHotkeys = false; Settings.DisableHotkeys = false;
} }
@ -36,6 +38,7 @@ function setSettingsLabels() {
var nsPortLimit = document.getElementById("settingsNSPortRangeValLabel"); var nsPortLimit = document.getElementById("settingsNSPortRangeValLabel");
var suppressMsgs = document.getElementById("settingsSuppressMessages"); var suppressMsgs = document.getElementById("settingsSuppressMessages");
var suppressFactionInv = document.getElementById("settingsSuppressFactionInvites") var suppressFactionInv = document.getElementById("settingsSuppressFactionInvites")
var suppressTravelConfirmation = document.getElementById("settingsSuppressTravelConfirmation");
var autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel"); var autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel");
var disableHotkeys = document.getElementById("settingsDisableHotkeys"); var disableHotkeys = document.getElementById("settingsDisableHotkeys");
@ -45,6 +48,7 @@ function setSettingsLabels() {
nsPortLimit.innerHTML = Settings.MaxPortCapacity; nsPortLimit.innerHTML = Settings.MaxPortCapacity;
suppressMsgs.checked = Settings.SuppressMessages; suppressMsgs.checked = Settings.SuppressMessages;
suppressFactionInv.checked = Settings.SuppressFactionInvites; suppressFactionInv.checked = Settings.SuppressFactionInvites;
suppressTravelConfirmation.checked = Settings.SuppressTravelConfirmation;
autosaveInterval.innerHTML = Settings.AutosaveInterval; autosaveInterval.innerHTML = Settings.AutosaveInterval;
disableHotkeys.checked = Settings.DisableHotkeys; disableHotkeys.checked = Settings.DisableHotkeys;
@ -91,6 +95,10 @@ function setSettingsLabels() {
Settings.SuppressFactionInvites = this.checked; Settings.SuppressFactionInvites = this.checked;
}; };
suppressTravelConfirmation.onclick = function() {
Settings.SuppressTravelConfirmation = this.checked;
};
disableHotkeys.onclick = function() { disableHotkeys.onclick = function() {
Settings.DisableHotkeys = this.checked; Settings.DisableHotkeys = this.checked;
} }

@ -66,7 +66,7 @@ function initSourceFiles() {
"Level 1: 24%<br>" + "Level 1: 24%<br>" +
"Level 2: 36%<br>" + "Level 2: 36%<br>" +
"Level 3: 42%<br>"); "Level 3: 42%<br>");
SourceFiles["SourceFile12"] = new SourceFile(12); SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File increases all your multipliers by 1% per level");
} }
function PlayerOwnedSourceFile(number, level) { function PlayerOwnedSourceFile(number, level) {
@ -181,6 +181,42 @@ function applySourceFile(srcFile) {
Player.work_money_mult *= incMult; Player.work_money_mult *= incMult;
Player.company_rep_mult *= incMult; Player.company_rep_mult *= incMult;
break; break;
case 12: //The testing ground
const inc = Math.pow(1.01, srcFile.lvl);
const dec = Math.pow(0.99, srcFile.lvl);
Player.hacking_chance_mult *= inc;
Player.hacking_speed_mult *= inc;
Player.hacking_money_mult *= inc;
Player.hacking_grow_mult *= inc;
Player.hacking_mult *= inc;
Player.strength_mult *= inc;
Player.defense_mult *= inc;
Player.dexterity_mult *= inc;
Player.agility_mult *= inc;
Player.charisma_mult *= inc;
Player.hacking_exp_mult *= inc;
Player.strength_exp_mult *= inc;
Player.defense_exp_mult *= inc;
Player.dexterity_exp_mult *= inc;
Player.agility_exp_mult *= inc;
Player.charisma_exp_mult *= inc;
Player.company_rep_mult *= inc;
Player.faction_rep_mult *= inc;
Player.crime_money_mult *= inc;
Player.crime_success_mult *= inc;
Player.hacknet_node_money_mult *= inc;
Player.hacknet_node_purchase_cost_mult *= dec;
Player.hacknet_node_ram_cost_mult *= dec;
Player.hacknet_node_core_cost_mult *= dec;
Player.hacknet_node_level_cost_mult *= dec;
Player.work_money_mult *= inc;
default: default:
console.log("ERROR: Invalid source file number: " + srcFile.n); console.log("ERROR: Invalid source file number: " + srcFile.n);
break; break;

@ -11,7 +11,7 @@ import {clearEventListeners, getRandomInt,
clearEventListenersEl} from "../utils/HelperFunctions.js"; clearEventListenersEl} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate, import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton, yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -703,7 +703,7 @@ function displayStockMarketContent() {
if (!Player.hasWseAccount && Player.money.gte(CONSTANTS.WSEAccountCost)) { if (!Player.hasWseAccount && Player.money.gte(CONSTANTS.WSEAccountCost)) {
wseAccountButton.setAttribute("class", "a-link-button"); wseAccountButton.setAttribute("class", "a-link-button");
} else if (Player.hasWseAccount){ } else if (Player.hasWseAccount){
wseAccountButton.innerText = "WSE Account - acquired"; wseAccountButton.innerText = "WSE Account - Purchased";
wseAccountButton.setAttribute("class", "a-link-button-bought"); wseAccountButton.setAttribute("class", "a-link-button-bought");
} else { } else {
wseAccountButton.setAttribute("class", "a-link-button-inactive"); wseAccountButton.setAttribute("class", "a-link-button-inactive");
@ -724,7 +724,7 @@ function displayStockMarketContent() {
if (!Player.hasTixApiAccess && Player.money.gte(CONSTANTS.TIXAPICost)) { if (!Player.hasTixApiAccess && Player.money.gte(CONSTANTS.TIXAPICost)) {
tixApiAccessButton.setAttribute("class", "a-link-button"); tixApiAccessButton.setAttribute("class", "a-link-button");
} else if(Player.hasTixApiAccess) { } else if(Player.hasTixApiAccess) {
tixApiAccessButton.innerText = "Trade Information eXchange (TIX) API Access - granted" tixApiAccessButton.innerText = "Trade Information eXchange (TIX) API Access - Purchased"
tixApiAccessButton.setAttribute("class", "a-link-button-bought"); tixApiAccessButton.setAttribute("class", "a-link-button-bought");
} else { } else {
tixApiAccessButton.setAttribute("class", "a-link-button-inactive"); tixApiAccessButton.setAttribute("class", "a-link-button-inactive");

@ -3,7 +3,7 @@ import {gameOptionsBoxOpen, gameOptionsBoxClose}from "../utils/GameOptions.js";
import {clearEventListeners, createElement, import {clearEventListeners, createElement,
removeChildrenFromElement, removeChildrenFromElement,
exceptionAlert} from "../utils/HelperFunctions.js"; exceptionAlert} from "../utils/HelperFunctions.js";
import numeral from "../utils/numeral.min.js"; import numeral from "numeral/min/numeral.min";
import {formatNumber, import {formatNumber,
convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js"; convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js";
import {loxBoxCreate, logBoxUpdateText, import {loxBoxCreate, logBoxUpdateText,
@ -12,7 +12,8 @@ import {loxBoxCreate, logBoxUpdateText,
import {updateActiveScriptsItems} from "./ActiveScriptsUI.js"; import {updateActiveScriptsItems} from "./ActiveScriptsUI.js";
import {Augmentations, installAugmentations, import {Augmentations, installAugmentations,
initAugmentations, AugmentationNames, initAugmentations, AugmentationNames,
displayAugmentationsContent} from "./Augmentations.js"; displayAugmentationsContent,
PlayerOwnedAugmentation} from "./Augmentations.js";
import {BitNodes, initBitNodes, import {BitNodes, initBitNodes,
initBitNodeMultipliers} from "./BitNode.js"; initBitNodeMultipliers} from "./BitNode.js";
import {Bladeburner} from "./Bladeburner.js"; import {Bladeburner} from "./Bladeburner.js";
@ -44,13 +45,14 @@ import {updateOnlineScriptTimes,
import {Player} from "./Player.js"; import {Player} from "./Player.js";
import {prestigeAugmentation, import {prestigeAugmentation,
prestigeSourceFile} from "./Prestige.js"; prestigeSourceFile} from "./Prestige.js";
import {redPillFlag} from "./RedPill.js"; import {redPillFlag, hackWorldDaemon} from "./RedPill.js";
import {saveObject, loadGame} from "./SaveObject.js"; import {saveObject, loadGame} from "./SaveObject.js";
import {loadAllRunningScripts, scriptEditorInit, import {loadAllRunningScripts, scriptEditorInit,
updateScriptEditorContent} from "./Script.js"; updateScriptEditorContent} from "./Script.js";
import {AllServers, Server, initForeignServers} from "./Server.js"; import {AllServers, Server, initForeignServers} from "./Server.js";
import {Settings, setSettingsLabels} from "./Settings.js"; import {Settings, setSettingsLabels} from "./Settings.js";
import {initSourceFiles, SourceFiles} from "./SourceFile.js"; import {initSourceFiles, SourceFiles,
PlayerOwnedSourceFile} from "./SourceFile.js";
import {SpecialServerIps, initSpecialServerIps} from "./SpecialServerIps.js"; import {SpecialServerIps, initSpecialServerIps} from "./SpecialServerIps.js";
import {StockMarket, StockSymbols, import {StockMarket, StockSymbols,
SymbolToStockMap, initStockSymbols, SymbolToStockMap, initStockSymbols,
@ -145,6 +147,7 @@ let Engine = {
factionsMainMenuButton: null, factionsMainMenuButton: null,
augmentationsMainMenuButton: null, augmentationsMainMenuButton: null,
tutorialMainMenuButton: null, tutorialMainMenuButton: null,
devMainMenuButton: null,
saveMainMenuButton: null, saveMainMenuButton: null,
deleteMainMenuButton: null, deleteMainMenuButton: null,
@ -158,6 +161,41 @@ let Engine = {
tutorialFactionsButton: null, tutorialFactionsButton: null,
tutorialAugmentationsButton: null, tutorialAugmentationsButton: null,
tutorialBackButton: null, tutorialBackButton: null,
//Dev menu
devMenuGiveMoney: null,
devMenuGiveRam: null,
devMenuAugDropdown: null,
devMenuAddAug: null,
devMenuTriggerBitFlume: null,
devMenuFactionDropdown: null,
devMenuAddFaction: null,
devMenuOpen: null,
devMenuMinSecurity: null,
devMenuMaxMoney: null,
devMenuConnectDropdown: null,
devMenuConnect: null,
devMenuProgramsDropdown: null,
devMenuAddProgram: null,
devMenuHackingExp: null,
devMenuAddHacking: null,
devMenuStrengthExp: null,
devMenuAddStrength: null,
devMenuDefenseExp: null,
devMenuAddDefense: null,
devMenuDexterityExp: null,
devMenuAddDexterity: null,
devMenuAgilityExp: null,
devMenuAddAgility: null,
devMenuCharismaExp: null,
devMenuAddCharisma: null,
devMenuIntelligenceExp: null,
devMenuAddIntelligence: null,
devMenuEnableIntelligence: null,
devMenuDisableIntelligence: null,
devMenuSFN: null,
devMenuSFLvl: null,
devMenuAddSF: null,
}, },
//Display objects //Display objects
@ -183,6 +221,7 @@ let Engine = {
factionAugmentationsContent: null, factionAugmentationsContent: null,
augmentationsContent: null, augmentationsContent: null,
tutorialContent: null, tutorialContent: null,
devMenuContent: null,
infiltrationContent: null, infiltrationContent: null,
stockMarketContent: null, stockMarketContent: null,
locationContent: null, locationContent: null,
@ -208,6 +247,7 @@ let Engine = {
Faction: "Faction", Faction: "Faction",
Augmentations: "Augmentations", Augmentations: "Augmentations",
Tutorial: "Tutorial", Tutorial: "Tutorial",
DevMenu: "Dev Menu",
Location: "Location", Location: "Location",
workInProgress: "WorkInProgress", workInProgress: "WorkInProgress",
RedPill: "RedPill", RedPill: "RedPill",
@ -319,6 +359,14 @@ let Engine = {
document.getElementById("tutorial-menu-link").classList.add("active"); document.getElementById("tutorial-menu-link").classList.add("active");
}, },
loadDevMenuContent: function() {
Engine.hideAllContent();
Engine.Display.devMenuContent.style.display = "block";
Engine.displayDevMenuContent();
Engine.currentPage = Engine.Page.DevMenu;
document.getElementById("dev-menu-link").classList.add("active");
},
loadLocationContent: function() { loadLocationContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
Engine.Display.locationContent.style.display = "block"; Engine.Display.locationContent.style.display = "block";
@ -455,6 +503,7 @@ let Engine = {
Engine.Display.factionAugmentationsContent.style.display = "none"; Engine.Display.factionAugmentationsContent.style.display = "none";
Engine.Display.augmentationsContent.style.display = "none"; Engine.Display.augmentationsContent.style.display = "none";
Engine.Display.tutorialContent.style.display = "none"; Engine.Display.tutorialContent.style.display = "none";
Engine.Display.devMenuContent.style.display = "none";
Engine.Display.locationContent.style.display = "none"; Engine.Display.locationContent.style.display = "none";
Engine.Display.workInProgressContent.style.display = "none"; Engine.Display.workInProgressContent.style.display = "none";
Engine.Display.redPillContent.style.display = "none"; Engine.Display.redPillContent.style.display = "none";
@ -494,6 +543,7 @@ let Engine = {
document.getElementById("city-menu-link").classList.remove("active"); document.getElementById("city-menu-link").classList.remove("active");
document.getElementById("tutorial-menu-link").classList.remove("active"); document.getElementById("tutorial-menu-link").classList.remove("active");
document.getElementById("options-menu-link").classList.remove("active"); document.getElementById("options-menu-link").classList.remove("active");
document.getElementById("dev-menu-link").classList.remove("active");
}, },
displayCharacterOverviewInfo: function() { displayCharacterOverviewInfo: function() {
@ -650,6 +700,7 @@ let Engine = {
//Generic Locations (common to every city): //Generic Locations (common to every city):
// World Stock Exchange // World Stock Exchange
// Corporation (if applicable) // Corporation (if applicable)
// Bladeburner HQ (if applicable);
var genericLocationsList = document.getElementById("generic-locations-list"); var genericLocationsList = document.getElementById("generic-locations-list");
genericLocationsList.style.display = "inline"; genericLocationsList.style.display = "inline";
removeChildrenFromElement(genericLocationsList); removeChildrenFromElement(genericLocationsList);
@ -676,6 +727,18 @@ let Engine = {
})); }));
genericLocationsList.appendChild(li); genericLocationsList.appendChild(li);
} }
if (Player.bladeburner instanceof Bladeburner) {
var li = createElement("li");
li.appendChild(createElement("a", {
innerText:"Bladeburner Headquarters", class:"a-link-button",
clickListener:()=>{
Engine.loadBladeburnerContent();
return false;
}
}));
genericLocationsList.appendChild(li);
}
}, },
displayFactionsInfo: function() { displayFactionsInfo: function() {
@ -771,6 +834,43 @@ let Engine = {
document.getElementById("tutorial-text").style.display = "none"; document.getElementById("tutorial-text").style.display = "none";
}, },
displayDevMenuContent: function() {
Engine.Clickables.devMenuGiveMoney.style.display = "block";
Engine.Clickables.devMenuGiveRam.style.display = "block";
Engine.Clickables.devMenuAugDropdown.style.display = "block";
Engine.Clickables.devMenuAddAug.style.display = "block";
Engine.Clickables.devMenuTriggerBitFlume.style.display = "block";
Engine.Clickables.devMenuFactionDropdown.style.display = "block";
Engine.Clickables.devMenuAddFaction.style.display = "block";
Engine.Clickables.devMenuOpen.style.display = "block";
Engine.Clickables.devMenuMinSecurity.style.display = "block";
Engine.Clickables.devMenuMaxMoney.style.display = "block";
Engine.Clickables.devMenuConnectDropdown.style.display = "block";
Engine.Clickables.devMenuConnect.style.display = "block";
Engine.Clickables.devMenuProgramsDropdown.style.display = "block";
Engine.Clickables.devMenuAddProgram.style.display = "block";
Engine.Clickables.devMenuHackingExp.style.display = "block";
Engine.Clickables.devMenuAddHacking.style.display = "block";
Engine.Clickables.devMenuStrengthExp.style.display = "block";
Engine.Clickables.devMenuAddStrength.style.display = "block";
Engine.Clickables.devMenuDefenseExp.style.display = "block";
Engine.Clickables.devMenuAddDefense.style.display = "block";
Engine.Clickables.devMenuDexterityExp.style.display = "block";
Engine.Clickables.devMenuAddDexterity.style.display = "block";
Engine.Clickables.devMenuAgilityExp.style.display = "block";
Engine.Clickables.devMenuAddAgility.style.display = "block";
Engine.Clickables.devMenuCharismaExp.style.display = "block";
Engine.Clickables.devMenuAddCharisma.style.display = "block";
Engine.Clickables.devMenuIntelligenceExp.style.display = "block";
Engine.Clickables.devMenuAddIntelligence.style.display = "block";
Engine.Clickables.devMenuEnableIntelligence.style.display = "block";
Engine.Clickables.devMenuDisableIntelligence.style.display = "block";
Engine.Clickables.devMenuSFN.style.display = "block";
Engine.Clickables.devMenuSFLvl.style.display = "block";
Engine.Clickables.devMenuAddSF.style.display = "block";
},
//Displays the text when a section of the Tutorial is opened //Displays the text when a section of the Tutorial is opened
displayTutorialPage: function(text) { displayTutorialPage: function(text) {
document.getElementById("tutorial-getting-started-link").style.display = "none"; document.getElementById("tutorial-getting-started-link").style.display = "none";
@ -1169,6 +1269,7 @@ let Engine = {
var job = document.getElementById("job-tab"); var job = document.getElementById("job-tab");
var tutorial = document.getElementById("tutorial-tab"); var tutorial = document.getElementById("tutorial-tab");
var options = document.getElementById("options-tab"); var options = document.getElementById("options-tab");
var dev = document.getElementById("dev-tab");
//Load game from save or create new game //Load game from save or create new game
if (loadGame(saveString)) { if (loadGame(saveString)) {
@ -1245,7 +1346,7 @@ let Engine = {
formatNumber(offlineProductionFromHacknetNodes, 2)); formatNumber(offlineProductionFromHacknetNodes, 2));
//Close main menu accordions for loaded game //Close main menu accordions for loaded game
var visibleMenuTabs = [terminal, createScript, activeScripts, stats, var visibleMenuTabs = [terminal, createScript, activeScripts, stats,
hacknetnodes, city, tutorial, options]; hacknetnodes, city, tutorial, options, dev];
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);} if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
else {factions.style.display = "none";} else {factions.style.display = "none";}
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);} if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
@ -1299,7 +1400,7 @@ let Engine = {
Engine.openMainMenuHeader( Engine.openMainMenuHeader(
[terminal, createScript, activeScripts, stats, [terminal, createScript, activeScripts, stats,
hacknetnodes, city, hacknetnodes, city,
tutorial, options] tutorial, options, dev]
); );
//Start interactive tutorial //Start interactive tutorial
@ -1352,6 +1453,9 @@ let Engine = {
Engine.Display.tutorialContent = document.getElementById("tutorial-container"); Engine.Display.tutorialContent = document.getElementById("tutorial-container");
Engine.Display.tutorialContent.style.display = "none"; Engine.Display.tutorialContent.style.display = "none";
Engine.Display.devMenuContent = document.getElementById("dev-menu-container");
Engine.Display.devMenuContent.style.display = "none";
Engine.Display.infiltrationContent = document.getElementById("infiltration-container"); Engine.Display.infiltrationContent = document.getElementById("infiltration-container");
Engine.Display.infiltrationContent.style.display = "none"; Engine.Display.infiltrationContent.style.display = "none";
@ -1439,9 +1543,195 @@ let Engine = {
Engine.displayTutorialContent(); Engine.displayTutorialContent();
}); });
// dev menu buttons
Engine.Clickables.devMenuGiveMoney = document.getElementById("dev-need-money");
Engine.Clickables.devMenuGiveMoney.addEventListener("click", function() {
Player.gainMoney(1e15);
});
Engine.Clickables.devMenuGiveRam = document.getElementById("dev-need-ram");
Engine.Clickables.devMenuGiveRam.addEventListener("click", function() {
Player.getHomeComputer().maxRam *= 2;
});
Engine.Clickables.devMenuAugDropdown = document.getElementById("dev-menu-aug-dropdown");
const augDD = Engine.Clickables.devMenuAugDropdown;
for(const i in AugmentationNames) {
augDD.options[augDD.options.length] = new Option(AugmentationNames[i], AugmentationNames[i]);
}
Engine.Clickables.devMenuAddAug = document.getElementById("dev-add-aug");
Engine.Clickables.devMenuAddAug.addEventListener("click", function() {
Player.queueAugmentation(augDD.options[augDD.selectedIndex].value);
});
Engine.Clickables.devMenuTriggerBitFlume = document.getElementById("dev-bit-flume");
Engine.Clickables.devMenuTriggerBitFlume.addEventListener("click", function() {
hackWorldDaemon(Player.bitNodeN, true);
});
Engine.Clickables.devMenuFactionDropdown = document.getElementById("dev-menu-faction-dropdown");
const facDD = Engine.Clickables.devMenuFactionDropdown;
for(const i in Factions) {
facDD.options[facDD.options.length] = new Option(Factions[i].name, Factions[i].name);
}
Engine.Clickables.devMenuAddFaction = document.getElementById("dev-add-faction");
Engine.Clickables.devMenuAddFaction.addEventListener("click", function() {
const factionName = facDD.options[facDD.selectedIndex].value;
Player.receiveInvite(factionName);
});
Engine.Clickables.devMenuOpen = document.getElementById("dev-open-all");
Engine.Clickables.devMenuOpen.addEventListener("click", function() {
for(const i in AllServers) {
AllServers[i].hasAdminRights = true;
AllServers[i].sshPortOpen = true;
AllServers[i].ftpPortOpen = true;
AllServers[i].smtpPortOpen = true;
AllServers[i].httpPortOpen = true;
AllServers[i].sqlPortOpen = true;
AllServers[i].openPortCount = 5;
}
});
Engine.Clickables.devMenuMinSecurity = document.getElementById("dev-min-security");
Engine.Clickables.devMenuMinSecurity.addEventListener("click", function() {
for(const i in AllServers) {
AllServers[i].hackDifficulty = AllServers[i].minDifficulty;
}
});
Engine.Clickables.devMenuMaxMoney = document.getElementById("dev-max-money");
Engine.Clickables.devMenuMaxMoney.addEventListener("click", function() {
for(const i in AllServers) {
AllServers[i].moneyAvailable = AllServers[i].moneyMax;
}
});
Engine.Clickables.devMenuConnectDropdown = document.getElementById("dev-menu-connect-dropdown");
const connectDD = Engine.Clickables.devMenuConnectDropdown;
for(const i in AllServers) {
connectDD.options[connectDD.options.length] = new Option(AllServers[i].hostname, AllServers[i].hostname);
}
Engine.Clickables.devMenuConnect = document.getElementById("dev-connect");
Engine.Clickables.devMenuConnect.addEventListener("click", function() {
const host = connectDD.options[connectDD.selectedIndex].value;
Terminal.connectToServer(host);
});
Engine.Clickables.devMenuProgramsDropdown = document.getElementById("dev-menu-add-program-dropdown");
const programsDD = Engine.Clickables.devMenuProgramsDropdown;
for(const i in Programs) {
programsDD.options[programsDD.options.length] = new Option(Programs[i], Programs[i]);
}
Engine.Clickables.devMenuAddProgram = document.getElementById("dev-add-program");
Engine.Clickables.devMenuAddProgram.addEventListener("click", function() {
const program = programsDD.options[programsDD.selectedIndex].value;;
if(!Player.hasProgram(program)) {
Player.getHomeComputer().programs.push(program);
}
});
Engine.Clickables.devMenuHackingExp = document.getElementById("dev-hacking-exp");
Engine.Clickables.devMenuAddHacking = document.getElementById("dev-add-hacking");
Engine.Clickables.devMenuAddHacking.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuHackingExp.value);
Player.gainHackingExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuStrengthExp = document.getElementById("dev-strength-exp");
Engine.Clickables.devMenuAddStrength = document.getElementById("dev-add-strength");
Engine.Clickables.devMenuAddStrength.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuStrengthExp.value);
Player.gainStrengthExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuDefenseExp = document.getElementById("dev-defense-exp");
Engine.Clickables.devMenuAddDefense = document.getElementById("dev-add-defense");
Engine.Clickables.devMenuAddDefense.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuDefenseExp.value);
Player.gainDefenseExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuDexterityExp = document.getElementById("dev-dexterity-exp");
Engine.Clickables.devMenuAddDexterity = document.getElementById("dev-add-dexterity");
Engine.Clickables.devMenuAddDexterity.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuDexterityExp.value);
Player.gainDexterityExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuAgilityExp = document.getElementById("dev-agility-exp");
Engine.Clickables.devMenuAddAgility = document.getElementById("dev-add-agility");
Engine.Clickables.devMenuAddAgility.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuAgilityExp.value);
Player.gainAgilityExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuCharismaExp = document.getElementById("dev-charisma-exp");
Engine.Clickables.devMenuAddCharisma = document.getElementById("dev-add-charisma");
Engine.Clickables.devMenuAddCharisma.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuCharismaExp.value);
Player.gainCharismaExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuIntelligenceExp = document.getElementById("dev-intelligence-exp");
Engine.Clickables.devMenuAddIntelligence = document.getElementById("dev-add-intelligence");
Engine.Clickables.devMenuAddIntelligence.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuIntelligenceExp.value);
Player.gainIntelligenceExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuEnableIntelligence = document.getElementById("dev-enable-intelligence");
Engine.Clickables.devMenuEnableIntelligence.addEventListener("click", function() {
Player.intelligence = 1;
});
Engine.Clickables.devMenuDisableIntelligence = document.getElementById("dev-disable-intelligence");
Engine.Clickables.devMenuDisableIntelligence.addEventListener("click", function() {
Player.intelligence = 0;
});
Engine.Clickables.devMenuSFN = document.getElementById("dev-sf-n");
Engine.Clickables.devMenuSFLvl = document.getElementById("dev-sf-lvl");
Engine.Clickables.devMenuAddSF = document.getElementById("dev-add-source-file");
Engine.Clickables.devMenuAddSF.addEventListener("click", function() {
const sfN = parseInt(Engine.Clickables.devMenuSFN.value);
const sfLvl = parseInt(Engine.Clickables.devMenuSFLvl.value);
let sfIndex = -1;
for(const i in Player.sourceFiles) {
if(Player.sourceFiles[i].n === sfN) {
sfIndex = i;
break;
}
}
if(sfIndex === -1) { // add fresh source file
Player.sourceFiles.push(new PlayerOwnedSourceFile(sfN, sfLvl));
} else if(sfLvl === 0) { // remove a source file.
if(sfIndex === -1) { // doesn't have it anyway.
return;
}
Player.sourceFiles.splice(sfIndex, 1);
} else { // set source file level
Player.sourceFiles[sfIndex].lvl=sfLvl;
}
});
//If DarkWeb already purchased, disable the button //If DarkWeb already purchased, disable the button
if (SpecialServerIps.hasOwnProperty("Darkweb Server")) { if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button-inactive"); const purchaseTor = document.getElementById("location-purchase-tor");
purchaseTor.setAttribute("class", "a-link-button-bought");
purchaseTor.innerHTML = "TOR Router - Purchased";
} }
}, },
@ -1536,16 +1826,16 @@ let Engine = {
var options = document.getElementById("options-tab"); var options = document.getElementById("options-tab");
var optionsLink = document.getElementById("options-menu-link"); var optionsLink = document.getElementById("options-menu-link");
this.classList.toggle("opened"); this.classList.toggle("opened");
const elems = [tutorial, options];
const links = [tutorialLink, optionsLink];
if(process.env.NODE_ENV === "development") {
elems.push(document.getElementById("dev-tab"));
links.push(document.getElementById("dev-menu-link"));
}
if (tutorial.style.maxHeight) { if (tutorial.style.maxHeight) {
Engine.toggleMainMenuHeader(false, Engine.toggleMainMenuHeader(false, elems, links);
[tutorial, options],
[tutorialLink, optionsLink]
);
} else { } else {
Engine.toggleMainMenuHeader(true, Engine.toggleMainMenuHeader(true, elems, links);
[tutorial, options],
[tutorialLink, optionsLink]
);
} }
} }
@ -1623,6 +1913,12 @@ let Engine = {
return false; return false;
}); });
Engine.Clickables.devMainMenuButton = clearEventListeners("dev-menu-link");
Engine.Clickables.devMainMenuButton.addEventListener("click", function() {
Engine.loadDevMenuContent();
return false;
});
//Active scripts list //Active scripts list
Engine.ActiveScriptsList = document.getElementById("active-scripts-list"); Engine.ActiveScriptsList = document.getElementById("active-scripts-list");

@ -1,4 +1,5 @@
import {executeJSScript} from "../src/NetscriptJSEvaluator.js"; import {executeJSScript} from "../src/NetscriptJSEvaluator.js";
import {WorkerScript} from "../src/NetscriptWorker.js";
const chai = require("chai"); const chai = require("chai");
const chaiAsPromised = require("chai-as-promised"); const chaiAsPromised = require("chai-as-promised");
@ -9,17 +10,19 @@ console.info('asdf');
describe('NSJS ScriptStore', function() { describe('NSJS ScriptStore', function() {
it('should run an imported function', async function() { it('should run an imported function', async function() {
const s = { filename: "", code: "export function main() { return 2; }" }; const s = { filename: "", code: "export function main() { return 2; }", args:[]};
chai.expect(await executeJSScript(s)).to.equal(2); const worker = new WorkerScript(s);
chai.expect(await executeJSScript([], s)).to.equal(2);
}); });
/*
it('should handle recursive imports', async function() { it('should handle recursive imports', async function() {
const s1 = { filename: "s1.js", code: "export function iAmRecursiveImport(x) { return x + 2; }" }; const s1 = { filename: "s1.js", code: "export function iAmRecursiveImport(x) { return x + 2; }" };
const s2 = { filename: "", code: ` const s2 = { filename: "", code: `
import {iAmRecursiveImport} from \"s1.js\"; import {iAmRecursiveImport} from \"s1.js\";
export function main() { return iAmRecursiveImport(3); export function main() { return iAmRecursiveImport(3);
}`}; }`};
chai.expect(await executeJSScript(s2, [s1, s2])).to.equal(5); chai.expect(await executeJSScript([s1, s2], s2)).to.equal(5);
}); });
it (`should correctly reference the passed global env`, async function() { it (`should correctly reference the passed global env`, async function() {
@ -45,5 +48,5 @@ describe('NSJS ScriptStore', function() {
export function main() {} export function main() {}
`} `}
executeJSScript(s2, [s1, s2]).should.eventually.throw(); executeJSScript(s2, [s1, s2]).should.eventually.throw();
}); });*/
}); });

@ -11,7 +11,7 @@
<script src="https://unpkg.com/mocha@4.0.1/mocha.js"></script> <script src="https://unpkg.com/mocha@4.0.1/mocha.js"></script>
<script>mocha.setup('bdd')</script> <script>mocha.setup('bdd')</script>
<script type="module" src="../dist/tests.bundle.js"></script> <script type="module" src="tests.bundle.js"></script>
<script type="module"> <script type="module">
mocha.checkLeaks(); mocha.checkLeaks();
mocha.run(); mocha.run();

@ -74,6 +74,21 @@ function removeChildrenFromElement(el) {
} }
} }
/**
* Returns a reference to the first object with the specified value of the ID or NAME attribute, throwing an error if it is unable to find it.
* @param {string} elementId The HTML ID to retrieve the element by.
* @returns {HTMLElement} The single element.
* @throws {Error} When the 'idString' cannot be found.
*/
function getElementById(elementId) {
var el = document.getElementById(elementId);
if (el == null) {
throw new Error("Unable to find element with id '" + elementId + "'");
}
return el;
}
function createElement(type, params={}) { function createElement(type, params={}) {
var el = document.createElement(type); var el = document.createElement(type);
if (params.id) {el.id = params.id;} if (params.id) {el.id = params.id;}
@ -260,4 +275,4 @@ export {sizeOfObject, clearObject, addOffset, clearEventListeners, getRandomInt,
removeElementById, removeElement, createElement, createAccordionElement, removeElementById, removeElement, createElement, createAccordionElement,
appendLineBreaks, appendLineBreaks,
removeChildrenFromElement, createPopup, clearSelector, exceptionAlert, removeChildrenFromElement, createPopup, clearSelector, exceptionAlert,
createProgressBarText}; createProgressBarText, getElementById};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,37 +1,34 @@
var path = require('path'); var path = require('path');
var webpack = require('webpack'); var webpack = require('webpack');
module.exports = { module.exports = (env, argv) => ({
mode: "development", //mode: "development",
plugins: [ plugins: [
// http://stackoverflow.com/questions/29080148/expose-jquery-to-real-window-object-with-webpack new webpack.DefinePlugin({
new webpack.ProvidePlugin({ 'process.env.NODE_ENV': argv.mode === 'development' ? "\"development\"" : "\"production\""
// Automtically detect jQuery and $ as free var in modules }),
// and inject the jquery library // http://stackoverflow.com/questions/29080148/expose-jquery-to-real-window-object-with-webpack
// This is required by many jquery plugins new webpack.ProvidePlugin({
jquery: "jquery", // Automtically detect jQuery and $ as free var in modules
jQuery: "jquery", // and inject the jquery library
$: "jquery" // This is required by many jquery plugins
}), jquery: "jquery",
jQuery: "jquery",
$: "jquery"
})
], ],
target: "web", target: "web",
entry: { entry: {
engine: "./src/engine.js", "dist/engine": "./src/engine.js",
tests: "./tests/index.js", "tests/tests": "./tests/index.js",
}, },
devtool: "nosources-source-map", devtool: "source-map",
output: { output: {
path: path.resolve(__dirname, "dist"), path: path.resolve(__dirname, "./"),
filename: "[name].bundle.js", filename: "[name].bundle.js"
devtoolModuleFilenameTemplate: "[id]"
}, },
module: { module: {
rules: [ rules: []
/* {
test: /\.css$/,
use: "style!css"
}*/
]
}, },
optimization: { optimization: {
removeAvailableModules: true, removeAvailableModules: true,
@ -51,4 +48,4 @@ module.exports = {
devServer: { devServer: {
publicPath: "/dist", publicPath: "/dist",
} }
}; });