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
/node_modules
/dist/*.map
/tests/*.map
/tests/*.bundle.*

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

@ -288,30 +288,44 @@
}
#hacknet-nodes-text,
#hacknet-nodes-money,
#hacknet-nodes-container li {
width: 70%;
margin: 10px;
padding: 10px;
}
#hacknet-nodes-purchase-button {
display: inline-block;
#hacknet-nodes-container li {
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 {
display: inline-block;
width: 70%;
width: 70vw;
}
#hacknet-nodes-multipliers {
float: right;
}
#hacknet-nodes-purchase-button {
display: inline-block;
}
.hacknet-node {
margin: 6px;
padding: 6px;
width: 85%;
width: 34vw;
border: 2px solid var(--my-highlight-color);
-webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.1),
@ -324,12 +338,28 @@
0 0 16px rgba(0,0,0,0.1);
}
.hacknet-node-button-div a {
display: block;
.hacknet-node-container {
display: inline-table;
}
.hacknet-node-button-div:not(:last-child) {
border-bottom: none;
.hacknet-node-container .row {
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 */
@ -456,6 +486,21 @@
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-container {
position: fixed;

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

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

@ -50,8 +50,43 @@
<div class="section" id="changelog">
<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">
<h2>v0.37.1<a class="headerlink" href="#v0-37-1" title="Permalink to this headline"></a></h2>
<div class="section" id="v0-38-0-6-12-2018">
<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">
<li>You now earn money from successfully completing Bladeburner contracts. The amount you earn is based
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="shortcuts.html"> Keyboard Shortcuts</a></li>
<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-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>

@ -326,6 +326,8 @@
<li><a href="netscriptfunctions.html#print">print() (built-in function)</a>
</li>
<li><a href="netscriptfunctions.html#prompt">prompt() (built-in function)</a>
</li>
<li><a href="netscriptfunctions.html#ps">ps() (built-in function)</a>
</li>
</ul></td>
<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#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#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#gethostname">getHostname</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>
</li>
<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-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>

@ -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#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#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#gethostname">getHostname</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 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="changelog.html"> Changelog</a></li>
</ul>
<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>
</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 class="section" id="hasrootaccess">
<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="#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="#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="#gethostname">getHostname</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 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="changelog.html"> Changelog</a></li>
</ul>
<div role="search">

@ -52,7 +52,7 @@
<div class="body" role="main">
<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
allows users to write (almost) full-fledged Javascript code in their scripts, while
still being able to access the Netscript functions.</p>
@ -278,6 +278,7 @@ NetscriptJS and report any serious exploits.</p>
</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="changelog.html"> Changelog</a></li>
</ul>
<div role="search">

Binary file not shown.

File diff suppressed because one or more lines are too long

@ -3,8 +3,49 @@
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
on the difficulty of the contract.
* 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
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
^^^^^^^^^^^^^

@ -1,3 +1,5 @@
.. _netscriptjs:
NetscriptJS (Netscript 2.0)
===========================
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>
<meta charset="utf-8">
<title>Bitburner</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
<link rel="manifest" href="dist/site.webmanifest">
<link rel="mask-icon" href="dist/safari-pinned-tab.svg" color="#000000">
<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/terminal.css" />
<link rel="stylesheet" type="text/css" href="css/menupages.css" />
@ -23,7 +34,6 @@
ga('create', 'UA-100157497-1', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>
@ -89,6 +99,9 @@
<li id="options-tab" class="mainmenu-accordion-panel">
<a id="options-menu-link"> Options </a>
</li>
<li id="dev-tab" class="mainmenu-accordion-panel">
<a id="dev-menu-link"> Dev </a>
</li>
</ul>
</div>
@ -97,7 +110,7 @@
<div id="script-editor-filename-wrapper">
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"> </input>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
</div>
<div id="javascript-editor"></div>
@ -147,9 +160,7 @@
<fieldset>
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
<input type="range" max="1000" min="50" value="200"
step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"
</input>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr" />
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset>
</div> <!-- End script editor options panel -->
@ -160,8 +171,7 @@
<table id="terminal">
<tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"
onfocus="this.value = this.value;"/>
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
</td>
</tr>
</table>
@ -185,7 +195,7 @@
<!-- Hacknet Nodes -->
<div id="hacknet-nodes-container" class="generic-menupage-container">
<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 world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced.
@ -199,8 +209,11 @@
</p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br>
<div id="hacknet-nodes-money-multipliers-div">"
<p id="hacknet-nodes-money"> </p>
<div id="hacknet-nodes-money-multipliers-div">
<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">
<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>
@ -208,7 +221,7 @@
<a id="hacknet-nodes-max-multiplier" class="a-link-button"> MAX </a>
</span>
</div>
<ul id="hacknet-nodes-list" style="list-style : none;">
<ul id="hacknet-nodes-list">
</ul>
</div>
@ -473,6 +486,58 @@
<p id="tutorial-text"> </p>
</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) -->
<div id="location-container" class="generic-menupage-container">
<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-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"> </p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30"> </input>
<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-no" class="popup-box-button"> No </span>
</div>
@ -744,9 +809,7 @@
</span>
</label>
<input type ="range" max="250" min="15"
step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="100">
</input>
<input type ="range" max="250" min="15" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="100" />
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -760,9 +823,7 @@
</span>
</label>
<input type="range" max="100" min="20"
step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50">
</input>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -776,9 +837,7 @@
</span>
</label>
<input type="range" max="100" min="20"
step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50">
</input>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset>
@ -790,9 +849,7 @@
</span>
</label>
<input type="range" max="600" min="0"
step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60">
</input>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset>
@ -819,6 +876,16 @@
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</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 -->
<fieldset>
<label for="settingsDisableHotkeys" class="tooltip">Disable Hotkeys:
@ -843,7 +910,7 @@
<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" 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="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>
@ -872,6 +939,6 @@
<div class="loaderspinner"></div>
<div class="loaderlabel">Loading Bitburner...</div>
</div>
</body>
<script src="dist/engine.bundle.js"></script>
</body>
</html>

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

@ -9,7 +9,7 @@ import {printArray, createElement,
createAccordionElement, removeElement,
removeChildrenFromElement, exceptionAlert} from "../utils/HelperFunctions.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";
/* {

@ -184,6 +184,7 @@ let AugmentationNames = {
BladeArmorUnibeam: "BLADE-51b Tesla Armor: Unibeam Upgrade",
BladeArmorOmnibeam: "BLADE-51b Tesla Armor: Omnibeam Upgrade",
BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade",
BladesSimulacrum: "The Blade's Simulacrum",
//Wasteland Augs
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System
@ -1552,7 +1553,7 @@ function initAugmentations() {
var BladeburnersFactionName = "Bladeburners";
if (factionExists(BladeburnersFactionName)) {
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 " +
"for Bladeburner units. This " +
"is implanted by installing a mechanical frame in the skull's orbit. " +
@ -1569,7 +1570,7 @@ function initAugmentations() {
resetAugmentation(EsperEyewear);
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 " +
"technique was originally used on Bladeburners during the Synthoid uprising " +
"to induce wakefulness and concentration, suppress fear, reduce empathy, and " +
@ -1583,7 +1584,7 @@ function initAugmentations() {
resetAugmentation(EMS4Recombination);
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, " +
"the ORION-MKIV shoulder enhances the strength and dexterity " +
"of the user's right arm. It also provides protection due to its " +
@ -1597,7 +1598,7 @@ function initAugmentations() {
resetAugmentation(OrionShoulder);
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 " +
"of rapidly firing bolts of high-density plasma. The weapon is meant to " +
"be used against augmented enemies as the ionized " +
@ -1611,7 +1612,7 @@ function initAugmentations() {
resetAugmentation(HyperionV1);
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 " +
"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 " +
@ -1624,7 +1625,7 @@ function initAugmentations() {
resetAugmentation(HyperionV2);
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, " +
"including strength, speed, immune system performance, and mitochondrial efficiency. The " +
"serum was originally developed by the Chinese military in an attempt to " +
@ -1637,7 +1638,7 @@ function initAugmentations() {
resetAugmentation(GolemSerum);
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 " +
"heightens the senses and focus of its host, and also enhances its intuition.<br><br>" +
"This augmentation:<br>" +
@ -1649,7 +1650,7 @@ function initAugmentations() {
resetAugmentation(VangelisVirus);
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 " +
"injected into the human brain tissue. On top of the benefits of the original " +
"virus, this also grants an accelerated healing factor and enhanced " +
@ -1664,7 +1665,7 @@ function initAugmentations() {
resetAugmentation(VangelisVirus3);
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 " +
"extracellular matrix (ECM). This improves the ECM's ability to " +
"structurally support the body and grants heightened strength and " +
@ -1677,7 +1678,7 @@ function initAugmentations() {
resetAugmentation(INTERLINKED);
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 " +
"during the Synthoid Uprising. The organic musculature of the human foot " +
"is enhanced with flexible carbon nanotube matrices that are controlled by " +
@ -1691,7 +1692,7 @@ function initAugmentations() {
resetAugmentation(BladeRunner);
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 " +
"exoskeleton is incredibly adaptable and can protect the wearer from blunt, piercing, " +
"concussive, thermal, chemical, and electric trauma. It also enhances the user's " +
@ -1705,7 +1706,7 @@ function initAugmentations() {
resetAugmentation(BladeArmor);
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 " +
"more efficiently storing and using power.<br><br>" +
"This augmentation:<br>" +
@ -1718,7 +1719,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorPowerCells);
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 " +
"that is capable of projecting an energy shielding force field.<br><br>" +
"This augmentation:<br>" +
@ -1730,7 +1731,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorEnergyShielding);
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 " +
"weapon. It's precision an accuracy makes it useful for quickly neutralizing " +
"threats while keeping casualties to a minimum.<br><br>" +
@ -1742,7 +1743,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorUnibeam);
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 " +
"multiple-fiber system. The upgraded weapon uses multiple fiber laser " +
"modules that combine together to form a single, more powerful beam of up to " +
@ -1755,7 +1756,7 @@ function initAugmentations() {
resetAugmentation(BladeArmorOmnibeam);
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 " +
"Unit that was specially designed to analyze Synthoid related data and " +
"information.<br><br>" +
@ -1766,6 +1767,19 @@ function initAugmentations() {
});
BladeArmorIPU.addToFactions([BladeburnersFactionName]);
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
@ -1777,8 +1791,6 @@ function initAugmentations() {
}
Player.reapplyAllAugmentations();
}
//Resets an Augmentation during (re-initizliation)
@ -2350,6 +2362,8 @@ function applyAugmentation(aug, reapply=false) {
Player.bladeburner_analysis_mult *= 1.15;
Player.bladeburner_success_chance_mult *= 1.02;
break;
case AugmentationNames.BladesSimulacrum: //No multiplier effect
break;
default:
throw new Error("ERROR: No such augmentation!");
return;
@ -2594,8 +2608,9 @@ function displaySourceFiles(listElement, sourceFiles) {
console.log("ERROR: Invalid source file number: " + sourceFiles[i].n);
continue;
}
const maxLevel = sourceFiles[i].n == 12 ? "∞" : "3";
var accordion = createAccordionElement({
hdrText:sourceFileObject.name + "<br>" + "Level " + (sourceFiles[i].lvl) + " / 3",
hdrText:sourceFileObject.name + "<br>" + "Level " + (sourceFiles[i].lvl) + " / "+maxLevel,
panelText:sourceFileObject.info
});

@ -54,7 +54,7 @@ function initBitNodes() {
"The starting and maximum amount of money on servers is reduced by 75%<br>" +
"Server growth rate is reduced by 80%<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 " +
"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>" +
@ -156,10 +156,13 @@ function initBitNodes() {
"Level 1: 24%<br>" +
"Level 2: 36%<br>" +
"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
BitNodes["BitNode12"] = new BitNode(12, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode13"] = new BitNode(13, "", "COMING SOON");
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON");
@ -232,10 +235,10 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.RepToDonateToFaction = 0.5;
BitNodeMultipliers.AugmentationRepCost = 3;
BitNodeMultipliers.AugmentationMoneyCost = 3;
BitNodeMultipliers.ServerMaxMoney = 0.25;
BitNodeMultipliers.ServerStartingMoney = 0.25;
BitNodeMultipliers.ServerGrowthRate = 0.20;
BitNodeMultipliers.ScriptHackMoney = 0.25;
BitNodeMultipliers.ServerMaxMoney = 0.2;
BitNodeMultipliers.ServerStartingMoney = 0.2;
BitNodeMultipliers.ServerGrowthRate = 0.2;
BitNodeMultipliers.ScriptHackMoney = 0.2;
BitNodeMultipliers.CompanyWorkMoney = 0.25;
BitNodeMultipliers.CrimeMoney = 0.25;
BitNodeMultipliers.HacknetNodeMoney = 0.25;
@ -304,10 +307,56 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.InfiltrationRep = 2.5;
BitNodeMultipliers.CorporationValuation = 0.01;
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:
console.log("WARNING: Player.bitNodeN invalid");
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 {Engine} from "./engine.js";
import {Faction, Factions, factionExists,
joinFaction, displayFactionContent} from "./Faction.js";
import {Locations} from "./Location.js";
import {Player} from "./Player.js";
import {hackWorldDaemon} from "./RedPill.js";
import {hackWorldDaemon, redPillFlag} from "./RedPill.js";
import {KEY} from "./Terminal.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
@ -15,7 +16,7 @@ import {getRandomInt, addOffset, clearObject,
createProgressBarText} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON,
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";
@ -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
//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
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
@ -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 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 OperationSuccessesPerLevel = 10; //How many successes you need to level up an op
var ContractSuccessesPerLevel = 3; //How many successes you need to level up a contract
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 ContractBaseMoneyGain = 5e3; //Base Money Gained per contract
var ContractBaseMoneyGain = 10e3; //Base Money Gained per contract
//DOM related variables
var ActiveActionCssClass = "bladeburner-active-action";
@ -518,7 +526,10 @@ Action.prototype.getActionTime = function(inst) {
var effAgility = Player.agility * inst.skillMultipliers.effAgi;
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);
@ -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() {
return Generic_toJSON("Action", this);
}
@ -684,6 +705,14 @@ function Bladeburner(params={}) {
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() {
this.contracts["Tracking"] = new Contract({
name:"Tracking",
@ -804,8 +833,13 @@ Bladeburner.prototype.storeCycles = function(numCycles=1) {
}
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 (Player.isWorking) {
if (Augmentations[AugmentationNames.BladesSimulacrum].owned === false && Player.isWorking) {
if (this.action.type !== ActionTypes["Idle"]) {
dialogBoxCreate("Your Bladeburner action was cancelled because you started " +
"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");
}
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) {
if (actionId == null) {return;}
this.action = actionId;
this.actionTimeCurrent = 0;
switch (actionId.type) {
@ -1067,10 +1103,7 @@ Bladeburner.prototype.startAction = function(actionId) {
this.actionTimeToComplete = 30;
break;
case ActionTypes["Recruitment"]:
var effCharisma = Player.charisma * this.skillMultipliers.effCha;
var charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
var time = Math.max(10, Math.round(BaseRecruitmentTimeNeeded - charismaFactor));
this.actionTimeToComplete = time;
this.actionTimeToComplete = this.getRecruitmentTime();
break;
case ActionTypes["FieldAnalysis"]:
case ActionTypes["Field Analysis"]:
@ -1130,9 +1163,9 @@ Bladeburner.prototype.completeAction = function() {
}
if (isOperation) {
action.maxLevel = Math.floor(action.successes / OperationSuccessesPerLevel) + 1;
action.setMaxLevel(OperationSuccessesPerLevel);
} else {
action.maxLevel = Math.floor(action.successes / ContractSuccessesPerLevel) + 1;
action.setMaxLevel(ContractSuccessesPerLevel);
}
if (action.rankGain) {
var gain = addOffset(action.rankGain * rewardMultiplier, 10);
@ -1301,7 +1334,7 @@ Bladeburner.prototype.completeAction = function() {
this.startAction(this.action); //Repeat action
break;
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);
if (Math.random() < successChance) {
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
//@action(Action obj) - Derived action class
//@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
//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 successMult = success ? 1 : 0.5;
@ -1621,6 +1664,7 @@ Bladeburner.prototype.initializeDomElementRefs = function() {
operations: {},
blackops: {},
skills: {},
skillPointsDisplay: null,
};
}
@ -1682,6 +1726,7 @@ Bladeburner.prototype.createContent = function() {
document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv);
this.postToConsole("Bladeburner Console BETA");
this.postToConsole("Type 'help' to see console commands");
DomElems.consoleInput.focus();
}
@ -1836,7 +1881,7 @@ Bladeburner.prototype.createOverviewContent = function() {
}));
//Faction button
var bladeburnersFactionName = "Bladeburners";
const bladeburnersFactionName = "Bladeburners";
if (factionExists(bladeburnersFactionName)) {
var bladeburnerFac = Factions[bladeburnersFactionName];
if (!(bladeburnerFac instanceof Faction)) {
@ -1850,7 +1895,7 @@ Bladeburner.prototype.createOverviewContent = function() {
Engine.loadFactionContent();
displayFactionContent(bladeburnersFactionName);
} else {
if (this.rank >= 25) {
if (this.rank >= RankNeededForFaction) {
joinFaction(bladeburnerFac);
dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction");
removeChildrenFromElement(DomElems.overviewDiv);
@ -2112,9 +2157,10 @@ Bladeburner.prototype.createSkillsContent = function() {
}
//Skill Points
DomElems.actionAndSkillsDiv.appendChild(createElement("p", {
DomElems.skillPointsDisplay = createElement("p", {
innerHTML:"<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>"
}));
});
DomElems.actionAndSkillsDiv.appendChild(DomElems.skillPointsDisplay);
//UI Element for each skill
for (var skillName in Skills) {
@ -2226,6 +2272,8 @@ Bladeburner.prototype.updateActionAndSkillsContent = function() {
}
break;
case "skills":
DomElems.skillPointsDisplay.innerHTML = "<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>";
var skillElems = Object.keys(DomElems.skills);
for (var i = 0; i < skillElems.length; ++i) {
var skillElem = DomElems.skills[skillElems[i]];
@ -2321,7 +2369,9 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
appendLineBreaks(el, 2);
el.appendChild(createElement("pre", {
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", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@ -2453,7 +2503,9 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
appendLineBreaks(el, 2);
el.appendChild(createElement("pre", {
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", {
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",
margin:"3px", padding:"3px",
clickListener:()=>{
if (this.skillPoints < pointCost) {return;}
this.skillPoints -= pointCost;
this.upgradeSkill(skill);
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() {
return Generic_toJSON("Bladeburner", this);
@ -3185,7 +3629,7 @@ function initBladeburner() {
Skills[SkillNames.Overclock] = new Skill({
name:SkillNames.Overclock,
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,
actionTime:1
});
@ -3271,7 +3715,7 @@ function initBladeburner() {
"Zenyatta and RedWater by any means necessary. After the task " +
"is completed, the actions must be covered up from the general public.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3288,7 +3732,7 @@ function initBladeburner() {
"fabricated as a last resort. Be warned that AeroCorp has some of " +
"the most advanced security measures in the world.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true
@ -3307,7 +3751,7 @@ function initBladeburner() {
"investigate the sewer systems, and eliminate Samizdat. They must " +
"never publish anything again.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3325,7 +3769,7 @@ function initBladeburner() {
"also to destroy any information or research at the facility that " +
"is relevant to the Synthoids and their goals.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3339,7 +3783,7 @@ function initBladeburner() {
"that this deal does not happen.<br><br>" +
"Your task is to intercept the deal. Leave no survivors.",
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},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3354,7 +3798,7 @@ function initBladeburner() {
"the Red Rabbit brothel. Try to limit the number of other casualties, " +
"but do what you must to complete the mission.",
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},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true,
@ -3371,7 +3815,7 @@ function initBladeburner() {
"have thus enlisted our help.<br><br>" +
"Your mission is to eradicate Juggernaut and his followers.",
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},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true,
@ -3387,7 +3831,7 @@ function initBladeburner() {
"in Los Angeles. Intelligence tells us that their base houses " +
"one of their Synthoid manufacturing units.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true,
@ -3407,7 +3851,7 @@ function initBladeburner() {
"operation. Your goal is to destroy this technology and eliminate" +
"anyone who was involved in its creation.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3422,7 +3866,7 @@ function initBladeburner() {
"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.",
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},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true,
@ -3438,7 +3882,7 @@ function initBladeburner() {
"with Augmentations. Your task is to hunt down the associated Dark Army " +
"members and eliminate them.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true,
@ -3457,7 +3901,7 @@ function initBladeburner() {
"The goal of Operation Wallace is to destroy the Dark Army and " +
"Syndicate factions in Aevum immediately. Leave no survivors.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3473,7 +3917,7 @@ function initBladeburner() {
"successfully return. In the event of failure, all of the operation's " +
"team members must not let themselves be captured alive.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true
@ -3495,7 +3939,7 @@ function initBladeburner() {
"Infiltrate the compound, delete and destroy the work, and then find and kill the " +
"project lead.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
@ -3512,7 +3956,7 @@ function initBladeburner() {
"The mission is to destroy this broadcast tower. Speed and " +
"stealth are of the upmost important for this.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true
@ -3541,7 +3985,7 @@ function initBladeburner() {
"'The Covenant'. We have no prior intelligence about this " +
"organization, so you are going in blind.",
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},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true

@ -13,7 +13,7 @@ import {getRandomInt, removeElementById,
clearSelector} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON,
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 {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -231,7 +231,8 @@ let MaterialSizes = {
Chemicals: 0.05,
Drugs: 0.02,
Robots: 0.5,
"AICores": 0.1
AICores: 0.1,
RealEstate: 0,
}
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
var cmpAndDmdText = "";
if (company.unlockUpgrades[2] === 1) {
cmpAndDmdText += "<br>Competition: " + formatNumber(mat.cmp, 3);
cmpAndDmdText += "<br>Demand: " + formatNumber(mat.dmd, 3);
}
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) +
"(" + formatNumber(totalGain, 3) + "/s)" +
@ -2430,8 +2431,9 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
});
//Select industry and city to export to
var citySelector = createElement("select");
var citySelector = createElement("select", {class: "dropdown"});
var industrySelector = createElement("select", {
class: "dropdown",
changeListener:()=>{
var industryName = industrySelector.options[industrySelector.selectedIndex].value;
for (var foo = 0; foo < company.divisions.length; ++foo) {
@ -2474,6 +2476,7 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
//Select amount to export
var exportAmount = createElement("input", {
class: "text-input",
placeholder:"Export amount / s"
});
@ -2695,11 +2698,12 @@ Warehouse.prototype.createProductUI = function(product, parentRefs) {
//Completed products
var cmpAndDmdText = "";
if (company.unlockUpgrades[2] === 1) {
cmpAndDmdText += "<br>Competition: " + formatNumber(product.cmp, 3);
}
if (company.unlockUpgrades[3] === 1) {
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
div.appendChild(createElement("p", {
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:",
});
var selector = createElement("select", {
class:"cmpy-mgmt-industry-select"
class:"dropdown"
});
var industryDescription = createElement("p", {});
var yesBtn;
var nameInput = createElement("input", {
type:"text",
id:"cmpy-mgmt-expand-industry-name-input",
color:"white",
backgroundColor:"black",
class: "text-input",
display:"block",
maxLength: 30,
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? " +
"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) {
if (division.offices.hasOwnProperty(cityName)) {
if (!(division.offices[cityName] instanceof OfficeSpace)) {

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

@ -2,146 +2,235 @@ import {CONSTANTS} from "./Constants.js";
import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
/* Crimes.js */
function commitShopliftCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeShoplift;
var time = 2000;
Player.startCrime(0, 0, 0, 2/div, 2/div, 0, 15000/div, time, singParams); //$7500/s, 1 exp/s
return time;
function Crime(name, type, time, money, difficulty, karma, params) {
this.name = name;
this.type = type;
this.time = time;
this.money = money;
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) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeRobStore;
var time = 60000;
Player.startCrime(30/div, 0, 0, 45/div, 45/div, 0, 400000/div, time, singParams); //$6666,6/2, 0.5exp/s, 0.75exp/s
return time;
Crime.prototype.commit = function(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = this.type;
Player.startCrime(
this.hacking_exp/div,
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) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeMug;
var time = 4000;
Player.startCrime(0, 3/div, 3/div, 3/div, 3/div, 0, 36000/div, time, singParams); //$9000/s, .66 exp/s
return time;
Crime.prototype.successRate = function() {
var chance = (this.hacking_success_weight * Player.hacking_skill +
this.strength_success_weight * Player.strength +
this.defense_success_weight * Player.defense +
this.dexterity_success_weight * Player.dexterity +
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) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeLarceny;
var time = 90000;
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;
}
const Crimes = {
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1/20, 0.1, {
dexterity_success_weight: 1,
agility_success_weight: 1,
function commitDealDrugsCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
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;
}
dexterity_exp: 2,
agility_exp: 2,
}),
function commitBondForgeryCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeBondForgery;
var time = 300000;
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;
}
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1/5, 0.5, {
hacking_exp: 30,
dexterity_exp: 45,
agility_exp: 45,
function commitTraffickArmsCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeTraffickArms;
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;
}
hacking_success_weight: 0.5 ,
dexterity_success_weight: 2,
agility_success_weight: 1,
function commitHomicideCrime(div=1, singParams=null) {
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;
}
intelligence_exp: 0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}),
function commitGrandTheftAutoCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeGrandTheftAuto;
var time = 80000;
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
return time;
}
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1/5, 0.25, {
strength_exp: 3,
defense_exp: 3,
dexterity_exp: 3,
agility_exp: 3,
function commitKidnapCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeKidnap;
var time = 120000;
Player.startCrime(0, 80/div, 80/div, 80/div, 80/div, 80/div, 3600000/div, time, singParams); //$30000/s. .66 exp/s
return time;
}
strength_success_weight: 1.5,
defense_success_weight: 0.5,
dexterity_success_weight: 1.5,
agility_success_weight: 0.5,
}),
function commitAssassinationCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeAssassination;
var time = 300000;
Player.startCrime(0, 300/div, 300/div, 300/div, 300/div, 0, 12000000/div, time, singParams); //$40000/s, 1 exp/s
return time;
}
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1/3, 1.5, {
hacking_exp: 45,
dexterity_exp: 60,
agility_exp: 60,
function commitHeistCrime(div=1, singParams=null) {
if (div <= 0) {div = 1;}
Player.crimeType = CONSTANTS.CrimeHeist;
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;
}
hacking_skill_success_weight: 0.5,
dexterity_success_weight: 1,
agility_success_weight: 1,
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;
switch (crime) {
case CONSTANTS.CrimeShoplift:
chance = determineCrimeChanceShoplift();
break;
case CONSTANTS.CrimeRobStore:
chance = determineCrimeChanceRobStore();
break;
case CONSTANTS.CrimeMug:
chance = determineCrimeChanceMug();
break;
case CONSTANTS.CrimeLarceny:
chance = determineCrimeChanceLarceny();
break;
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;
var found = false;
for(const i in Crimes) {
const crime = Crimes[i];
if(crime.type == type) {
chance = crime.successRate();
found = true;
break;
}
}
if(!found) {
console.log(crime);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
return;
}
if (Math.random() <= chance) {
@ -154,134 +243,33 @@ function determineCrimeSuccess(crime, moneyGained) {
}
}
let intWgt = CONSTANTS.IntelligenceCrimeWeight;
let maxLvl = CONSTANTS.MaxSkillLevel;
function determineCrimeChanceShoplift() {
var chance = (Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 20;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
function findCrime(roughName) {
if (roughName.includes("shoplift")) {
return Crimes.Shoplift;
} else if (roughName.includes("rob") && roughName.includes("store")) {
return Crimes.RobStore;
} else if (roughName.includes("mug")) {
return Crimes.Mug;
} else if (roughName.includes("larceny")) {
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() {
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};
export {determineCrimeSuccess,findCrime,Crimes};

@ -19,7 +19,6 @@ function checkIfConnectedToDarkweb() {
"to purchase an item");
}
}
}
//Handler for dark web commands. The terminal's executeCommand() function will pass
@ -49,150 +48,68 @@ function executeDarkwebTerminalCommand(commandArray) {
}
function listAllDarkwebItems() {
for (var item in DarkWebItems) {
if (DarkWebItems.hasOwnProperty(item)) {
var item = DarkWebItems[item];
//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;
for(const key in DarkWebItems) {
const item = DarkWebItems[key];
post(item.toString());
}
//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) {
if (itemName.toLowerCase() == Programs.BruteSSHProgram.name.toLowerCase()) {
var price = parseDarkwebItemPrice(DarkWebItems.BruteSSHProgram);
if (price > 0 && Player.money.gt(price)) {
Player.loseMoney(price);
Player.getHomeComputer().programs.push(Programs.BruteSSHProgram.name);
post("You have purchased the BruteSSH.exe program. The new program " +
"can be found on your home computer.");
} else {
post("Not enough money to purchase " + itemName);
itemName = itemName.toLowerCase();
// find the program that matches, if any
let item = null;
for(const key in DarkWebItems) {
const i = DarkWebItems[key];
if(i.program.toLowerCase() == itemName) {
item = i;
}
} 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) {
var split = itemDesc.split(" - ");
if (split.length == 3) {
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;}
} else {
return -1;
// return if invalid
if(item === null) {
post("Unrecognized item: "+itemName);
return;
}
// 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 = {
BruteSSHProgram: "BruteSSH.exe - $500,000 - Opens up SSH Ports",
FTPCrackProgram: "FTPCrack.exe - $1,500,000 - Opens up FTP Ports",
RelaySMTPProgram: "relaySMTP.exe - $5,000,000 - Opens up SMTP Ports",
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",
function DarkWebItem(program, price, description) {
this.program = program;
this.price = price;
this.description = description;
}
export {checkIfConnectedToDarkweb, executeDarkwebTerminalCommand,
listAllDarkwebItems, buyDarkwebItem, parseDarkwebItemPrice,
DarkWebItems};
// formats the item for the terminal (eg. "BruteSSH.exe - $500,000 - Opens up SSH Ports")
DarkWebItem.prototype.toString = function() {
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 {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
import {FactionInfo} from "./FactionInfo.js";
import {FactionInfos} from "./FactionInfo.js";
import {Locations} from "./Location.js";
import {HackingMission, setInMission} from "./Missions.js";
import {Player} from "./Player.js";
@ -15,7 +15,7 @@ import {clearEventListeners, createElement,
removeChildrenFromElement} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON,
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 {yesNoBoxCreate, yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js";
@ -23,7 +23,6 @@ import {yesNoBoxCreate, yesNoBoxGetYesButton,
function Faction(name="") {
this.name = name;
this.augmentations = []; //Name of augmentation only
this.info = ""; //Introductory/informational text about the faction
//Player-related properties for faction
this.isMember = false; //Whether player is member
@ -31,22 +30,17 @@ function Faction(name="") {
this.playerReputation = 0; //"Reputation" within faction
this.alreadyInvited = false;
//Multipliers for unlocking and purchasing augmentations
this.augmentationPriceMult = 1;
this.augmentationRepRequirementMult = 1;
//Faction favor
this.favor = 0;
this.rolloverRep = 0;
};
Faction.prototype.setAugmentationMultipliers = function(price, rep) {
this.augmentationPriceMult = price;
this.augmentationRepRequirementMult = rep;
}
Faction.prototype.setInfo = function(inf) {
this.info = inf;
Faction.prototype.getInfo = function() {
const info = FactionInfos[this.name];
if(info == null) {
throw new Error("Missing faction from FactionInfos: " + this.name+" this probably means the faction got corrupted somehow");
}
return info;
}
Faction.prototype.gainFavor = function() {
@ -119,142 +113,9 @@ function factionExists(name) {
//TODO Augmentation price and rep requirement mult are 1 for everything right now,
// This might change in the future for balance
function initFactions() {
//Endgame
var Illuminati = new Faction("Illuminati");
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);
for(const name in FactionInfos) {
resetFaction(new Faction(name));
}
}
//Resets a faction during (re-)initialization. Saves the favor in the new
@ -287,36 +148,12 @@ function inviteToFaction(faction) {
function joinFaction(faction) {
faction.isMember = true;
Player.factions.push(faction.name);
const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction
if (faction.name == "Chongqing") {
Factions["Sector-12"].isBanned = true;
Factions["Aevum"].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;
for(const i in factionInfo.enemies) {
const enemy = factionInfo.enemies[i];
Factions[enemy].isBanned = true;
}
}
@ -326,6 +163,8 @@ function displayFactionContent(factionName) {
if (faction == null) {
throw new Error("Invalid factionName passed into displayFactionContent: " + factionName);
}
var factionInfo = faction.getInfo();
removeChildrenFromElement(Engine.Display.factionContent);
var elements = [];
@ -334,7 +173,7 @@ function displayFactionContent(factionName) {
innerText:factionName
}));
elements.push(createElement("pre", {
innerHTML:"<i>" + faction.info + "</i>"
innerHTML:"<i>" + factionInfo.infoText + "</i>"
}));
elements.push(createElement("p", {
innerText:"---------------",
@ -346,14 +185,14 @@ function displayFactionContent(factionName) {
favorGain = favorGain[0];
elements.push(createElement("p", {
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"
}))
elements.push(createElement("p", {
innerText:"---------------",
}));
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 " +
"you earn reputation for this faction by 1% per favor. Faction favor " +
"is gained whenever you reset after installing an Augmentation. The amount of " +
@ -583,214 +422,17 @@ function displayFactionContent(factionName) {
return;
}
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 {
if (!faction.isMember) {
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
for (var i = 0; i < elements.length; ++i) {
Engine.Display.factionContent.appendChild(elements[i]);
@ -915,6 +557,8 @@ function displayFactionAugmentations(factionName) {
// @augs Array of Aug names
// @faction Faction for which to display Augmentations
function createFactionAugmentationDisplayElements(augmentationsList, augs, faction) {
const factionInfo = faction.getInfo();
for (var i = 0; i < augs.length; ++i) {
(function () {
var aug = Augmentations[augs[i]];
@ -955,7 +599,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
var pElem = createElement("p", {
display:"inline",
})
var req = aug.baseRepRequirement * faction.augmentationRepRequirementMult;
var req = aug.baseRepRequirement * factionInfo.augmentationRepRequirementMult;
var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) {
aElem.setAttribute("class", "a-link-button-inactive");
@ -966,10 +610,10 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
pElem.innerHTML = "ALREADY OWNED";
} else if (faction.playerReputation >= req) {
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 {
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";
}
aDiv.appendChild(aElem);
@ -982,6 +626,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
}
function purchaseAugmentationBoxCreate(aug, fac) {
const factionInfo = fac.getInfo();
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Purchase";
noBtn.innerHTML = "Cancel";
@ -995,7 +640,7 @@ function purchaseAugmentationBoxCreate(aug, fac) {
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
aug.info + "<br><br>" +
"<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
@ -1026,12 +671,13 @@ function hasAugmentationPrereqs(aug) {
}
function purchaseAugmentation(aug, fac, sing=false) {
const factionInfo = fac.getInfo();
var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) {
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
"purchase this one.";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (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;
if (sing) {return 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;
if (sing) {return 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) {
Player.firstAugPurchased = true;
document.getElementById("augmentations-tab").style.display = "list-item";
@ -1053,7 +699,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
}
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 (aug.name == AugmentationNames.NeuroFluxGovernor) {

@ -1,68 +1,81 @@
//Contains the "information" property for all the Factions, which is just a description
//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
IlluminatiInfo: "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. ",
"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. ", [], 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> " +
"Only then can you discover immortality.",
"Only then can you discover immortality.", [], true, true, true, false),
//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 " +
"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 " +
"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>" +
"Legal Insight - Business Instinct - Experience Innovation",
"Bachman & Associates": new FactionInfo("Where Law and Business meet - thats where we are. <br><br>" +
"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 " +
"direction in its life. That is why humans created God. " +
"And that is why humans created civilization - " +
"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 " +
"deep learning and innovative ideas. And improved by iteration. That's Four Sigma.",
"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.", [], 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
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, " +
"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
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 " +
"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 " +
"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. " +
"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>" +
"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>" +
" _.nITESECNIt. <br>" +
" .-'NITESECNITESEc. <br>" +
@ -97,47 +110,47 @@ let FactionInfo = {
" / .d$$$$; , ; <br>" +
" d .dNITESEC $ | <br>" +
" :bp.__.gNITESEC$$ :$ ; <br>" +
" NITESECNITESECNIT $$b : <br>",
" NITESECNITESECNIT $$b : <br>", [], true, true, false, false),
//City factions, essentially governments
ChongqingInfo: "Serve the people",
Sector12Info: "The City of the Future",
HongKongInfo: "Asia's World City",
AevumInfo: "The Silicon City",
IshimaInfo: "The East Asian Order of the Future",
VolhavenInfo: "Benefit, Honour, and Glory",
"Chongqing": new FactionInfo("Serve the people", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
"Sector-12": new FactionInfo("The City of the Future", ["Chongqing", "New Tokyo", "Ishima", "Volhaven"], true, true, true, true),
"New Tokyo": new FactionInfo("Asia's World City", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
"Aevum": new FactionInfo("The Silicon City", ["Chongqing", "New Tokyo", "Ishima", "Volhaven"], true, true, true, true),
"Ishima": new FactionInfo("The East Asian Order of the Future", ["Sector-12", "Aevum", "Volhaven"], true, true, true, true),
"Volhaven": new FactionInfo("Benefit, Honour, and Glory", ["Chongqing", "Sector-12", "New Tokyo", "Aevum", "Ishima"], true, true, true, true),
//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 " +
"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
//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 " +
"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
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 " +
"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,
createAccordionElement, createPopup,
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 {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,

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

@ -3,18 +3,7 @@ import {CompanyPositions, initCompanies,
Companies, getJobRequirementText} from "./Company.js";
import {Corporation} from "./CompanyManagement.js";
import {CONSTANTS} from "./Constants.js";
import {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} from "./Crimes.js";
import {Crimes} from "./Crimes.js";
import {Engine} from "./engine.js";
import {beginInfiltration} from "./Infiltration.js";
import {hasBladeburnerSF} from "./NetscriptFunctions.js";
@ -22,12 +11,13 @@ import {Player} from "./Player.js";
import {Server, AllServers, AddToAllServers} from "./Server.js";
import {purchaseServer,
purchaseRamForHomeComputer} from "./ServerPurchases.js";
import {Settings} from "./Settings.js";
import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners, createElement} from "../utils/HelperFunctions.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 {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -289,7 +279,10 @@ function displayLocationContent() {
purchase256gb.innerHTML = "Purchase 256GB Server - $" + formatNumber(256*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase512gb.innerHTML = "Purchase 512GB Server - $" + formatNumber(512*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";
travelToAevum.style.display = "none";
@ -337,9 +330,9 @@ function displayLocationContent() {
repGain = repGain[0];
jobReputation.innerHTML = "Company reputation: " + formatNumber(company.playerReputation, 4) +
"<span class='tooltiptext'>You will earn " +
formatNumber(repGain, 4) +
formatNumber(repGain, 0) +
" 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 " +
"you earn reputation for this company by 1% per favor. Company favor " +
"is gained whenever you reset after installing an Augmentation. The amount of " +
@ -726,6 +719,7 @@ function displayLocationContent() {
securityJob.style.display = "block";
agentJob.style.display = "block";
if (Player.bitNodeN === 6 || hasBladeburnerSF === true) {
if (Player.bitNodeN === 8) {break;}
if (Player.bladeburner instanceof Bladeburner) {
//Note: Can't infiltrate NSA when part of bladeburner
nsaBladeburner.innerText = "Enter Bladeburner Headquarters";
@ -1057,18 +1051,18 @@ function displayLocationContent() {
case Locations.NewTokyoSlums:
case Locations.IshimaSlums:
case Locations.VolhavenSlums:
var shopliftChance = determineCrimeChanceShoplift();
var robStoreChance = determineCrimeChanceRobStore();
var mugChance = determineCrimeChanceMug();
var larcenyChance = determineCrimeChanceLarceny();
var drugsChance = determineCrimeChanceDealDrugs();
var bondChance = determineCrimeChanceBondForgery();
var armsChance = determineCrimeChanceTraffickArms();
var homicideChance = determineCrimeChanceHomicide();
var gtaChance = determineCrimeChanceGrandTheftAuto();
var kidnapChance = determineCrimeChanceKidnap();
var assassinateChance = determineCrimeChanceAssassination();
var heistChance = determineCrimeChanceHeist();
var shopliftChance = Crimes.Shoplift.successRate();
var robStoreChance = Crimes.RobStore.successRate();
var mugChance = Crimes.Mug.successRate();
var larcenyChance = Crimes.Larceny.successRate();
var drugsChance = Crimes.DealDrugs.successRate();
var bondChance = Crimes.BondForgery.successRate();
var armsChance = Crimes.TraffickArms.successRate();
var homicideChance = Crimes.Homicide.successRate();
var gtaChance = Crimes.GrandTheftAuto.successRate();
var kidnapChance = Crimes.Kidnap.successRate();
var assassinateChance = Crimes.Assassination.successRate();
var heistChance = Crimes.Heist.successRate();
slumsDescText.style.display = "block";
slumsShoplift.style.display = "block";
@ -1771,16 +1765,8 @@ function initLocationButtons() {
});
purchaseHomeRam.addEventListener("click", function() {
//Calculate how many times ram has been upgraded (doubled)
var currentRam = 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;
const cost = Player.getUpgradeHomeRamCost();
const ram = Player.getHomeComputer().maxRam;
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel";
@ -1792,8 +1778,8 @@ function initLocationButtons() {
yesNoBoxClose();
});
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 cost $" + formatNumber(cost, 2));
"This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB. <br><br>" +
"This will cost " + numeral(cost).format('$0.000a'));
});
purchaseHomeCores.addEventListener("click", function() {
@ -1833,92 +1819,92 @@ function initLocationButtons() {
});
travelToAevum.addEventListener("click", function() {
travelBoxCreate(Locations.Aevum, 200000);
travelBoxCreate(Locations.Aevum, CONSTANTS.TravelCost);
return false;
});
travelToChongqing.addEventListener("click", function() {
travelBoxCreate(Locations.Chongqing, 200000);
travelBoxCreate(Locations.Chongqing, CONSTANTS.TravelCost);
return false;
});
travelToSector12.addEventListener("click", function() {
travelBoxCreate(Locations.Sector12, 200000);
travelBoxCreate(Locations.Sector12, CONSTANTS.TravelCost);
return false;
});
travelToNewTokyo.addEventListener("click", function() {
travelBoxCreate(Locations.NewTokyo, 200000);
travelBoxCreate(Locations.NewTokyo, CONSTANTS.TravelCost);
return false;
});
travelToIshima.addEventListener("click", function() {
travelBoxCreate(Locations.Ishima, 200000);
travelBoxCreate(Locations.Ishima, CONSTANTS.TravelCost);
return false;
});
travelToVolhaven.addEventListener("click", function() {
travelBoxCreate(Locations.Volhaven, 200000);
travelBoxCreate(Locations.Volhaven, CONSTANTS.TravelCost);
return false;
});
slumsShoplift.addEventListener("click", function() {
commitShopliftCrime();
Crimes.Shoplift.commit();
return false;
});
slumsRobStore.addEventListener("click", function() {
commitRobStoreCrime();
Crimes.RobStore.commit();
return false;
});
slumsMug.addEventListener("click", function() {
commitMugCrime();
Crimes.Mug.commit();
return false;
});
slumsLarceny.addEventListener("click", function() {
commitLarcenyCrime();
Crimes.Larceny.commit();
return false;
});
slumsDealDrugs.addEventListener("click", function() {
commitDealDrugsCrime();
Crimes.DealDrugs.commit();
return false;
});
slumsBondForgery.addEventListener("click", function() {
commitBondForgeryCrime();
Crimes.BondForgery.commit();
return false;
});
slumsTrafficArms.addEventListener("click", function() {
commitTraffickArmsCrime();
Crimes.TraffickArms.commit();
return false;
});
slumsHomicide.addEventListener("click", function() {
commitHomicideCrime();
Crimes.Homicide.commit();
return false;
});
slumsGta.addEventListener("click", function() {
commitGrandTheftAutoCrime();
Crimes.GrandTheftAuto.commit();
return false;
});
slumsKidnap.addEventListener("click", function() {
commitKidnapCrime();
Crimes.Kidnap.commit();
return false;
});
slumsAssassinate.addEventListener("click", function() {
commitAssassinationCrime();
Crimes.Assassination.commit();
return false;
});
slumsHeist.addEventListener("click", function() {
commitHeistCrime();
Crimes.Heist.commit();
return false;
});
@ -2020,11 +2006,13 @@ function purchaseTorRouter() {
AddToAllServers(darkweb);
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);
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) {
@ -2162,6 +2150,10 @@ function setJobRequirementTooltip(loc, entryPosType, btn) {
}
function travelBoxCreate(destCityName, cost) {
if(Settings.SuppressTravelConfirmation) {
travelToCity(destCityName, cost);
return;
}
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Yes";
noBtn.innerHTML = "No";

@ -833,7 +833,9 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
return Promise.resolve(false);
} else {
//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);
runningScriptObj.threads = threads;
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.fnWorker = null; //Workerscript for a function call
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
//Properties used for dynamic RAM evaluation
this.dynamicRamUsage = 1.4;
this.dynamicLoadedFns = {};
}
//Returns the server on which the workerScript is running
@ -52,6 +56,14 @@ WorkerScript.prototype.getScript = function() {
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
let workerScripts = [];

@ -8,7 +8,7 @@ import {Company, Companies, getNextCompanyPosition,
import {CONSTANTS} from "./Constants.js";
import {Corporation} from "./CompanyManagement.js";
import {Programs} from "./CreateProgram.js";
import {determineCrimeSuccess} from "./Crimes.js";
import {determineCrimeSuccess, Crimes} from "./Crimes.js";
import {Engine} from "./engine.js";
import {Factions, Faction,
displayFactionContent} from "./Faction.js";
@ -25,7 +25,7 @@ import {clearEventListeners} from "../utils/HelperFunctions.j
import {createRandomIp} from "../utils/IPAddress.js";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js";
import numeral from "numeral/min/numeral.min";
import {formatNumber,
convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js";
@ -99,6 +99,7 @@ function PlayerObject() {
this.currentServer = ""; //IP address of Server currently being accessed through terminal
this.purchasedServers = []; //IP Addresses of purchased servers
this.hacknetNodes = [];
this.hacknetNodeWrappers = [];
this.totalHacknetNodeProduction = 0;
//Factions
@ -298,8 +299,6 @@ PlayerObject.prototype.prestigeAugmentation = function() {
this.hacknetNodes.length = 0;
this.totalHacknetNodeProduction = 0;
this.bladeburner = 0;
}
PlayerObject.prototype.prestigeSourceFile = function() {
@ -390,16 +389,6 @@ PlayerObject.prototype.prestigeSourceFile = function() {
if (this.bitNodeN === 3) {this.money = new Decimal(150e9);}
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.scriptProdSinceLastAug = 0;
}
@ -412,6 +401,26 @@ PlayerObject.prototype.getHomeComputer = function() {
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
PlayerObject.prototype.calculateSkill = function(exp) {
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;
}
this.hacking_exp += exp;
if(this.hacking_exp < 0) {
this.hacking_exp = 0;
}
}
PlayerObject.prototype.gainStrengthExp = function(exp) {
@ -585,6 +597,9 @@ PlayerObject.prototype.gainStrengthExp = function(exp) {
console.log("ERR: NaN passed into Player.gainStrengthExp()"); return;
}
this.strength_exp += exp;
if(this.strength_exp < 0) {
this.strength_exp = 0;
}
}
PlayerObject.prototype.gainDefenseExp = function(exp) {
@ -592,6 +607,9 @@ PlayerObject.prototype.gainDefenseExp = function(exp) {
console.log("ERR: NaN passed into player.gainDefenseExp()"); return;
}
this.defense_exp += exp;
if(this.defense_exp < 0) {
this.defense_exp = 0;
}
}
PlayerObject.prototype.gainDexterityExp = function(exp) {
@ -599,6 +617,9 @@ PlayerObject.prototype.gainDexterityExp = function(exp) {
console.log("ERR: NaN passed into Player.gainDexterityExp()"); return;
}
this.dexterity_exp += exp;
if(this.dexterity_exp < 0) {
this.dexterity_exp = 0;
}
}
PlayerObject.prototype.gainAgilityExp = function(exp) {
@ -606,6 +627,9 @@ PlayerObject.prototype.gainAgilityExp = function(exp) {
console.log("ERR: NaN passed into Player.gainAgilityExp()"); return;
}
this.agility_exp += exp;
if(this.agility_exp < 0) {
this.agility_exp = 0;
}
}
PlayerObject.prototype.gainCharismaExp = function(exp) {
@ -613,6 +637,9 @@ PlayerObject.prototype.gainCharismaExp = function(exp) {
console.log("ERR: NaN passed into Player.gainCharismaExp()"); return;
}
this.charisma_exp += exp;
if(this.charisma_exp < 0) {
this.charisma_exp = 0;
}
}
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
if (determineCrimeSuccess(this.crimeType, this.workMoneyGained)) {
//Handle Karma and crime statistics
switch(this.crimeType) {
case CONSTANTS.CrimeShoplift:
this.karma -= 0.1;
let crime = null;
for(const i in Crimes) {
if(Crimes[i].type == this.crimeType) {
crime = Crimes[i];
break;
case CONSTANTS.CrimeRobStore:
this.karma -= 0.5;
this.gainIntelligenceExp(0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeMug:
this.karma -= 0.25;
break;
case CONSTANTS.CrimeLarceny:
this.karma -= 1.5;
this.gainIntelligenceExp(0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain);
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;
}
}
if(crime == null) {
console.log(this.crimeType);
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
}
this.karma -= crime.karma;
this.numPeopleKilled += crime.kills;
if(crime.intelligence_exp > 0) {
this.gainIntelligenceExp(crime.intelligence_exp);
}
//On a crime success, gain 2x exp
@ -2349,6 +2341,25 @@ PlayerObject.prototype.setBitNodeNumber = function(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 */
function loadPlayer(saveString) {
Player = JSON.parse(saveString, Reviver);

@ -2,6 +2,7 @@ import {deleteActiveScriptsItem} from "./ActiveScriptsUI.js";
import {Augmentations, augmentationExists,
initAugmentations, AugmentationNames} from "./Augmentations.js";
import {initBitNodeMultipliers} from "./BitNode.js";
import {Bladeburner} from "./Bladeburner.js";
import {writeCinematicText} from "./CinematicText.js";
import {Companies, Company, initCompanies} from "./Company.js";
import {Programs} from "./CreateProgram.js";
@ -34,6 +35,8 @@ import {createPopup, createElement,
import {yesNoBoxCreate, yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js";
let BitNode8StartingMoney = 250e6;
//Prestige by purchasing augmentation
function prestigeAugmentation() {
initBitNodeMultipliers();
@ -123,11 +126,13 @@ function prestigeAugmentation() {
}
}
//Reset Bladeburner
Player.bladeburner = null;
//Cancel Bladeburner action
if (Player.bladeburner instanceof Bladeburner) {
Player.bladeburner.prestige();
}
//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) {
Player.hasWseAccount = 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
Player.gainIntelligenceExp(5);
}

@ -113,7 +113,7 @@ function giveSourceFile(bitNodeNumber) {
}
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 + ", " +
"is already at max level!");
} else {
@ -208,7 +208,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
var elemId = "bitnode-" + i.toString();
var elem = clearEventListeners(elemId);
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() {
var bitNodeKey = "BitNode" + i;
var bitNode = BitNodes[bitNodeKey];

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

@ -1,4 +1,5 @@
var ace = require('brace');
var beautify = require('js-beautify').js_beautify;
require('brace/mode/javascript');
require('../netscript');
require('brace/theme/chaos');
@ -57,6 +58,15 @@ function scriptEditorInit() {
console.log("Error finding 'script-editor-buttons-wrapper'");
return;
}
var beautifyButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerText:"beautify",
clickListener:()=>{
beautifyScript();
return false;
}
});
var closeButton = createElement("a", {
class:"a-link-button", display:"inline-block",
innerText:"Save & Close (Ctrl/Cmd + b)",
@ -90,6 +100,7 @@ function scriptEditorInit() {
target:"_blank"
});
wrapper.appendChild(beautifyButton);
wrapper.appendChild(closeButton);
wrapper.appendChild(scriptEditorRamText);
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() {
var filename = document.getElementById("script-editor-filename").value;
var editor = ace.edit('javascript-editor');
@ -448,6 +466,7 @@ function parseOnlyRamCalculate(server, code, workerScript) {
if (ref == specialReferenceFOR) ram += CONSTANTS.ScriptForRamCost;
if (ref == specialReferenceWHILE) ram += CONSTANTS.ScriptWhileRamCost;
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
// 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.
}
//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.
// walkDeeper is for doing recursive walks of expressions in composites that we handle.
function commonVisitors() {
return {
Identifier: (node, st, walkDeeper) => {
if (objectPrototypeProperties.includes(node.name)) {return;}
addRef(st.key, node.name);
},
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
function processSingleServerGrowth(server, numCycles) {
//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
var growthRate = CONSTANTS.ServerBaseGrowthRate;
const growthRate = CONSTANTS.ServerBaseGrowthRate;
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
//Calculate adjusted server growth rate based on parameters
var serverGrowthPercentage = server.serverGrowth / 100;
var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
const serverGrowthPercentage = server.serverGrowth / 100;
const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
//Apply serverGrowth for the calculated number of growth cycles
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
@ -789,19 +801,26 @@ function processSingleServerGrowth(server, numCycles) {
serverGrowth = 1;
}
var oldMoneyAvailable = server.moneyAvailable;
const oldMoneyAvailable = server.moneyAvailable;
server.moneyAvailable *= serverGrowth;
// in case of data corruption
if (server.moneyMax && isNaN(server.moneyAvailable)) {
server.moneyAvailable = server.moneyMax;
}
// cap at max
if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
server.moneyAvailable = server.moneyMax;
return server.moneyAvailable / oldMoneyAvailable;
}
//Growing increases server security twice as much as hacking
server.fortify(2 * CONSTANTS.ServerFortifyAmount * numServerGrowthCycles);
return serverGrowth;
// if there was any growth at all, increase security
if(oldMoneyAvailable !== server.moneyAvailable) {
//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) {
@ -873,9 +892,11 @@ function GetServerByHostname(hostname) {
function getServer(s) {
if (!isValidIPAddress(s)) {
return GetServerByHostname(s);
} else {
}
if(AllServers[s] !== undefined) {
return AllServers[s];
}
return null;
}
//Debugging tool

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

@ -66,7 +66,7 @@ function initSourceFiles() {
"Level 1: 24%<br>" +
"Level 2: 36%<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) {
@ -181,6 +181,42 @@ function applySourceFile(srcFile) {
Player.work_money_mult *= incMult;
Player.company_rep_mult *= incMult;
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:
console.log("ERROR: Invalid source file number: " + srcFile.n);
break;

@ -11,7 +11,7 @@ import {clearEventListeners, getRandomInt,
clearEventListenersEl} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON,
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 {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -703,7 +703,7 @@ function displayStockMarketContent() {
if (!Player.hasWseAccount && Player.money.gte(CONSTANTS.WSEAccountCost)) {
wseAccountButton.setAttribute("class", "a-link-button");
} else if (Player.hasWseAccount){
wseAccountButton.innerText = "WSE Account - acquired";
wseAccountButton.innerText = "WSE Account - Purchased";
wseAccountButton.setAttribute("class", "a-link-button-bought");
} else {
wseAccountButton.setAttribute("class", "a-link-button-inactive");
@ -724,7 +724,7 @@ function displayStockMarketContent() {
if (!Player.hasTixApiAccess && Player.money.gte(CONSTANTS.TIXAPICost)) {
tixApiAccessButton.setAttribute("class", "a-link-button");
} 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");
} else {
tixApiAccessButton.setAttribute("class", "a-link-button-inactive");

@ -3,7 +3,7 @@ import {gameOptionsBoxOpen, gameOptionsBoxClose}from "../utils/GameOptions.js";
import {clearEventListeners, createElement,
removeChildrenFromElement,
exceptionAlert} from "../utils/HelperFunctions.js";
import numeral from "../utils/numeral.min.js";
import numeral from "numeral/min/numeral.min";
import {formatNumber,
convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions.js";
import {loxBoxCreate, logBoxUpdateText,
@ -12,7 +12,8 @@ import {loxBoxCreate, logBoxUpdateText,
import {updateActiveScriptsItems} from "./ActiveScriptsUI.js";
import {Augmentations, installAugmentations,
initAugmentations, AugmentationNames,
displayAugmentationsContent} from "./Augmentations.js";
displayAugmentationsContent,
PlayerOwnedAugmentation} from "./Augmentations.js";
import {BitNodes, initBitNodes,
initBitNodeMultipliers} from "./BitNode.js";
import {Bladeburner} from "./Bladeburner.js";
@ -44,13 +45,14 @@ import {updateOnlineScriptTimes,
import {Player} from "./Player.js";
import {prestigeAugmentation,
prestigeSourceFile} from "./Prestige.js";
import {redPillFlag} from "./RedPill.js";
import {redPillFlag, hackWorldDaemon} from "./RedPill.js";
import {saveObject, loadGame} from "./SaveObject.js";
import {loadAllRunningScripts, scriptEditorInit,
updateScriptEditorContent} from "./Script.js";
import {AllServers, Server, initForeignServers} from "./Server.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 {StockMarket, StockSymbols,
SymbolToStockMap, initStockSymbols,
@ -145,6 +147,7 @@ let Engine = {
factionsMainMenuButton: null,
augmentationsMainMenuButton: null,
tutorialMainMenuButton: null,
devMainMenuButton: null,
saveMainMenuButton: null,
deleteMainMenuButton: null,
@ -158,6 +161,41 @@ let Engine = {
tutorialFactionsButton: null,
tutorialAugmentationsButton: 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
@ -183,6 +221,7 @@ let Engine = {
factionAugmentationsContent: null,
augmentationsContent: null,
tutorialContent: null,
devMenuContent: null,
infiltrationContent: null,
stockMarketContent: null,
locationContent: null,
@ -208,6 +247,7 @@ let Engine = {
Faction: "Faction",
Augmentations: "Augmentations",
Tutorial: "Tutorial",
DevMenu: "Dev Menu",
Location: "Location",
workInProgress: "WorkInProgress",
RedPill: "RedPill",
@ -319,6 +359,14 @@ let Engine = {
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() {
Engine.hideAllContent();
Engine.Display.locationContent.style.display = "block";
@ -455,6 +503,7 @@ let Engine = {
Engine.Display.factionAugmentationsContent.style.display = "none";
Engine.Display.augmentationsContent.style.display = "none";
Engine.Display.tutorialContent.style.display = "none";
Engine.Display.devMenuContent.style.display = "none";
Engine.Display.locationContent.style.display = "none";
Engine.Display.workInProgressContent.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("tutorial-menu-link").classList.remove("active");
document.getElementById("options-menu-link").classList.remove("active");
document.getElementById("dev-menu-link").classList.remove("active");
},
displayCharacterOverviewInfo: function() {
@ -650,6 +700,7 @@ let Engine = {
//Generic Locations (common to every city):
// World Stock Exchange
// Corporation (if applicable)
// Bladeburner HQ (if applicable);
var genericLocationsList = document.getElementById("generic-locations-list");
genericLocationsList.style.display = "inline";
removeChildrenFromElement(genericLocationsList);
@ -676,6 +727,18 @@ let Engine = {
}));
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() {
@ -771,6 +834,43 @@ let Engine = {
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
displayTutorialPage: function(text) {
document.getElementById("tutorial-getting-started-link").style.display = "none";
@ -1169,6 +1269,7 @@ let Engine = {
var job = document.getElementById("job-tab");
var tutorial = document.getElementById("tutorial-tab");
var options = document.getElementById("options-tab");
var dev = document.getElementById("dev-tab");
//Load game from save or create new game
if (loadGame(saveString)) {
@ -1245,7 +1346,7 @@ let Engine = {
formatNumber(offlineProductionFromHacknetNodes, 2));
//Close main menu accordions for loaded game
var visibleMenuTabs = [terminal, createScript, activeScripts, stats,
hacknetnodes, city, tutorial, options];
hacknetnodes, city, tutorial, options, dev];
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
else {factions.style.display = "none";}
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
@ -1299,7 +1400,7 @@ let Engine = {
Engine.openMainMenuHeader(
[terminal, createScript, activeScripts, stats,
hacknetnodes, city,
tutorial, options]
tutorial, options, dev]
);
//Start interactive tutorial
@ -1352,6 +1453,9 @@ let Engine = {
Engine.Display.tutorialContent = document.getElementById("tutorial-container");
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.style.display = "none";
@ -1439,9 +1543,195 @@ let Engine = {
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 (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 optionsLink = document.getElementById("options-menu-link");
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) {
Engine.toggleMainMenuHeader(false,
[tutorial, options],
[tutorialLink, optionsLink]
);
Engine.toggleMainMenuHeader(false, elems, links);
} else {
Engine.toggleMainMenuHeader(true,
[tutorial, options],
[tutorialLink, optionsLink]
);
Engine.toggleMainMenuHeader(true, elems, links);
}
}
@ -1623,6 +1913,12 @@ let Engine = {
return false;
});
Engine.Clickables.devMainMenuButton = clearEventListeners("dev-menu-link");
Engine.Clickables.devMainMenuButton.addEventListener("click", function() {
Engine.loadDevMenuContent();
return false;
});
//Active scripts list
Engine.ActiveScriptsList = document.getElementById("active-scripts-list");

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

@ -11,7 +11,7 @@
<script src="https://unpkg.com/mocha@4.0.1/mocha.js"></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">
mocha.checkLeaks();
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={}) {
var el = document.createElement(type);
if (params.id) {el.id = params.id;}
@ -260,4 +275,4 @@ export {sizeOfObject, clearObject, addOffset, clearEventListeners, getRandomInt,
removeElementById, removeElement, createElement, createAccordionElement,
appendLineBreaks,
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 webpack = require('webpack');
module.exports = {
mode: "development",
module.exports = (env, argv) => ({
//mode: "development",
plugins: [
// http://stackoverflow.com/questions/29080148/expose-jquery-to-real-window-object-with-webpack
new webpack.ProvidePlugin({
// Automtically detect jQuery and $ as free var in modules
// and inject the jquery library
// This is required by many jquery plugins
jquery: "jquery",
jQuery: "jquery",
$: "jquery"
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': argv.mode === 'development' ? "\"development\"" : "\"production\""
}),
// http://stackoverflow.com/questions/29080148/expose-jquery-to-real-window-object-with-webpack
new webpack.ProvidePlugin({
// Automtically detect jQuery and $ as free var in modules
// and inject the jquery library
// This is required by many jquery plugins
jquery: "jquery",
jQuery: "jquery",
$: "jquery"
})
],
target: "web",
entry: {
engine: "./src/engine.js",
tests: "./tests/index.js",
"dist/engine": "./src/engine.js",
"tests/tests": "./tests/index.js",
},
devtool: "nosources-source-map",
devtool: "source-map",
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
devtoolModuleFilenameTemplate: "[id]"
path: path.resolve(__dirname, "./"),
filename: "[name].bundle.js"
},
module: {
rules: [
/* {
test: /\.css$/,
use: "style!css"
}*/
]
rules: []
},
optimization: {
removeAvailableModules: true,
@ -51,4 +48,4 @@ module.exports = {
devServer: {
publicPath: "/dist",
}
};
});