This commit is contained in:
danielyxie 2018-03-12 14:39:04 -05:00
parent 629e2eb425
commit f33d81b1a5
38 changed files with 26916 additions and 7217 deletions

@ -481,10 +481,6 @@ div.faction-clear {
width: 95%;
}
.installed-augmentation {
/* TODO */
}
/* Tutorial */
#tutorial-container {
position: fixed;

@ -253,6 +253,27 @@ a:link, a:visited {
visibility: visible;
}
/* help tip. Question mark that opens popup with info/details */
.help-tip {
content:'?';
padding:1px;
margin-left:3px;
color:#fff;
border:1px solid white;
border-radius:5px;
display:inline-block;
}
.help-tip:hover {
background-color: #888;
}
.help-tip:active {
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
-moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
}
/* Flashing button (Red) */
@-webkit-keyframes glowing {
0% { background-color: #B20000; -webkit-box-shadow: 0 0 3px #B20000; }

31862
dist/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.

BIN
doc/build/doctrees/shortcuts.doctree vendored Normal file

Binary file not shown.

@ -20,7 +20,7 @@ secrets that you've been searching for.
:caption: Contents:
Netscript <netscript>
Keyboard Shortcuts <shortcuts>
Indices and tables

@ -142,6 +142,68 @@ Comments are not evaluated as code, and can be used to document and/or explain c
* comment */
print("This code will actually get executed");
Importing Functions
-------------------
In Netscript you can import functions that are declared in other scripts.
The script will incur the RAM usage of all imported functions.
There are two ways of doing this::
import * as namespace from "script filename"; //Import all functions from script
import {fn1, fn2, ...} from "script filename"; //Import specific functions from script
Suppose you have a library script called *testlibrary.script*::
function foo1(args) {
//function definition...
}
function foo2(args) {
//function definition...
}
function foo3(args) {
//function definition...
}
function foo4(args) {
//function definition...
}
Then, if you wanted to use these functions in another script, you can import them like so::
import * as testlib from "testlibrary.script";
values = [1,2,3];
//The imported functions must be specified using the namespace
someVal1 = testlib.foo3(values);
someVal2 = testlib.foo1(values);
if (someVal1 > someVal2) {
//...
} else {
//...
}
If you only wanted to import certain functions, you can do so without needing
to specify a namespace for the import::
import {foo1, foo3} from "testlibrary.script"; //Saves RAM since not all functions are imported!
values = [1,2,3];
//No namespace needed
someVal1 = foo3(values);
someVal2 = foo1(values);
if (someVal1 > someVal2) {
//...
} else {
//...
}
Note that exporting functions is not required.
Javascript Math Module
----------------------

@ -0,0 +1,99 @@
Keyboard Shortcuts
==================
This page documents the various keyboard shortcuts that can be used in the game.
Game Navigation
---------------
These are used to switch between the different menus/tabs in the game.
These shortcuts are almost always available. Exceptions include:
* Working at a company or for a faction
* Creating a program
* Taking a university class
* Training at a gym
* Active Mission (aka Hacking Mission)
========== ===========================================================================
Shortcut Action
========== ===========================================================================
Alt + t Switch to Terminal
Alt + c Switch to 'Stats' page
Alt + e Switch to Script Editor. Will open up the last-edited file or a new file
Alt + s Switch to 'Active Scripts' page
Alt + h Switch to 'Hacknet Nodes' page
Alt + w Switch to 'City' page
Alt + j Go to the company where you are employed ('Job' page on navigation menu)
Alt + r Go to Travel Agency in current City ('Travel' page on navigation menu)
Alt + p Switch to 'Create Program' page
Alt + f Switch to 'Factions' page
Alt + a Switch to 'Augmentations' page
Alt + u Switch to 'Tutorial' page
Alt + o Switch to 'Options' page
========== ===========================================================================
Script Editor
-------------
These shortcuts are available only in the Script Editor
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Ctrl + b Save script and return to Terminal
Ctrl + space Function autocompletion
============= ===========================================================================
In the Script Editor you can configure your key binding mode to three preset options:
* `Ace <https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts>`_
* Vim
* Emacs
Terminal Shortcuts
------------------
These shortcuts are available only in the Terminal
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Up/Down arrow Cycle through previous commands
Ctrl + c Cancel a hack/analyze action
Ctrl + l Clear screen
Tab Autocomplete command
============= ===========================================================================
Terminal Bash Shortcuts
-----------------------
These shortcuts were implemented to better emulate a bash shell. They must be enabled
in your Terminal's *.fconf* file. This can be done be entering the Terminal command::
nano .fconf
and then setting the *ENABLE_BASH_HOTKEYS* option to 1.
**Note that these Bash shortcuts override any other shortcuts defined in the game (unless otherwise noted),
as well as your browser's shortcuts**
**Also note that more Bash-like shortcuts will be implemented in the future**
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Ctrl + c Clears current Terminal input (does NOT override default Ctrl + c command)
Ctrl + p Same as Up Arrow
Ctrl + n Same as Down Arrow
Ctrl + a Move cursor to beginning of line (same as 'Home' key)
Ctrl + e Move cursor to end of line (same as 'End' key)
Ctrl + b Move cursor to previous character
Alt + b Move cursor to previous word
Ctrl + f Move cursor to next character
Alt + f Move cursor to next word
Ctrl + h/d Delete previous character ('Backspace')
============= ===========================================================================
Misc Shortcuts
--------------
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Esc Close a script's log window
============= ===========================================================================

@ -443,6 +443,7 @@
<p class="caption"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="netscript.html"> Netscript</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
</ul>
<div role="search">

@ -201,6 +201,7 @@ secrets that you've been searching for.</p>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html"> Miscellaneous</a><ul>
<li class="toctree-l3"><a class="reference internal" href="netscriptmisc.html#netscript-ports">Netscript Ports</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptmisc.html#comments">Comments</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptmisc.html#importing-functions">Importing Functions</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptmisc.html#javascript-math-module">Javascript Math Module</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptmisc.html#javascript-date-module">Javascript Date Module</a></li>
<li class="toctree-l3"><a class="reference internal" href="netscriptmisc.html#javascript-number-module">Javascript Number Module</a></li>
@ -208,6 +209,14 @@ secrets that you've been searching for.</p>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="shortcuts.html#game-navigation">Game Navigation</a></li>
<li class="toctree-l2"><a class="reference internal" href="shortcuts.html#script-editor">Script Editor</a></li>
<li class="toctree-l2"><a class="reference internal" href="shortcuts.html#terminal-shortcuts">Terminal Shortcuts</a></li>
<li class="toctree-l2"><a class="reference internal" href="shortcuts.html#terminal-bash-shortcuts">Terminal Bash Shortcuts</a></li>
<li class="toctree-l2"><a class="reference internal" href="shortcuts.html#misc-shortcuts">Misc Shortcuts</a></li>
</ul>
</li>
</ul>
</div>
</div>
@ -231,6 +240,7 @@ secrets that you've been searching for.</p>
<p class="caption"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="netscript.html"> Netscript</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
</ul>
<div role="search">

@ -202,6 +202,7 @@ to reach out to the developer!</p>
<li class="toctree-l1"><a class="reference internal" href="netscriptmisc.html"> Miscellaneous</a><ul>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html#netscript-ports">Netscript Ports</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html#comments">Comments</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html#importing-functions">Importing Functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html#javascript-math-module">Javascript Math Module</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html#javascript-date-module">Javascript Date Module</a></li>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html#javascript-number-module">Javascript Number Module</a></li>
@ -233,6 +234,7 @@ to reach out to the developer!</p>
<li class="toctree-l2"><a class="reference internal" href="netscriptmisc.html"> Miscellaneous</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
</ul>
<div role="search">

@ -24,6 +24,7 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Keyboard Shortcuts" href="shortcuts.html" />
<link rel="prev" title="Netscript Singularity Functions" href="netscriptsingularityfunctions.html" />
</head>
<body>
@ -34,6 +35,8 @@
<div class="rel" role="navigation" aria-label="related navigation">
<a href="netscriptsingularityfunctions.html" title="Netscript Singularity Functions"
accesskey="P">previous</a> |
<a href="shortcuts.html" title="Keyboard Shortcuts"
accesskey="N">next</a> |
<a href="genindex.html" title="General Index"
accesskey="I">index</a>
</div>
@ -218,6 +221,66 @@ Comments are not evaluated as code, and can be used to document and/or explain c
</pre></div>
</div>
</div>
<div class="section" id="importing-functions">
<h2>Importing Functions<a class="headerlink" href="#importing-functions" title="Permalink to this headline"></a></h2>
<p>In Netscript you can import functions that are declared in other scripts.
The script will incur the RAM usage of all imported functions.
There are two ways of doing this:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="o">*</span> <span class="k">as</span> <span class="n">namespace</span> <span class="kn">from</span> <span class="s2">&quot;script filename&quot;</span><span class="p">;</span> <span class="o">//</span><span class="n">Import</span> <span class="nb">all</span> <span class="n">functions</span> <span class="kn">from</span> <span class="nn">script</span>
<span class="k">import</span> <span class="p">{</span><span class="n">fn1</span><span class="p">,</span> <span class="n">fn2</span><span class="p">,</span> <span class="o">...</span><span class="p">}</span> <span class="kn">from</span> <span class="s2">&quot;script filename&quot;</span><span class="p">;</span> <span class="o">//</span><span class="n">Import</span> <span class="n">specific</span> <span class="n">functions</span> <span class="kn">from</span> <span class="nn">script</span>
</pre></div>
</div>
<p>Suppose you have a library script called <em>testlibrary.script</em>:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">function</span> <span class="n">foo1</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
<span class="o">//</span><span class="n">function</span> <span class="n">definition</span><span class="o">...</span>
<span class="p">}</span>
<span class="n">function</span> <span class="n">foo2</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
<span class="o">//</span><span class="n">function</span> <span class="n">definition</span><span class="o">...</span>
<span class="p">}</span>
<span class="n">function</span> <span class="n">foo3</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
<span class="o">//</span><span class="n">function</span> <span class="n">definition</span><span class="o">...</span>
<span class="p">}</span>
<span class="n">function</span> <span class="n">foo4</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
<span class="o">//</span><span class="n">function</span> <span class="n">definition</span><span class="o">...</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Then, if you wanted to use these functions in another script, you can import them like so:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="o">*</span> <span class="k">as</span> <span class="n">testlib</span> <span class="kn">from</span> <span class="s2">&quot;testlibrary.script&quot;</span><span class="p">;</span>
<span class="n">values</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">];</span>
<span class="o">//</span><span class="n">The</span> <span class="n">imported</span> <span class="n">functions</span> <span class="n">must</span> <span class="n">be</span> <span class="n">specified</span> <span class="n">using</span> <span class="n">the</span> <span class="n">namespace</span>
<span class="n">someVal1</span> <span class="o">=</span> <span class="n">testlib</span><span class="o">.</span><span class="n">foo3</span><span class="p">(</span><span class="n">values</span><span class="p">);</span>
<span class="n">someVal2</span> <span class="o">=</span> <span class="n">testlib</span><span class="o">.</span><span class="n">foo1</span><span class="p">(</span><span class="n">values</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">someVal1</span> <span class="o">&gt;</span> <span class="n">someVal2</span><span class="p">)</span> <span class="p">{</span>
<span class="o">//...</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="o">//...</span>
<span class="p">}</span>
</pre></div>
</div>
<p>If you only wanted to import certain functions, you can do so without needing
to specify a namespace for the import:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span>import {foo1, foo3} from &quot;testlibrary.script&quot;; //Saves RAM since not all functions are imported!
values = [1,2,3];
//No namespace needed
someVal1 = foo3(values);
someVal2 = foo1(values);
if (someVal1 &gt; someVal2) {
//...
} else {
//...
}
</pre></div>
</div>
<p>Note that exporting functions is not required.</p>
</div>
<div class="section" id="javascript-math-module">
<h2>Javascript Math Module<a class="headerlink" href="#javascript-math-module" title="Permalink to this headline"></a></h2>
<p>The <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math">Javascript Math Module</a> is
@ -274,6 +337,7 @@ However, since the 'new' operator does not work in Netscript, only the Date modu
<li class="toctree-l2 current"><a class="current reference internal" href="#"> Miscellaneous</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#netscript-ports">Netscript Ports</a></li>
<li class="toctree-l3"><a class="reference internal" href="#comments">Comments</a></li>
<li class="toctree-l3"><a class="reference internal" href="#importing-functions">Importing Functions</a></li>
<li class="toctree-l3"><a class="reference internal" href="#javascript-math-module">Javascript Math Module</a></li>
<li class="toctree-l3"><a class="reference internal" href="#javascript-date-module">Javascript Date Module</a></li>
<li class="toctree-l3"><a class="reference internal" href="#javascript-number-module">Javascript Number Module</a></li>
@ -281,6 +345,7 @@ However, since the 'new' operator does not work in Netscript, only the Date modu
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
</ul>
<div role="search">
@ -303,6 +368,8 @@ However, since the 'new' operator does not work in Netscript, only the Date modu
<div role="navigation" aria-label="related navigaton">
<a href="netscriptsingularityfunctions.html" title="Netscript Singularity Functions"
>previous</a> |
<a href="shortcuts.html" title="Keyboard Shortcuts"
>next</a> |
<a href="genindex.html" title="General Index"
>index</a>
</div>

Binary file not shown.

@ -86,6 +86,7 @@
<p class="caption"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="netscript.html"> Netscript</a></li>
<li class="toctree-l1"><a class="reference internal" href="shortcuts.html"> Keyboard Shortcuts</a></li>
</ul>
<div role="search">

File diff suppressed because one or more lines are too long

314
doc/build/html/shortcuts.html vendored Normal file

@ -0,0 +1,314 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="English">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Keyboard Shortcuts &#8212; Bitburner 1.0 documentation</title>
<link rel="stylesheet" href="_static/agogo.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="prev" title="Netscript Miscellaneous" href="netscriptmisc.html" />
</head>
<body>
<div class="header-wrapper" role="banner">
<div class="header">
<div class="headertitle"><a
href="index.html">Bitburner 1.0 documentation</a></div>
<div class="rel" role="navigation" aria-label="related navigation">
<a href="netscriptmisc.html" title="Netscript Miscellaneous"
accesskey="P">previous</a> |
<a href="genindex.html" title="General Index"
accesskey="I">index</a>
</div>
</div>
</div>
<div class="content-wrapper">
<div class="content">
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="keyboard-shortcuts">
<h1>Keyboard Shortcuts<a class="headerlink" href="#keyboard-shortcuts" title="Permalink to this headline"></a></h1>
<p>This page documents the various keyboard shortcuts that can be used in the game.</p>
<div class="section" id="game-navigation">
<h2>Game Navigation<a class="headerlink" href="#game-navigation" title="Permalink to this headline"></a></h2>
<p>These are used to switch between the different menus/tabs in the game.
These shortcuts are almost always available. Exceptions include:</p>
<ul class="simple">
<li>Working at a company or for a faction</li>
<li>Creating a program</li>
<li>Taking a university class</li>
<li>Training at a gym</li>
<li>Active Mission (aka Hacking Mission)</li>
</ul>
<table border="1" class="docutils">
<colgroup>
<col width="12%" />
<col width="88%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Shortcut</th>
<th class="head">Action</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Alt + t</td>
<td>Switch to Terminal</td>
</tr>
<tr class="row-odd"><td>Alt + c</td>
<td>Switch to 'Stats' page</td>
</tr>
<tr class="row-even"><td>Alt + e</td>
<td>Switch to Script Editor. Will open up the last-edited file or a new file</td>
</tr>
<tr class="row-odd"><td>Alt + s</td>
<td>Switch to 'Active Scripts' page</td>
</tr>
<tr class="row-even"><td>Alt + h</td>
<td>Switch to 'Hacknet Nodes' page</td>
</tr>
<tr class="row-odd"><td>Alt + w</td>
<td>Switch to 'City' page</td>
</tr>
<tr class="row-even"><td>Alt + j</td>
<td>Go to the company where you are employed ('Job' page on navigation menu)</td>
</tr>
<tr class="row-odd"><td>Alt + r</td>
<td>Go to Travel Agency in current City ('Travel' page on navigation menu)</td>
</tr>
<tr class="row-even"><td>Alt + p</td>
<td>Switch to 'Create Program' page</td>
</tr>
<tr class="row-odd"><td>Alt + f</td>
<td>Switch to 'Factions' page</td>
</tr>
<tr class="row-even"><td>Alt + a</td>
<td>Switch to 'Augmentations' page</td>
</tr>
<tr class="row-odd"><td>Alt + u</td>
<td>Switch to 'Tutorial' page</td>
</tr>
<tr class="row-even"><td>Alt + o</td>
<td>Switch to 'Options' page</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="script-editor">
<h2>Script Editor<a class="headerlink" href="#script-editor" title="Permalink to this headline"></a></h2>
<p>These shortcuts are available only in the Script Editor</p>
<table border="1" class="docutils">
<colgroup>
<col width="15%" />
<col width="85%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Shortcut</th>
<th class="head">Action</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Ctrl + b</td>
<td>Save script and return to Terminal</td>
</tr>
<tr class="row-odd"><td>Ctrl + space</td>
<td>Function autocompletion</td>
</tr>
</tbody>
</table>
<p>In the Script Editor you can configure your key binding mode to three preset options:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts">Ace</a></li>
<li>Vim</li>
<li>Emacs</li>
</ul>
</div>
<div class="section" id="terminal-shortcuts">
<h2>Terminal Shortcuts<a class="headerlink" href="#terminal-shortcuts" title="Permalink to this headline"></a></h2>
<p>These shortcuts are available only in the Terminal</p>
<table border="1" class="docutils">
<colgroup>
<col width="15%" />
<col width="85%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Shortcut</th>
<th class="head">Action</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Up/Down arrow</td>
<td>Cycle through previous commands</td>
</tr>
<tr class="row-odd"><td>Ctrl + c</td>
<td>Cancel a hack/analyze action</td>
</tr>
<tr class="row-even"><td>Ctrl + l</td>
<td>Clear screen</td>
</tr>
<tr class="row-odd"><td>Tab</td>
<td>Autocomplete command</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="terminal-bash-shortcuts">
<h2>Terminal Bash Shortcuts<a class="headerlink" href="#terminal-bash-shortcuts" title="Permalink to this headline"></a></h2>
<p>These shortcuts were implemented to better emulate a bash shell. They must be enabled
in your Terminal's <em>.fconf</em> file. This can be done be entering the Terminal command:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">nano</span> <span class="o">.</span><span class="n">fconf</span>
</pre></div>
</div>
<p>and then setting the <em>ENABLE_BASH_HOTKEYS</em> option to 1.</p>
<p><strong>Note that these Bash shortcuts override any other shortcuts defined in the game (unless otherwise noted),
as well as your browser's shortcuts</strong></p>
<p><strong>Also note that more Bash-like shortcuts will be implemented in the future</strong></p>
<table border="1" class="docutils">
<colgroup>
<col width="15%" />
<col width="85%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Shortcut</th>
<th class="head">Action</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Ctrl + c</td>
<td>Clears current Terminal input (does NOT override default Ctrl + c command)</td>
</tr>
<tr class="row-odd"><td>Ctrl + p</td>
<td>Same as Up Arrow</td>
</tr>
<tr class="row-even"><td>Ctrl + n</td>
<td>Same as Down Arrow</td>
</tr>
<tr class="row-odd"><td>Ctrl + a</td>
<td>Move cursor to beginning of line (same as 'Home' key)</td>
</tr>
<tr class="row-even"><td>Ctrl + e</td>
<td>Move cursor to end of line (same as 'End' key)</td>
</tr>
<tr class="row-odd"><td>Ctrl + b</td>
<td>Move cursor to previous character</td>
</tr>
<tr class="row-even"><td>Alt + b</td>
<td>Move cursor to previous word</td>
</tr>
<tr class="row-odd"><td>Ctrl + f</td>
<td>Move cursor to next character</td>
</tr>
<tr class="row-even"><td>Alt + f</td>
<td>Move cursor to next word</td>
</tr>
<tr class="row-odd"><td>Ctrl + h/d</td>
<td>Delete previous character ('Backspace')</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="misc-shortcuts">
<h2>Misc Shortcuts<a class="headerlink" href="#misc-shortcuts" title="Permalink to this headline"></a></h2>
<table border="1" class="docutils">
<colgroup>
<col width="15%" />
<col width="85%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Shortcut</th>
<th class="head">Action</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>Esc</td>
<td>Close a script's log window</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sidebar">
<h3>Table Of Contents</h3>
<p class="caption"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="netscript.html"> Netscript</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#"> Keyboard Shortcuts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#game-navigation">Game Navigation</a></li>
<li class="toctree-l2"><a class="reference internal" href="#script-editor">Script Editor</a></li>
<li class="toctree-l2"><a class="reference internal" href="#terminal-shortcuts">Terminal Shortcuts</a></li>
<li class="toctree-l2"><a class="reference internal" href="#terminal-bash-shortcuts">Terminal Bash Shortcuts</a></li>
<li class="toctree-l2"><a class="reference internal" href="#misc-shortcuts">Misc Shortcuts</a></li>
</ul>
</li>
</ul>
<div role="search">
<h3 style="margin-top: 1.5em;">Search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
<div class="footer-wrapper">
<div class="footer">
<div class="left">
<div role="navigation" aria-label="related navigaton">
<a href="netscriptmisc.html" title="Netscript Miscellaneous"
>previous</a> |
<a href="genindex.html" title="General Index"
>index</a>
</div>
<div role="note" aria-label="source link">
<br/>
<a href="_sources/shortcuts.rst.txt"
rel="nofollow">Show Source</a>
</div>
</div>
<div class="right">
<div class="footer" role="contentinfo">
&#169; Copyright 2017, Bitburner.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.6.4.
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</body>
</html>

@ -20,7 +20,7 @@ secrets that you've been searching for.
:caption: Contents:
Netscript <netscript>
Keyboard Shortcuts <shortcuts>
Indices and tables

@ -142,6 +142,68 @@ Comments are not evaluated as code, and can be used to document and/or explain c
* comment */
print("This code will actually get executed");
Importing Functions
-------------------
In Netscript you can import functions that are declared in other scripts.
The script will incur the RAM usage of all imported functions.
There are two ways of doing this::
import * as namespace from "script filename"; //Import all functions from script
import {fn1, fn2, ...} from "script filename"; //Import specific functions from script
Suppose you have a library script called *testlibrary.script*::
function foo1(args) {
//function definition...
}
function foo2(args) {
//function definition...
}
function foo3(args) {
//function definition...
}
function foo4(args) {
//function definition...
}
Then, if you wanted to use these functions in another script, you can import them like so::
import * as testlib from "testlibrary.script";
values = [1,2,3];
//The imported functions must be specified using the namespace
someVal1 = testlib.foo3(values);
someVal2 = testlib.foo1(values);
if (someVal1 > someVal2) {
//...
} else {
//...
}
If you only wanted to import certain functions, you can do so without needing
to specify a namespace for the import::
import {foo1, foo3} from "testlibrary.script"; //Saves RAM since not all functions are imported!
values = [1,2,3];
//No namespace needed
someVal1 = foo3(values);
someVal2 = foo1(values);
if (someVal1 > someVal2) {
//...
} else {
//...
}
Note that exporting functions is not required.
Javascript Math Module
----------------------

99
doc/source/shortcuts.rst Normal file

@ -0,0 +1,99 @@
Keyboard Shortcuts
==================
This page documents the various keyboard shortcuts that can be used in the game.
Game Navigation
---------------
These are used to switch between the different menus/tabs in the game.
These shortcuts are almost always available. Exceptions include:
* Working at a company or for a faction
* Creating a program
* Taking a university class
* Training at a gym
* Active Mission (aka Hacking Mission)
========== ===========================================================================
Shortcut Action
========== ===========================================================================
Alt + t Switch to Terminal
Alt + c Switch to 'Stats' page
Alt + e Switch to Script Editor. Will open up the last-edited file or a new file
Alt + s Switch to 'Active Scripts' page
Alt + h Switch to 'Hacknet Nodes' page
Alt + w Switch to 'City' page
Alt + j Go to the company where you are employed ('Job' page on navigation menu)
Alt + r Go to Travel Agency in current City ('Travel' page on navigation menu)
Alt + p Switch to 'Create Program' page
Alt + f Switch to 'Factions' page
Alt + a Switch to 'Augmentations' page
Alt + u Switch to 'Tutorial' page
Alt + o Switch to 'Options' page
========== ===========================================================================
Script Editor
-------------
These shortcuts are available only in the Script Editor
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Ctrl + b Save script and return to Terminal
Ctrl + space Function autocompletion
============= ===========================================================================
In the Script Editor you can configure your key binding mode to three preset options:
* `Ace <https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts>`_
* Vim
* Emacs
Terminal Shortcuts
------------------
These shortcuts are available only in the Terminal
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Up/Down arrow Cycle through previous commands
Ctrl + c Cancel a hack/analyze action
Ctrl + l Clear screen
Tab Autocomplete command
============= ===========================================================================
Terminal Bash Shortcuts
-----------------------
These shortcuts were implemented to better emulate a bash shell. They must be enabled
in your Terminal's *.fconf* file. This can be done be entering the Terminal command::
nano .fconf
and then setting the *ENABLE_BASH_HOTKEYS* option to 1.
**Note that these Bash shortcuts override any other shortcuts defined in the game (unless otherwise noted),
as well as your browser's shortcuts**
**Also note that more Bash-like shortcuts will be implemented in the future**
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Ctrl + c Clears current Terminal input (does NOT override default Ctrl + c command)
Ctrl + p Same as Up Arrow
Ctrl + m Same as Down Arrow
Ctrl + a Move cursor to beginning of line (same as 'Home' key)
Ctrl + e Move cursor to end of line (same as 'End' key)
Ctrl + b Move cursor to previous character
Alt + b Move cursor to previous word
Ctrl + f Move cursor to next character
Alt + f Move cursor to next word
Ctrl + h/d Delete previous character ('Backspace')
============= ===========================================================================
Misc Shortcuts
--------------
============= ===========================================================================
Shortcut Action
============= ===========================================================================
Esc Close a script's log window
============= ===========================================================================

@ -578,6 +578,7 @@
<ul id="queued-augmentations-list"></ul>
<br>
<a id="install-augmentations-button" class="a-link-button"> Install Augmentations </a>
<a id="install-augmentations-backup-button" class="a-link-button"> Backup Save (Export) </a>
<br><br>
<h1> Installed Augmentations </h1>
<p style="width:70%;"> List of all augmentations (including Source Files) that have been installed. You have gained the effects of these augmentations </p>

@ -39,7 +39,7 @@ routines, to develop your own software, but may not duplicate the Source Code. T
right referenced in the preceding sentence is hereinafter referred to as "Educational Use." By so exercising the Educational
Use right you shall not obtain any ownership, copyright, proprietary or other interest in or to the Source Code, or any portion
of the Source Code. You may dispose of your own software in your sole discretion. When exercising the Educational Use right,
you may not use or exploit the Software, or an portion of the Software, which includes the Source Code, for commercial gain.
you may not use or exploit the Software, or any portion of the Software, which includes the Source Code, for commercial gain.
3. Prohibited Uses: Under no circumstances shall you, the end-user, be permitted, allowed or authorized to commercially
exploit the Software or any work that in whole or in part contains or is derived from the Software or any part thereof.

65
package-lock.json generated

@ -7211,6 +7211,11 @@
"event-emitter": "0.3.5"
}
},
"es6-promise": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz",
"integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y="
},
"es6-promise-polyfill": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/es6-promise-polyfill/-/es6-promise-polyfill-1.2.0.tgz",
@ -7765,6 +7770,11 @@
"loader-utils": "1.1.0"
}
},
"file-saver": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz",
"integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI="
},
"filename-regex": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
@ -8537,6 +8547,11 @@
"dev": true,
"optional": true
},
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@ -9290,6 +9305,48 @@
"promise": "6.1.0"
}
},
"jszip": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz",
"integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==",
"requires": {
"core-js": "2.3.0",
"es6-promise": "3.0.2",
"lie": "3.1.1",
"pako": "1.0.6",
"readable-stream": "2.0.6"
},
"dependencies": {
"core-js": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz",
"integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"readable-stream": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"string_decoder": "0.10.31",
"util-deprecate": "1.0.2"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
}
}
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
@ -9589,6 +9646,14 @@
"type-check": "0.3.2"
}
},
"lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
"requires": {
"immediate": "3.0.6"
}
},
"listr": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz",

@ -42,11 +42,13 @@
"brace": "^0.11.1",
"enhanced-resolve": "^3.4.0",
"escope": "^3.6.0",
"file-saver": "^1.3.3",
"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",

@ -323,7 +323,8 @@ Product.prototype.finishProduct = function(employeeProd, industry) {
console.log("designMult: " + designMult);
var balanceMult = (1.2 * engrRatio) + (0.9 * mgmtRatio) + (1.3 * rndRatio) +
(1.5 * opsRatio) + (busRatio);
var totalMult = progrMult * balanceMult * designMult;
var sciMult = 1 + (Math.pow(industry.sciResearch.qty, industry.sciFac) / 1000);
var totalMult = progrMult * balanceMult * designMult * sciMult;
this.qlt = totalMult * ((0.10 * employeeProd[EmployeePositions.Engineer]) +
(0.05 * employeeProd[EmployeePositions.Management]) +
@ -357,7 +358,7 @@ Product.prototype.finishProduct = function(employeeProd, industry) {
(0.05 * employeeProd[EmployeePositions.Business]));
this.calculateRating(industry);
var advMult = 1 + (Math.pow(this.advCost, 0.1) / 100);
this.mku = 100 / (advMult * Math.pow((this.qlt + 0.001), 0.75) * (busRatio + mgmtRatio));
this.mku = 100 / (advMult * Math.pow((this.qlt + 0.001), 0.6) * (busRatio + mgmtRatio));
this.dmd = industry.awareness === 0 ? 20 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness)));
this.cmp = getRandomInt(0, 70);
@ -483,7 +484,7 @@ var IndustryDescriptions = {
Healthcare: "Create and manage hospitals.<br><br>" +
"Starting cost: " + numeral(IndustryStartingCosts.Healthcare).format("$0.000a") + "<br>" +
"Recommended starting Industry: NO",
RealEstate: "Develop and manuage real estate properties.<br><br>" +
RealEstate: "Develop and manage real estate properties.<br><br>" +
"Starting cost: " + numeral(IndustryStartingCosts.RealEstate).format("$0.000a") + "<br>" +
"Recommended starting Industry: NO",
}
@ -552,11 +553,11 @@ var ProductRatingWeights = {
var IndustryUpgrades = {
"0": [0, 500e3, 1, 1.05,
"Coffee", "Provide your employees with coffee, increasing their energy by 5%."],
"1": [1, 1e9, 1.03, 1.03,
"1": [1, 1e9, 1.05, 1.03,
"AdVert.Inc", "Hire AdVert.Inc to advertise your company. Each level of " +
"this upgrade grants your company a static increase of 4 and 1 to its awareness and " +
"popularity, respectively. It will then increase your company's awareness by 1%, and its popularity " +
"by a random percentage between 3% and 6%. These effects are increased by other upgrades " +
"by a random percentage between 2% and 4%. These effects are increased by other upgrades " +
"that increase the power of your advertising."]
}
@ -786,8 +787,8 @@ Industry.prototype.init = function() {
this.makesProducts = true;
break;
case Industries.Software:
this.sciFac = 0.7;
this.advFac = 0.18;
this.sciFac = 0.65;
this.advFac = 0.16;
this.hwFac = 0.25;
this.reFac = 0.1;
this.aiFac = 0.1;
@ -871,20 +872,26 @@ Industry.prototype.getProductDescriptionText = function() {
//Calculates the values that factor into the production and properties of
//materials/products (such as quality, etc.)
Industry.prototype.calculateProductionFactors = function(city) {
Industry.prototype.calculateProductionFactors = function() {
var multSum = 0;
for (var i = 0; i < Cities.length; ++i) {
var city = Cities[i];
var warehouse = this.warehouses[city];
if (!(warehouse instanceof Warehouse)) {
this.prodMult = 0;
return;
continue;
}
var materials = warehouse.materials,
office = this.offices[city];
//Production is multiplied by this
this.prodMult = Math.pow(0.002 * materials.RealEstate.qty+1, this.reFac) *
var cityMult = Math.pow(0.002 * materials.RealEstate.qty+1, this.reFac) *
Math.pow(0.002 * materials.Hardware.qty+1, this.hwFac) *
Math.pow(0.002 * materials.Robots.qty+1, this.robFac) *
Math.pow(0.002 * materials.AICores.qty+1, this.aiFac);
if (this.prodMult < 1) {this.prodMult = 1;}
multSum += Math.pow(cityMult, 0.73);
}
multSum < 1 ? this.prodMult = 1 : this.prodMult = multSum;
}
Industry.prototype.updateWarehouseSizeUsed = function(warehouse) {
@ -897,6 +904,9 @@ Industry.prototype.updateWarehouseSizeUsed = function(warehouse) {
if (this.products.hasOwnProperty(prodName)) {
var prod = this.products[prodName];
warehouse.sizeUsed += (prod.data[warehouse.loc][0] * prod.siz);
if (prod.data[warehouse.loc][0] > 0 && warehouse.loc === currentCityUi) {
industryWarehouseStorageBreakdownText += (prodName + ": " + formatNumber(prod.data[warehouse.loc][0] * prod.siz, 0) + "<br>");
}
}
}
}
@ -1017,12 +1027,12 @@ Industry.prototype.processProductMarket = function(marketCycles=1) {
//Process production, purchase, and import/export of materials
Industry.prototype.processMaterials = function(marketCycles=1, company) {
var revenue = 0, expenses = 0;
var revenue = 0, expenses = 0, industry = this;
this.calculateProductionFactors();
for (var i = 0; i < Cities.length; ++i) {
var city = Cities[i], office = this.offices[city];
if (this.warehouses[city] instanceof Warehouse) {
this.calculateProductionFactors(city);
var warehouse = this.warehouses[city];
switch(this.state) {
@ -1031,9 +1041,17 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
/* Process purchase of materials */
for (var matName in warehouse.materials) {
if (warehouse.materials.hasOwnProperty(matName)) {
(function(matName) {
(function(matName, ind) {
var mat = warehouse.materials[matName];
var buyAmt = (mat.buy * SecsPerMarketCycle * marketCycles), maxAmt
var buyAmt, maxAmt;
if (warehouse.smartSupplyEnabled && Object.keys(ind.reqMats).includes(matName)) {
//Smart supply tracker is stored as per second rate
mat.buy = ind.reqMats[matName] * warehouse.smartSupplyStore;
buyAmt = mat.buy * SecsPerMarketCycle * marketCycles;
} else {
buyAmt = (mat.buy * SecsPerMarketCycle * marketCycles);
}
if (matName == "RealEstate") {
maxAmt = buyAmt;
} else {
@ -1044,13 +1062,15 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
mat.qty += buyAmt;
expenses += (buyAmt * mat.bCost);
}
})(matName);
})(matName, industry);
this.updateWarehouseSizeUsed(warehouse);
}
} //End process purchase of materials
break;
case "PRODUCTION":
warehouse.smartSupplyStore = 0; //Reset smart supply amount
/* Process production of materials */
if (this.prodMats.length > 0) {
var mat = warehouse.materials[this.prodMats[0]];
@ -1083,6 +1103,9 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
prod = Math.min(maxAmt, prod);
}
//Keep track of production for smart supply (/s)
warehouse.smartSupplyStore += (prod / (SecsPerMarketCycle * marketCycles));
//Make sure we have enough resource to make our materials
var producableFrac = 1;
for (var reqMatName in this.reqMats) {
@ -1220,10 +1243,10 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
var expIndustry = company.divisions[foo];
var expWarehouse = expIndustry.warehouses[exp.city];
if (!(expWarehouse instanceof Warehouse)) {
console.log("ERROR: Invalid export!");
console.log("ERROR: Invalid export! " + expIndustry.name + " " + exp.city);
break;
}
expWarehouse.materials[mat.name].qty += amt;
expWarehouse.materials[matName].qty += amt;
mat.qty -= amt;
break;
}
@ -1275,7 +1298,7 @@ Industry.prototype.processProducts = function(marketCycles=1, corporation) {
office.employeeProd[EmployeePositions.Operations] / total +
office.employeeProd[EmployeePositions.Management] / total;
}
prod.createProduct(marketCycles, ratio * Math.pow(total, 0.3));
prod.createProduct(marketCycles, ratio * Math.pow(total, 0.29));
if (prod.prog >= 100) {
prod.finishProduct(office.employeeProd, this);
}
@ -1334,6 +1357,8 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
prod = Math.min(maxAmt, prod);
}
warehouse.smartSupplyStore += (prod / (SecsPerMarketCycle * marketCycles));
//Make sure we have enough resources to make our Products
var producableFrac = 1;
for (var reqMatName in product.reqMats) {
@ -1384,8 +1409,8 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
var businessFactor = this.getBusinessFactor(office); //Business employee productivity
var advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
var marketFactor = this.getMarketFactor(product); //Competition + demand
var maxSell = Math.pow(product.rat, 0.9) * marketFactor * corporation.getSalesMultiplier() *
markup * businessFactor * advertisingFactor;
var maxSell = 0.5 * Math.pow(product.rat, 0.65) * marketFactor * corporation.getSalesMultiplier() *
Math.pow(markup, 2) * businessFactor * advertisingFactor;
var sellAmt;
if (product.sllman[city][0] && product.sllman[city][1] > 0) {
//Sell amount is manually limited
@ -1448,7 +1473,7 @@ Industry.prototype.upgrade = function(upgrade, refs) {
this.awareness += (4 * advMult);
this.popularity += (1 * advMult);
this.awareness *= (1.01 * advMult);
this.popularity *= ((1 + getRandomInt(3, 6) / 100) * advMult);
this.popularity *= ((1 + getRandomInt(2, 4) / 100) * advMult);
break;
default:
console.log("ERROR: Un-implemented function index: " + upgN);
@ -1492,7 +1517,7 @@ Industry.prototype.getAdvertisingFactors = function() {
var awarenessFac = Math.pow(this.awareness + 1, this.advFac);
var popularityFac = Math.pow(this.popularity + 1, this.advFac);
var ratioFac = (this.awareness === 0 ? 0.01 : Math.max((this.popularity + .001) / this.awareness, 0.01));
var totalFac = awarenessFac * popularityFac * ratioFac;
var totalFac = Math.pow(awarenessFac * popularityFac * ratioFac, 0.85);
return [totalFac, awarenessFac, popularityFac, ratioFac];
}
@ -1960,8 +1985,13 @@ function Warehouse(params={}) {
this.loc = params.loc ? params.loc : "";
this.size = params.size ? params.size : 0;
this.level = 0;
this.sizeUsed = 0;
this.smartSupplyEnabled = false; //Whether or not smart supply is enabled
//Stores the amount of product to be produced. Used for Smart Supply unlock.
//The production tracked by smart supply is always based on the previous cycle,
//so it will always trail the "true" production by 1 cycle
this.smartSupplyStore = 0;
this.materials = {
Water: new Material({name: "Water"}),
@ -1980,11 +2010,15 @@ function Warehouse(params={}) {
Warehouse.prototype.updateMaterialSizeUsed = function() {
this.sizeUsed = 0;
if (this.loc === currentCityUi) {industryWarehouseStorageBreakdownText = ""; }
for (var matName in this.materials) {
if (this.materials.hasOwnProperty(matName)) {
var mat = this.materials[matName];
if (MaterialSizes.hasOwnProperty(matName)) {
this.sizeUsed += (mat.qty * MaterialSizes[matName]);
if (mat.qty > 0 && this.loc === currentCityUi) {
industryWarehouseStorageBreakdownText += (matName + ": " + formatNumber(mat.qty * MaterialSizes[matName], 0) + "<br>");
}
}
}
}
@ -2009,18 +2043,15 @@ Warehouse.prototype.createUI = function(parentRefs) {
}
var company = parentRefs.company, industry = parentRefs.industry;
removeChildrenFromElement(industryWarehousePanel);
var storageText = "Storage: " +
(this.sizedUsed >= this.size ? formatNumber(this.sizeUsed, 3) : formatNumber(this.sizeUsed, 3)) +
"/" + formatNumber(this.size, 3);
industryWarehousePanel.appendChild(createElement("p", {
innerHTML: storageText,
display:"inline-block",
industryWarehouseStorageText = createElement("p", {
display:"inline-block", class:"tooltip",
color: this.sizeUsed >= this.size ? "red" : "white",
}));
});
industryWarehousePanel.appendChild(industryWarehouseStorageText);
//Upgrade warehouse size button
var upgradeCost = WarehouseUpgradeBaseCost * Math.pow(1.07, Math.round(this.size / 100) - 1);
industryWarehousePanel.appendChild(createElement("a", {
industryWarehouseUpgradeSizeButton = createElement("a", {
innerText:"Upgrade Warehouse Size - " + numeral(upgradeCost).format('$0.000a'),
display:"inline-block",
class: company.funds.lt(upgradeCost) ? "a-link-button-inactive" : "a-link-button",
@ -2036,7 +2067,8 @@ Warehouse.prototype.createUI = function(parentRefs) {
this.createUI(parentRefs);
return;
}
}));
});
industryWarehousePanel.appendChild(industryWarehouseUpgradeSizeButton);
//Material requirement text
var reqText = "This Industry uses [" + Object.keys(industry.reqMats).join(", ") +
@ -2050,28 +2082,7 @@ Warehouse.prototype.createUI = function(parentRefs) {
reqText += industry.getProductDescriptionText();
}
reqText += "<br><br>To get started with production, purchase your required " +
"materials or import them from another of your company's divisions.<br><br>" +
"Current state: ";
switch(industry.state) {
case "START":
reqText += "Preparing...";
break;
case "PURCHASE":
reqText += "Purchasing materials...";
break;
case "PRODUCTION":
reqText += "Producing materials and/or products...";
break;
case "SALE":
reqText += "Selling materials and/or products...";
break;
case "EXPORT":
reqText += "Exporting materials and/or products...";
break;
default:
console.log("ERROR: Invalid state: " + industry.state);
break;
}
"materials or import them from another of your company's divisions.<br><br>";
//Material ratio text for tooltip
var reqRatioText = "The exact requirements for production are:<br>";
@ -2094,28 +2105,116 @@ Warehouse.prototype.createUI = function(parentRefs) {
innerHTML:reqText, tooltipleft:reqRatioText
}));
//Current state
industryWarehouseStateText = createElement("p");
industryWarehousePanel.appendChild(industryWarehouseStateText);
//Smart Supply Enable/Disable
if (company.unlockUpgrades[1]) {
if (this.smartSupplyEnabled == null) {this.smartSupplyEnabled = false;}
var smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox";
industryWarehousePanel.appendChild(createElement("label", {
for:smartSupplyCheckboxId, innerText:"Enable Smart Supply",
color:"white"
}));
industrySmartSupplyCheckbox = createElement("input", {
type:"checkbox", id:smartSupplyCheckboxId, margin:"3px",
changeListener:()=>{
this.smartSupplyEnabled = industrySmartSupplyCheckbox.checked;
}
});
industrySmartSupplyCheckbox.checked = this.smartSupplyEnabled;
industryWarehousePanel.appendChild(industrySmartSupplyCheckbox);
}
//Materials
industryWarehousePanel.appendChild(createElement("p", {
innerHTML: "<br>Materials:<br>",
}));
industryWarehouseMaterials = createElement("ul");
industryWarehousePanel.appendChild(industryWarehouseMaterials);
//Products
if (industry.makesProducts && Object.keys(industry.products).length > 0) {
industryWarehousePanel.appendChild(createElement("p", {
innerHTML: "<br>Products:<br>",
}));
industryWarehouseProducts = createElement("ul");
industryWarehousePanel.appendChild(industryWarehouseProducts);
}
this.updateUI(parentRefs);
}
Warehouse.prototype.updateUI = function(parentRefs) {
if (parentRefs.company == null || parentRefs.industry == null) {
console.log("ERROR: Warehouse.updateUI called without parentRefs.company or parentRefs.industry");
return;
}
var company = parentRefs.company, industry = parentRefs.industry;
//Storage text
var storageText = "Storage: " +
(this.sizedUsed >= this.size ? formatNumber(this.sizeUsed, 3) : formatNumber(this.sizeUsed, 3)) +
"/" + formatNumber(this.size, 3);
if (industryWarehouseStorageBreakdownText != null &&
industryWarehouseStorageBreakdownText != "") {
storageText += ("<span class='tooltiptext'>" +
industryWarehouseStorageBreakdownText + "</span>");
}
industryWarehouseStorageText.innerHTML = storageText;
//Upgrade warehouse size button
var upgradeCost = WarehouseUpgradeBaseCost * Math.pow(1.07, Math.round(this.size / 100) - 1);
if (company.funds.lt(upgradeCost)) {
industryWarehouseUpgradeSizeButton.className = "a-link-button-inactive";
} else {
industryWarehouseUpgradeSizeButton.className = "a-link-button";
}
//Current state
var stateText = "Current state: ";
switch(industry.state) {
case "START":
stateText += "Preparing...";
break;
case "PURCHASE":
stateText += "Purchasing materials...";
break;
case "PRODUCTION":
stateText += "Producing materials and/or products...";
break;
case "SALE":
stateText += "Selling materials and/or products...";
break;
case "EXPORT":
stateText += "Exporting materials and/or products...";
break;
default:
console.log("ERROR: Invalid state: " + industry.state);
break;
}
industryWarehouseStateText.innerText = stateText;
//Materials
removeChildrenFromElement(industryWarehouseMaterials);
for (var matName in this.materials) {
if (this.materials.hasOwnProperty(matName) && this.materials[matName] instanceof Material) {
if (Object.keys(industry.reqMats).includes(matName) || industry.prodMats.includes(matName) ||
matName === "Hardware" || matName === "Robots" || matName === "AICores" ||
matName === "RealEstate") {
this.createMaterialUI(this.materials[matName], matName, parentRefs);
industryWarehouseMaterials.appendChild(this.createMaterialUI(this.materials[matName], matName, parentRefs));
}
}
}
//Products
if (!(industry.makesProducts && Object.keys(industry.products).length > 0)) {return;}
industryWarehousePanel.appendChild(createElement("p", {
innerHTML: "<br>Products:<br>",
}));
if (industry.makesProducts && Object.keys(industry.products).length > 0) {
removeChildrenFromElement(industryWarehouseProducts);
for (var productName in industry.products) {
if (industry.products.hasOwnProperty(productName) && industry.products[productName] instanceof Product) {
this.createProductUI(industry.products[productName], parentRefs);
industryWarehouseProducts.appendChild(this.createProductUI(industry.products[productName], parentRefs));
}
}
}
}
@ -2185,9 +2284,7 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
type:"number", value:mat.buy ? mat.buy : null, placeholder: "Purchase amount",
onkeyup:(e)=>{
e.preventDefault();
if (e.keyCode === 13) {
confirmBtn.click();
}
if (e.keyCode === 13) {confirmBtn.click();}
}
});
confirmBtn = createElement("a", {
@ -2239,11 +2336,8 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
});
//Select industry and city to export to
var industrySelector = createElement("select", {}),
citySelector = createElement("select", {});
for (var i = 0; i < company.divisions.length; ++i) {
industrySelector.add(createElement("option", {
text:company.divisions[i].name, value:company.divisions[i].name,
var citySelector = createElement("select");
var industrySelector = createElement("select", {
changeListener:()=>{
var industryName = industrySelector.options[industrySelector.selectedIndex].value;
for (var foo = 0; foo < company.divisions.length; ++foo) {
@ -2261,6 +2355,11 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
}
}
}
});
for (var i = 0; i < company.divisions.length; ++i) {
industrySelector.add(createElement("option", {
text:company.divisions[i].name, value:company.divisions[i].name,
})); //End create element option
} //End for
@ -2471,7 +2570,7 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
}
}));
industryWarehousePanel.appendChild(div);
return div;
}
Warehouse.prototype.createProductUI = function(product, parentRefs) {
@ -2487,8 +2586,7 @@ Warehouse.prototype.createProductUI = function(product, parentRefs) {
innerHTML: "Designing " + product.name + "...<br>" +
formatNumber(product.prog, 2) + "% complete",
}));
industryWarehousePanel.appendChild(div);
return;
return div;
}
//Completed products
@ -2517,7 +2615,10 @@ Warehouse.prototype.createProductUI = function(product, parentRefs) {
"<span class='tooltiptext'>An estimate of how much it costs to produce one unit of this product. " +
"If your sell price exceeds this by too much, people won't buy your product. The better your " +
"product is, the higher you can mark up its price.</span></p><br>" +
"Size: " + formatNumber(product.siz, 3),
"<p class='tooltip'>Est. Market Price: " + numeral(product.pCost + product.rat / product.mku).format("$0.000a") +
"<span class='tooltiptext'>An estimate of how much consumers are willing to pay for this product. " +
"Setting the sale price above this may result in less sales. Setting the sale price below this may result " +
"in more sales.</span></p>"
}));
var buttonPanel = createElement("div", {
display:"inline-block",
@ -2688,7 +2789,7 @@ Warehouse.prototype.createProductUI = function(product, parentRefs) {
createPopup(popupId, [txt, confirmBtn, cancelBtn]);
}
}));
industryWarehousePanel.appendChild(div);
return div;
}
Warehouse.prototype.toJSON = function() {
@ -2711,7 +2812,7 @@ var CorporationUnlockUpgrades = {
"This allows you to move materials around between different divisions and cities."],
//Lets you buy exactly however many required materials you need for production
"1": [1, 999999e9, "Smart Supply", "NOT YET IMPLEMENTED!!!!!! - Use advanced AI to anticipate your supply needs. " +
"1": [1, 50e9, "Smart Supply", "Use advanced AI to anticipate your supply needs. " +
"This allows you to purchase exactly however many materials you need for production."],
//Displays each material/product's demand
@ -2754,10 +2855,10 @@ var CorporationUpgrades = {
"20 seconds."],
//Makes advertising more effective
"3": [3, 4e9, 1.12, 0.01,
"3": [3, 4e9, 1.12, 0.005,
"Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " +
"firm. Each level of this upgrades increases the effectiveness of your " +
"advertising by 1% (additive)."],
"advertising by 0.5% (additive)."],
//Augmentation for employees, increases cre
"4": [4, 1e9, 1.06, 0.1,
@ -2825,12 +2926,15 @@ Corporation.prototype.getState = function() {
return this.state.getState();
}
var numMarketCyclesPersist = 1;
Corporation.prototype.process = function(numCycles=1) {
var corp = this;
Corporation.prototype.storeCycles = function(numCycles=1) {
this.storedCycles += numCycles;
}
Corporation.prototype.process = function() {
var corp = this;
if (this.storedCycles >= CyclesPerIndustryStateCycle) {
var state = this.getState();
var state = this.getState(), marketCycles=1;
this.storedCycles -= (marketCycles * CyclesPerIndustryStateCycle);
//At the start of a new cycle, calculate profits from previous cycle
if (state === "START") {
@ -2841,7 +2945,7 @@ Corporation.prototype.process = function(numCycles=1) {
this.expenses = this.expenses.plus(ind.lastCycleExpenses);
});
var profit = this.revenue.minus(this.expenses);
var cycleProfit = profit.times(numMarketCyclesPersist * SecsPerMarketCycle);
var cycleProfit = profit.times(marketCycles * SecsPerMarketCycle);
if (isNaN(this.funds)) {
dialogBoxCreate("There was an error calculating your Corporations funds and they got reset to 0. " +
"This is a bug. Please report to game developer.<br><br>" +
@ -2852,19 +2956,6 @@ Corporation.prototype.process = function(numCycles=1) {
this.updateSharePrice();
}
//Determine number of market cycles at the START state
if (state === "START") {
if (this.storedCycles >= 2*CyclesPerMarketCycle) {
//Enough cycles stored for 2+ market cycles
//Capped out at 3 to prevent weird behavior
numMarketCyclesPersist = Math.max(3, Math.floor(this.storedCycles / CyclesPerMarketCycle));
} else {
numMarketCyclesPersist = 1;
}
}
var marketCycles = numMarketCyclesPersist;
this.storedCycles -= (marketCycles * CyclesPerIndustryStateCycle);
this.divisions.forEach(function(ind) {
ind.process(marketCycles, state, corp);
});
@ -2948,12 +3039,17 @@ Corporation.prototype.goPublic = function() {
"your company's stock price in the future.<br><br>" +
"You have a total of " + numeral(this.numShares).format("0.000a") + " of shares that you can issue.",
});
var yesBtn;
var input = createElement("input", {
type:"number",
placeholder: "Shares to issue",
onkeyup:(e)=>{
e.preventDefault();
if (e.keyCode === 13) {yesBtn.click();}
}
});
var br = createElement("br", {});
var yesBtn = createElement("a", {
yesBtn = createElement("a", {
class:"a-link-button",
innerText:"Go Public",
clickListener:()=>{
@ -3099,11 +3195,20 @@ Corporation.prototype.getScientificResearchMultiplier = function() {
var companyManagementDiv, companyManagementHeaderTabs, companyManagementPanel,
currentCityUi,
corporationUnlockUpgrades, corporationUpgrades,
//Industry Overview Panel
industryOverviewPanel, industryOverviewText,
//Industry Employee Panel
industryEmployeePanel, industryEmployeeText, industryEmployeeHireButton, industryEmployeeAutohireButton,
industryEmployeeManagementUI, industryEmployeeInfo, industryIndividualEmployeeInfo,
industryOfficeUpgradeSizeButton,
industryWarehousePanel,
//Industry Warehouse Panel
industryWarehousePanel, industrySmartSupplyCheckbox, industryWarehouseStorageText,
industryWarehouseStorageBreakdownText,
industryWarehouseUpgradeSizeButton, industryWarehouseStateText,
industryWarehouseMaterials, industryWarehouseProducts,
headerTabs, cityTabs;
Corporation.prototype.createUI = function() {
companyManagementDiv = createElement("div", {
@ -3163,28 +3268,33 @@ Corporation.prototype.updateUIHeaderTabs = function() {
var container = createElement("div", {
class:"popup-box-container",
id:"cmpy-mgmt-expand-industry-popup",
}),
content = createElement("div", {class:"popup-box-content"}),
txt = createElement("p", {
});
var content = createElement("div", {class:"popup-box-content"});
var txt = createElement("p", {
innerHTML: "Create a new division to expand into a new industry:",
}),
selector = createElement("select", {
});
var selector = createElement("select", {
class:"cmpy-mgmt-industry-select"
}),
industryDescription = createElement("p", {}),
nameInput = createElement("input", {
});
var industryDescription = createElement("p", {});
var yesBtn;
var nameInput = createElement("input", {
type:"text",
id:"cmpy-mgmt-expand-industry-name-input",
color:"white",
backgroundColor:"black",
display:"block",
maxLength: 30,
pattern:"[a-zA-Z0-9-_]"
}),
nameLabel = createElement("label", {
pattern:"[a-zA-Z0-9-_]",
onkeyup:(e)=>{
e.preventDefault();
if (e.keyCode === 13) {yesBtn.click();}
}
});
var nameLabel = createElement("label", {
for:"cmpy-mgmt-expand-industry-name-input",
innerText:"Division name: "
}),
});
yesBtn = createElement("span", {
class:"popup-box-button",
innerText:"Create Division",
@ -3216,8 +3326,8 @@ Corporation.prototype.updateUIHeaderTabs = function() {
}
return false;
}
}),
noBtn = createElement("span", {
});
var noBtn = createElement("span", {
class:"popup-box-button",
innerText:"Cancel",
clickListener: function() {
@ -4054,7 +4164,8 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
division.products[product.name] = product;
removeElementById(popupId);
}
this.updateUIContent();
//this.updateUIContent();
this.displayDivisionContent(division, city);
return false;
}
})
@ -4129,16 +4240,42 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
tooltip:"Upgrade the office's size so that it can hold more employees!",
clickListener:()=>{
var popupId = "cmpy-mgmt-upgrade-office-size-popup";
var upgradeCost = OfficeInitialCost * Math.pow(1.07, Math.round(office.size / OfficeInitialSize));
var initialPriceMult = Math.round(office.size / OfficeInitialSize);
var upgradeCost = OfficeInitialCost * Math.pow(1.07, initialPriceMult);
//Calculate cost to upgrade size by 15 employees
var mult = 0;
for (var i = 0; i < 5; ++i) {
mult += (Math.pow(1.07, initialPriceMult + i));
}
var upgradeCost15 = OfficeInitialCost * mult;
//Calculate max upgrade size and cost
var maxMult = (this.funds.dividedBy(OfficeInitialCost)).toNumber();
var maxNum = 1;
mult = Math.pow(1.07, initialPriceMult);
while(maxNum < 50) { //Hard cap of 50x (extra 150 employees)
if (mult >= maxMult) {break;}
var multIncrease = Math.pow(1.07, initialPriceMult + maxNum);
if (mult + multIncrease > maxMult) {
break;
} else {
mult += multIncrease;
}
++maxNum;
}
var upgradeCostMax = OfficeInitialCost * mult;
var text = createElement("p", {
innerHTML:"Increase the size of your office space to fit " + OfficeInitialSize +
" more employees. This will cost " + numeral(upgradeCost).format('$0.000a'),
innerText:"Increase the size of your office space to fit additional employees!"
});
var text2 = createElement("p", {innerText: "Upgrade size: "});
var confirmBtn = createElement("a", {
class:"a-link-button",
display:"inline-block",
margin:"8px",
innerText:"Upgrade Office Size",
class: this.funds.lt(upgradeCost) ? "a-link-button-inactive" : "a-link-button",
display:"inline-block", margin:"4px", innerText:"by 3",
tooltip:numeral(upgradeCost).format("$0.000a"),
clickListener:()=>{
if (this.funds.lt(upgradeCost)) {
dialogBoxCreate("You don't have enough company funds to purchase this upgrade!");
@ -4152,17 +4289,48 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
return false;
}
});
var confirmBtn15 = createElement("a", {
class: this.funds.lt(upgradeCost15) ? "a-link-button-inactive" : "a-link-button",
display:"inline-block", margin:"4px", innerText:"by 15",
tooltip:numeral(upgradeCost15).format("$0.000a"),
clickListener:()=>{
if (this.funds.lt(upgradeCost15)) {
dialogBoxCreate("You don't have enough company funds to purchase this upgrade!");
} else {
office.size += (OfficeInitialSize * 5);
this.funds = this.funds.minus(upgradeCost15);
dialogBoxCreate("Office space increased! It can now hold " + office.size + " employees");
this.updateUIContent();
}
removeElementById(popupId);
return false;
}
});
var confirmBtnMax = createElement("a", {
class:this.funds.lt(upgradeCostMax) ? "a-link-button-inactive" : "a-link-button",
display:"inline-block", margin:"4px", innerText:"by MAX (" + maxNum*OfficeInitialSize + ")",
tooltip:numeral(upgradeCostMax).format("$0.000a"),
clickListener:()=>{
if (this.funds.lt(upgradeCostMax)) {
dialogBoxCreate("You don't have enough company funds to purchase this upgrade!");
} else {
office.size += (OfficeInitialSize * maxNum);
this.funds = this.funds.minus(upgradeCostMax);
dialogBoxCreate("Office space increased! It can now hold " + office.size + " employees");
this.updateUIContent();
}
removeElementById(popupId);
return false;
}
});
var cancelBtn = createElement("a", {
class:"a-link-button",
innerText:"Cancel",
display:"inline-block",
margin:"8px",
class:"a-link-button", innerText:"Cancel", display:"inline-block", margin:"4px",
clickListener:()=>{
removeElementById(popupId);
return false;
}
})
createPopup(popupId, [text, confirmBtn, cancelBtn]);
createPopup(popupId, [text, text2, confirmBtn, confirmBtn15, confirmBtnMax, cancelBtn]);
return false;
}
});
@ -4182,6 +4350,7 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
var totalCostTxt = createElement("p", {
innerText:"Throwing this party will cost a total of $0"
});
var confirmBtn;
var input = createElement("input", {
type:"number", margin:"5px", placeholder:"$ / employee",
inputListener:()=>{
@ -4191,9 +4360,13 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
var totalCost = input.value * office.employees.length;
totalCostTxt.innerText = "Throwing this party will cost a total of " + numeral(totalCost).format('$0.000a');
}
},
onkeyup:(e)=>{
e.preventDefault();
if (e.keyCode === 13) {confirmBtn.click();}
}
});
var confirmBtn = createElement("a", {
confirmBtn = createElement("a", {
class:"a-link-button",
display:"inline-block",
innerText:"Throw Party",
@ -4383,7 +4556,7 @@ Corporation.prototype.displayDivisionContent = function(division, city) {
size:WarehouseInitialSize,
});
this.funds = this.funds.minus(WarehouseInitialCost);
this.updateDivisionContent(division);
this.displayDivisionContent(division, currentCityUi);
}
return false;
}
@ -4411,23 +4584,51 @@ Corporation.prototype.updateDivisionContent = function(division) {
advertisingInfo =
"<p class='tooltip'>Advertising Multiplier: x" + formatNumber(totalAdvertisingFac, 3) +
"<span class='tooltiptext' style='font-size:12px'>Total multiplier for this industry's sales due to its awareness and popularity<br>" +
"Awareness Bonus: x" + formatNumber(awarenessFac, 3) + "<br>" +
"Popularity Bonus: x" + formatNumber(popularityFac, 3) + "<br>" +
"Ratio Multiplier: x" + formatNumber(ratioFac, 3) + "</span></p><br>"
"Awareness Bonus: x" + formatNumber(Math.pow(awarenessFac, 0.85), 3) + "<br>" +
"Popularity Bonus: x" + formatNumber(Math.pow(popularityFac, 0.85), 3) + "<br>" +
"Ratio Multiplier: x" + formatNumber(Math.pow(ratioFac, 0.85), 3) + "</span></p><br>"
}
industryOverviewText.innerHTML =
"Industry: " + division.type + "<br><br>" +
removeChildrenFromElement(industryOverviewText);
industryOverviewText.appendChild(createElement("p", {
innerHTML:"Industry: " + division.type + " (Corp Funds: " + numeral(this.funds.toNumber()).format("$0.000a") + ")<br><br>" +
"Awareness: " + formatNumber(division.awareness, 3) + "<br>" +
"Popularity: " + formatNumber(division.popularity, 3) + "<br>" +
advertisingInfo + "<br>" +
"Revenue: " + numeral(division.lastCycleRevenue.toNumber()).format("$0.000a") + " / s<br>" +
"Expenses: " + numeral(division.lastCycleExpenses.toNumber()).format("$0.000a") + " /s<br>" +
"Profit: " + profitStr + " / s<br><br>" +
"<p class='tooltip'>Production Multiplier: " + formatNumber(division.prodMult, 2) +
"<span class='tooltiptext'>Production gain from owning production-boosting materials " +
"such as hardware, Robots, AI Cores, and Real Estate</span></p><br>" +
"Scientific Research: " + formatNumber(division.sciResearch.qty, 3);
"Profit: " + profitStr + " / s<br><br>"
}));
industryOverviewText.appendChild(createElement("p", {
marginTop:"2px",
innerText:"Production Multiplier: " + formatNumber(division.prodMult, 2),
tooltip:"Production gain from owning production-boosting materials " +
"such as hardware, Robots, AI Cores, and Real Estate"
}));
industryOverviewText.appendChild(createElement("div", {
innerText:"?", class:"help-tip",
clickListener:()=>{
dialogBoxCreate("Owning Hardware, Robots, AI Cores, and Real Estate " +
"can boost your Industry's production. The effect these " +
"materials have on your production varies between Industries. " +
"For example, Real Estate may be very effective for some Industries, " +
"but ineffective for others.<br><br>" +
"This division's production multiplier is calculated by summing " +
"the individual production multiplier of each of its office locations. " +
"This production multiplier is applied to each office. Therefore, it is " +
"beneficial to expand into new cities as this can greatly increase the " +
"production multiplier of your entire Division."
)
}
}));
industryOverviewText.appendChild(createElement("br"));
industryOverviewText.appendChild(createElement("p", {
display:"inline-block",
innerText:"Scientific Research: " + formatNumber(division.sciResearch.qty, 3),
tooltip:"Scientific Research increases the quality of the materials and " +
"products that you produce."
}));
//Office and Employee List
var office = division.offices[currentCityUi];
@ -4491,7 +4692,7 @@ Corporation.prototype.updateDivisionContent = function(division) {
//Warehouse
var warehouse = division.warehouses[currentCityUi];
if (warehouse instanceof Warehouse) {
warehouse.createUI({industry:division, company:this});
warehouse.updateUI({industry:division, company:this});
}
}
@ -4546,6 +4747,12 @@ Corporation.prototype.clearUI = function() {
industryOfficeUpgradeSizeButton = null;
industryWarehousePanel = null;
industrySmartSupplyCheckbox = null;
industryWarehouseStorageText = null;
industryWarehouseUpgradeSizeButton = null;
industryWarehouseStateText = null;
industryWarehouseMaterials = null;
industryWarehouseProducts = null;
companyManagementHeaderTabs = null;
headerTabs = null;

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.35.0",
Version: "0.35.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
@ -1138,39 +1138,28 @@ let CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>",
LatestUpdate:
"v0.35.0<br>" +
"-Minor rebalancing of BitNodes due to the fact that Corporations provide a (relatively) new method of " +
"progressing<br>" +
"-Corporation Management Changes:<br>" +
"---Once your Corporation gets big/powerful enough, you can now bribe Factions for reputation using company funds an/or stock shares<br>" +
"---You can now only create one Division for every Industry type<br>" +
"---Added several new UI/UX elements<br>" +
"---Wilson Analytics multiplier was significantly reduced to 1% per level (additive).<br>" +
"---Reduced the effect of Advert Inc upgrade. Advert Inc. upgrade price increases faster<br>" +
"---Materials can now be marked up at higher prices<br>" +
"-Added Javascript's built-in Number object to Netscript<br>" +
"-Added getCharacterInformation(), getCompanyFavor(), and getFactionFavor() Netscript Singularity functions<br>" +
"-Rebalanced Singularity Function RAM Costs. They now cost x8 as much when outside of BN-4 (rather than x10). Also, " +
"many of the functions now use significantly less RAM<br>" +
"-Refactored Netscript Ports. You can now get a handle for a Netscript port using the " +
"getPortHandle() Netscript function. This allows you to access a port's underlying queue (which is just an array) and also " +
"makes several new functions available such as tryWrite(), full(), and empty().<br>" +
"-Number of Netscript Ports increased from 10 to 20<br>" +
"-Netscript assignments should now return proper values. i.e. i = 5 should return 5.<br>" +
"-Added throw statements to Netscript. It's not super useful since 'catch' isn't implemented, but it can be used " +
"to generate custom runtime error messages.<br>" +
"-Added import declaration to Netscript. With this, you are able to import functions (and only functions) from " +
"other files. Using export declarations is not necessary<br>" +
"-Most Netscript Runtime errors (the ones that cause your script to crash) should now include the line number where the error occured<br>" +
"-When working for a company, your current company reputation is now displayed<br>" +
"-Whenever you get a Faction Invite it will be immediately appended to your 'invited factions' list. " +
"Therefore the checkFactionInvitations() Singularity Function should now be properly useable since you no longer " +
"need to decline a Faction Invitation before it shows up in the result.<br>" +
"-Bug Fix: When purchasing servers, whitespace should now automatically be removed from the hostname<br>" +
"-Bug Fix: Can no longer have whitespace in the filename of text files created using write()<br>" +
"-Bug Fix: In Netscript, you can no longer assign a Hacknet Node handle (hacknetnodes[i]) to another value <br>" +
"-Bug Fix: If you are in the Factions tab when you accept an invitation from a Faction, the page will now properly 'refresh'<br>" +
"-Bug Fix: Scripts that run recursive functions should now be killed properly<br>"
"v0.35.1<br>" +
"* You can now easily download all of your scripts/text files as zip folders. Use the 'help download' Terminal command for details<br>" +
"* Scripts are now downloaded with the .script.js extension at the end of their filename<br>" +
"* Corporation Management Changes:<br>" +
"*** Implemented Smart Supply unlock<br>" +
"*** Changed the way a division's Production Multiplier is calculated. It is now the sum of the individual Production Multiplier " +
"for every city. Therefore, it is now beneficial to open offices in different cities<br." +
"*** The breakdown of what is taking up Warehouse space is now listed as a tooltip<br>" +
"*** Several small UI/UX improvements<br>" +
"*** Numerous balance changes. The significant ones are listed below.<br>" +
"*** Product descriptions will now display their estimated market price<br>" +
"*** The sale price of Products can no longer be marked up as high as before<br>" +
"*** Scientific Research now affects the rating of Products<br>" +
"*** In general, the maximum amount of product you are able to sell is reduced<br>" +
"*** Sale bonus from advertising (popularity/awareness) now has diminishing returns rather than scaling linearly<br>" +
"* Experience gained during Infiltration now scales linearly based on the clearance level you reach. Compared to before, " +
"the experience gained will be much less at lower clearance levels, but much more at higher clearance levels<br>" +
"* The editor can now be used to edit both scripts and text files<br>" +
"* New Terminal config file that can be edited using the command 'nano .fconf'. Right now there is only one option, but there " +
"will be more in the future.<br>" +
"* You can now enable Bash-style Terminal hotkeys using the .fconf file referenced above<br>" +
"* Bug Fix: Fixed an issue with the UI elements of Gang Management persisting across different instances of BitNode-2"
}
export {CONSTANTS};

117
src/Fconf.js Normal file

@ -0,0 +1,117 @@
import {parse, Node} from "../utils/acorn.js";
var FconfSettings = {
ENABLE_BASH_HOTKEYS: false
}
var FconfComments = {
ENABLE_BASH_HOTKEYS: "Improved Bash emulation mode. Setting this to 1 enables several\n" +
"new Terminal shortcuts and features that more closely resemble\n" +
"a real Bash-style shell. Note that when this mode is enabled,\n" +
"the default browser shortcuts are overriden by the new Bash\n" +
"shortcuts.\n\n" +
"To see a full list of the Terminal shortcuts that this enables, see:\n",
}
//Parse Fconf settings from the config text
//Throws an exception if parsing fails
function parseFconfSettings(config) {
var ast = parse(config, {sourceType:"module"});
var queue = [];
queue.push(ast);
while (queue.length != 0) {
var exp = queue.shift();
switch (exp.type) {
case "BlockStatement":
case "Program":
for (var i = 0; i < exp.body.length; ++i) {
if (exp.body[i] instanceof Node) {
queue.push(exp.body[i]);
}
}
break;
case "AssignmentExpression":
var setting, value;
if (exp.left != null && exp.left.name != null) {
setting = exp.left.name;
} else {
break;
}
if (exp.right != null && exp.right.raw != null) {
value = exp.right.raw;
} else {
break;
}
parseFconfSetting(setting, value);
break;
default:
break;
}
for (var prop in exp) {
if (exp.hasOwnProperty(prop)) {
if (exp[prop] instanceof Node) {
queue.push(exp[prop]);
}
}
}
}
}
function parseFconfSetting(setting, value) {
setting = String(setting);
value = String(value);
if (setting == null || value == null || FconfSettings[setting] == null) {
console.log("WARNING: Invalid .fconf setting: " + setting);
return;
}
//Needed to convert entered value to boolean/strings accordingly
switch(setting) {
case "ENABLE_BASH_HOTKEYS":
var value = value.toLowerCase();
if (value === "1" || value === "true" || value === "y") {
value = true;
} else {
value = false;
}
FconfSettings[setting] = value;
break;
default:
break;
}
return;
}
//Create the .fconf file text from the settings
function createFconf() {
var res = "";
for (var setting in FconfSettings) {
if (FconfSettings.hasOwnProperty(setting)) {
//Setting comments (description)
var comment = FconfComments[setting];
if (comment == null) {continue;}
var comment = comment.split("\n");
for (var i = 0; i < comment.length; ++i) {
res += ("//" + comment[i] + "\n");
}
var value = 0;
if (FconfSettings[setting] === true) {
value = "1";
} else if (FconfSettings[setting] === false) {
value = "0";
} else {
value = String(FconfSettings[setting]);
}
res += (setting + "=" + value + "\n");
}
}
return res;
}
function loadFconf(saveString) {
FconfSettings = JSON.parse(saveString);
}
export {FconfSettings, createFconf, parseFconfSettings, loadFconf}

@ -1,7 +1,6 @@
import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
import {Faction, Factions} from "./Faction.js";
import {Locations} from "./Location.js";
import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {Reviver, Generic_toJSON,
@ -53,8 +52,6 @@ $(document).mousedown(function(event) {
let GangNames = ["Slum Snakes", "Tetrads", "The Syndicate", "The Dark Army", "Speakers for the Dead",
"NiteSec", "The Black Hand"];
let GangLocations = [Locations.Aevum, Locations.Chongqing, Locations.Sector12, Locations.NewTokyo,
Locations.Ishima, Locations.Volhaven];
let AllGangs = {
"Slum Snakes" : {
power: 1,
@ -1406,5 +1403,35 @@ function setGangMemberTaskDescription(memberObj, taskName) {
}
}
function deleteGangDisplayContent() {
if (gangContainer != null) {removeElementById(gangContainer.id);}
gangContentCreated = false;
gangContainer = null;
managementButton = null;
territoryButton = null;
//Subpages
gangManagementSubpage = null;
gangTerritorySubpage = null;
//Gang Management Elements
gangDesc = null;
gangInfo = null;
gangRecruitMemberButton = null;
gangRecruitRequirementText = null;
gangExpandAllButton = null;
gangCollapseAllButton = null;
gangMemberFilter = null;
gangManageEquipmentButton = null;
gangMemberList = null;
//Gang Equipment Upgrade Elements
gangMemberUpgradeBox = null;
gangMemberUpgradeBoxContent = null;
gangMemberUpgradeBoxFilter = null;
gangMemberUpgradeBoxElements = null;
}
export {Gang, displayGangContent, updateGangContent, loadAllGangs, AllGangs,
resetGangs};
resetGangs, deleteGangDisplayContent};

@ -9,7 +9,7 @@ let TerminalHelpText =
"clear Clear all text on the terminal <br>" +
"cls See 'clear' command <br>" +
"connect [ip/hostname] Connects to a remote server<br>" +
"download [script/text file] Downloads a script or text file to your computer<br>" +
"download [script/text file] Downloads scripts or text files to your computer<br>" +
"free Check the machine's memory (RAM) usage<br>" +
"hack Hack the current machine<br>" +
"help [command] Display this help text, or the help text for a command<br>" +
@ -21,7 +21,7 @@ let TerminalHelpText =
"ls [| grep pattern] Displays all files on the machine<br>" +
"lscpu Displays the number of CPU cores on the machine<br>" +
"mem [script] [-t] [n] Displays the amount of RAM required to run the script<br>" +
"nano [script] Script editor - Open up and edit a script<br>" +
"nano [file] Text editor - Open up and edit a script or text file<br>" +
"ps Display all scripts that are currently running<br>" +
"rm [file] Delete a file from the server<br>" +
"run [name] [-t] [n] [args...] Execute a program or script<br>" +
@ -87,7 +87,11 @@ let HelpTexts = {
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To " +
"see which servers can be connected to, use the 'scan' command.",
download: "download [script/text file]<br>" +
"Downloads a script or text file to your computer (like your real life computer).",
"Downloads a script or text file to your computer (like your real life computer).<br>" +
"You can also download all of your scripts/text files as a zip file using the following Terminal commands:<br><br>" +
"Download all scripts and text files: download *<br>" +
"Download all scripts: download *.script<br>" +
"Download all text files: download *.txt<br>",
free: "free<br>" +
"Display's the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as " +
"how much of it is being used.",
@ -137,8 +141,9 @@ let HelpTexts = {
"mem foo.script -t 50<br>" +
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example " +
"above will print the amount of RAM needed to run 'foo.script' with 50 threads.",
nano: "nano [script name]<br>" +
"Opens up the specified script in the Script Editor. If the script does not already exist, then a new, empty script " +
nano: "nano [file name]<br>" +
"Opens up the specified file in the Text Editor. Only scripts (.script) or text files (.txt) can be " +
"edited using the Text Editor. If the file does not already exist, then a new, empty one " +
"will be created",
ps: "ps<br>" +
"Prints all scripts that are running on the current server",

@ -453,18 +453,20 @@ function updateInfiltrationLevelText(inst) {
totalMoneyValue += inst.secretsStolen[i] * CONSTANTS.InfiltrationMoneyValue *
BitNodeMultipliers.InfiltrationMoney;
}
var expMultiplier = 2 * inst.clearanceLevel / inst.maxClearanceLevel;
document.getElementById("infiltration-level-text").innerHTML =
"Facility name: " + inst.companyName + "<br>" +
"Clearance Level: " + inst.clearanceLevel + "<br>" +
"Security Level: " + formatNumber(inst.securityLevel, 3) + "<br><br>" +
"Total reputation value of secrets stolen: " + formatNumber(totalValue, 3) + "<br>" +
"Total monetary value of secrets stolen: $" + formatNumber(totalMoneyValue, 2) + "<br><br>" +
"Hack exp gained: " + formatNumber(inst.hackingExpGained, 3) + "<br>" +
"Str exp gained: " + formatNumber(inst.strExpGained, 3) + "<br>" +
"Def exp gained: " + formatNumber(inst.defExpGained, 3) + "<br>" +
"Dex exp gained: " + formatNumber(inst.dexExpGained, 3) + "<br>" +
"Agi exp gained: " + formatNumber(inst.agiExpGained, 3) + "<br>" +
"Cha exp gained: " + formatNumber(inst.chaExpGained, 3);
"Hack exp gained: " + formatNumber(inst.hackingExpGained * expMultiplier, 3) + "<br>" +
"Str exp gained: " + formatNumber(inst.strExpGained * expMultiplier, 3) + "<br>" +
"Def exp gained: " + formatNumber(inst.defExpGained * expMultiplier, 3) + "<br>" +
"Dex exp gained: " + formatNumber(inst.dexExpGained * expMultiplier, 3) + "<br>" +
"Agi exp gained: " + formatNumber(inst.agiExpGained * expMultiplier, 3) + "<br>" +
"Cha exp gained: " + formatNumber(inst.chaExpGained * expMultiplier, 3);
}
function updateInfiltrationButtons(inst, scenario) {

@ -7,12 +7,14 @@ import {Programs} from "./CreateProgram.js";
import {Engine} from "./engine.js";
import {Factions, Faction, initFactions,
joinFaction} from "./Faction.js";
import {deleteGangDisplayContent} from "./Gang.js";
import {Locations} from "./Location.js";
import {initMessages, Messages, Message} from "./Message.js";
import {initSingularitySFFlags, hasWallStreetSF}from "./NetscriptFunctions.js";
import {WorkerScript, workerScripts,
prestigeWorkerScripts} from "./NetscriptWorker.js";
import {Player} from "./Player.js";
import {AllServers, AddToAllServers,
initForeignServers, Server,
prestigeAllServers,
@ -239,13 +241,16 @@ function prestigeSourceFile() {
}
Player.gang = null;
deleteGangDisplayContent();
Player.corporation = null;
//BitNode 3: Corporatocracy
if (Player.bitNodeN === 3) {Player.money = new Decimal(150e9);}
if (Player.bitNodeN === 3) {
Player.money = new Decimal(150e9);
homeComp.messages.push("corporation-management-handbook.lit");
dialogBoxCreate("You received a copy of the Corporation Management Handbook on your home computer. " +
"Read it if you need help getting started with Corporations!");
}
//Gain int exp
Player.gainIntelligenceExp(5);

@ -6,6 +6,7 @@ import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
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 {loadMessages, initMessages, Messages} from "./Message.js";
@ -40,6 +41,7 @@ function BitburnerSaveObject() {
this.MessagesSave = "";
this.StockMarketSave = "";
this.SettingsSave = "";
this.FconfSettingsSave = "";
this.VersionSave = "";
this.AllGangsSave = "";
}
@ -68,6 +70,7 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
this.MessagesSave = JSON.stringify(Messages);
this.StockMarketSave = JSON.stringify(StockMarket);
this.SettingsSave = JSON.stringify(Settings);
this.FconfSettingsSave = JSON.stringify(FconfSettings);
this.VersionSave = JSON.stringify(CONSTANTS.Version);
if (Player.bitNodeN == 2 && Player.inGang()) {
this.AllGangsSave = JSON.stringify(AllGangs);
@ -170,6 +173,13 @@ function loadGame(saveString) {
} else {
initSettings();
}
if (saveObj.hasOwnProperty("FconfSettingsSave")) {
try {
loadFconf(saveObj.FconfSettingsSave);
} catch(e) {
console.log("ERROR: Failed to parse .fconf Settings.");
}
}
if (saveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(saveObj.VersionSave, Reviver);
@ -378,6 +388,13 @@ function loadImportedGame(saveObj, saveString) {
} else {
initSettings();
}
if (saveObj.hasOwnProperty("FconfSettingsSave")) {
try {
loadFconf(saveObj.FconfSettingsSave);
} catch(e) {
console.log("ERROR: Failed to load .fconf settings when importing");
}
}
if (saveObj.hasOwnProperty("VersionSave")) {
try {
var ver = JSON.parse(saveObj.VersionSave, Reviver);

@ -15,6 +15,7 @@ require("brace/ext/language_tools");
import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
import {parseFconfSettings} from "./Fconf.js";
import {iTutorialSteps, iTutorialNextStep,
iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js";
import {evaluateImport} from "./NetscriptEvaluator.js";
@ -25,6 +26,7 @@ import {Player} from "./Player.js";
import {AllServers, processSingleServerGrowth} from "./Server.js";
import {Settings} from "./Settings.js";
import {post} from "./Terminal.js";
import {TextFile} from "./TextFile.js";
import {parse, Node} from "../utils/acorn.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
@ -206,7 +208,8 @@ function scriptEditorInit() {
//Updates RAM usage in script
function updateScriptEditorContent() {
if (scriptEditorRamCheck == null || !scriptEditorRamCheck.checked) {
var filename = document.getElementById("script-editor-filename").value;
if (scriptEditorRamCheck == null || !scriptEditorRamCheck.checked || !filename.endsWith(".script")) {
scriptEditorRamText.innerText = "N/A";
return;
}
@ -234,13 +237,13 @@ $(document).keydown(function(e) {
function saveAndCloseScriptEditor() {
var filename = document.getElementById("script-editor-filename").value;
var editor = ace.edit('javascript-editor');
var code = editor.getValue();
if (iTutorialIsRunning && currITutorialStep == iTutorialSteps.TerminalTypeScript) {
if (filename != "foodnstuff") {
if (filename != "foodnstuff.script") {
dialogBoxCreate("Leave the script name as 'foodnstuff'!");
return;
}
var editor = ace.edit('javascript-editor');
var code = editor.getValue();
code = code.replace(/\s/g, "");
if (code.indexOf("while(true){hack('foodnstuff');}") == -1) {
dialogBoxCreate("Please copy and paste the code from the tutorial!");
@ -259,12 +262,19 @@ function saveAndCloseScriptEditor() {
return;
}
filename += ".script";
var s = Player.getCurrentServer();
if (filename === ".fconf") {
try {
parseFconfSettings(code);
} catch(e) {
dialogBoxCreate("Invalid .fconf file");
return;
}
} else if (filename.endsWith(".script")) {
//If the current script already exists on the server, overwrite it
for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) {
if (filename == Player.getCurrentServer().scripts[i].filename) {
Player.getCurrentServer().scripts[i].saveScript();
for (var i = 0; i < s.scripts.length; i++) {
if (filename == s.scripts[i].filename) {
s.scripts[i].saveScript();
Engine.loadTerminalContent();
return;
}
@ -273,14 +283,29 @@ function saveAndCloseScriptEditor() {
//If the current script does NOT exist, create a new one
var script = new Script();
script.saveScript();
Player.getCurrentServer().scripts.push(script);
s.scripts.push(script);
} else if (filename.endsWith(".txt")) {
for (var i = 0; i < s.textFiles.length; ++i) {
if (s.textFiles[i].fn === filename) {
s.textFiles[i].write(code);
Engine.loadTerminalContent();
return;
}
}
var textFile = new TextFile(filename, code);
s.textFiles.push(textFile);
} else {
dialogBoxCreate("Invalid filename. Must be either a script (.script) or " +
" or text file (.txt)")
return;
}
Engine.loadTerminalContent();
}
//Checks that the string contains only valid characters for a filename, which are alphanumeric,
// underscores and hyphens
// underscores, hyphens, and dots
function checkValidFilename(filename) {
var regex = /^[a-zA-Z0-9_-]+$/;
var regex = /^[.a-zA-Z0-9_-]+$/;
if (filename.match(regex)) {
return true;
@ -303,7 +328,7 @@ Script.prototype.saveScript = function() {
var code = editor.getValue();
this.code = code.replace(/^\s+|\s+$/g, '');
var filename = document.getElementById("script-editor-filename").value + ".script";
var filename = document.getElementById("script-editor-filename").value;
this.filename = filename;
//Server
@ -417,7 +442,7 @@ function calculateRamUsage(codeCopy) {
}
Script.prototype.download = function() {
var filename = this.filename;
var filename = this.filename + ".js";
var file = new Blob([this.code], {type: 'text/plain'});
if (window.navigator.msSaveOrOpenBlob) {// IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
@ -425,7 +450,7 @@ Script.prototype.download = function() {
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = this.filename;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
@ -675,18 +700,6 @@ function AllServersMap(arr=false, filterOwned=false) {
}
}
AllServersMap.prototype.printConsole = function() {
for (var ip in this) {
if (this.hasOwnProperty(ip)) {
var serv = AllServers[ip];
if (serv == null) {
console.log("Warning null server encountered with ip: " + ip);
continue;
}
}
}
}
AllServersMap.prototype.toJSON = function() {
return Generic_toJSON("AllServersMap", this);
}

@ -7,6 +7,8 @@ import {Programs} from "./CreateProgram.js";
import {executeDarkwebTerminalCommand,
checkIfConnectedToDarkweb} from "./DarkWeb.js";
import {Engine} from "./engine.js";
import {FconfSettings, parseFconfSettings,
createFconf} from "./Fconf.js";
import {TerminalHelpText, HelpTexts} from "./HelpText.js";
import {iTutorialNextStep, iTutorialSteps,
iTutorialIsRunning,
@ -37,6 +39,9 @@ import {yesNoBoxCreate,
yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxClose} from "../utils/YesNoBox.js";
import * as JSZip from 'jszip';
import * as FileSaver from 'file-saver';
/* Write text to terminal */
//If replace is true then spaces are replaced with "&nbsp;"
function post(input) {
@ -65,6 +70,30 @@ function postNetburnerText() {
post("Bitburner v" + CONSTANTS.Version);
}
//Key Codes
let KEY = {
TAB: 9,
ENTER: 13,
CTRL: 17,
UPARROW: 38,
DOWNARROW: 40,
A: 65,
B: 66,
C: 67,
D: 68,
E: 69,
F: 70,
H: 72,
K: 75,
L: 76,
M: 77,
N: 78,
P: 80,
U: 85,
W: 87,
}
//Defines key commands in terminal
$(document).keydown(function(event) {
//Terminal
@ -72,8 +101,7 @@ $(document).keydown(function(event) {
var terminalInput = document.getElementById("terminal-input-text-box");
if (terminalInput != null && !event.ctrlKey && !event.shiftKey) {terminalInput.focus();}
//Enter
if (event.keyCode == 13) {
if (event.keyCode === KEY.ENTER) {
event.preventDefault(); //Prevent newline from being entered in Script Editor
var command = $('input[class=terminal-input]').val();
if (command.length > 0) {
@ -84,15 +112,30 @@ $(document).keydown(function(event) {
}
}
//Ctrl + c when an "Action" is in progress
if (event.keyCode == 67 && event.ctrlKey && Engine._actionInProgress) {
if (event.keyCode === KEY.C && event.ctrlKey) {
if (Engine._actionInProgress) {
//Cancel action
post("Cancelling...");
Engine._actionInProgress = false;
Terminal.finishAction(true);
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
//Dont prevent default so it still copies
Terminal.resetTerminalInput(); //Clear Terminal
}
}
//Up key to cycle through past commands
if (event.keyCode == 38) {
if (event.keyCode === KEY.L && event.ctrlKey) {
event.preventDefault();
Terminal.executeCommand("clear"); //Clear screen
}
//Ctrl p same as up arrow
//Ctrl n same as down arrow
if (event.keyCode === KEY.UPARROW ||
(FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.P && event.ctrlKey)) {
if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();}
//Cycle through past commands
if (terminalInput == null) {return;}
var i = Terminal.commandHistoryIndex;
var len = Terminal.commandHistory.length;
@ -110,8 +153,10 @@ $(document).keydown(function(event) {
setTimeout(function(){terminalInput.selectionStart = terminalInput.selectionEnd = 10000; }, 0);
}
//Down key
if (event.keyCode == 40) {
if (event.keyCode === KEY.DOWNARROW ||
(FconfSettings.ENABLE_BASH_HOTKEYS && event.keyCode === KEY.M && event.ctrlKey)) {
if (FconfSettings.ENABLE_BASH_HOTKEYS) {event.preventDefault();}
//Cycle through past commands
if (terminalInput == null) {return;}
var i = Terminal.commandHistoryIndex;
var len = Terminal.commandHistory.length;
@ -132,8 +177,8 @@ $(document).keydown(function(event) {
}
}
//Tab (autocomplete)
if (event.keyCode == 9) {
if (event.keyCode === KEY.TAB) {
//Autocomplete
if (terminalInput == null) {return;}
var input = terminalInput.value;
if (input == "") {return;}
@ -163,6 +208,52 @@ $(document).keydown(function(event) {
tabCompletion(command, arg, allPos);
}
//Extra Bash Emulation Hotkeys, must be enabled through .fconf
if (FconfSettings.ENABLE_BASH_HOTKEYS) {
if (event.keyCode === KEY.A && event.ctrlKey) {
event.preventDefault();
Terminal.moveTextCursor("home");
}
if (event.keyCode === KEY.E && event.ctrlKey) {
event.preventDefault();
Terminal.moveTextCursor("end");
}
if (event.keyCode === KEY.B && event.ctrlKey) {
event.preventDefault();
Terminal.moveTextCursor("prevchar");
}
if (event.keyCode === KEY.B && event.altKey) {
event.preventDefault();
Terminal.moveTextCursor("prevword");
}
if (event.keyCode === KEY.F && event.ctrlKey) {
event.preventDefault();
Terminal.moveTextCursor("nextchar");
}
if (event.keyCode === KEY.F && event.altKey) {
event.preventDefault();
Terminal.moveTextCursor("nextword");
}
if ((event.keyCode === KEY.H || event.keyCode === KEY.D) && event.ctrlKey) {
Terminal.modifyInput("backspace");
event.preventDefault();
}
//TODO AFTER THIS:
//alt + d deletes word after cursor
//^w deletes word before cursor
//^k clears line after cursor
//^u clears line before cursor
}
}
});
@ -344,8 +435,7 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
return allPos;
}
if (input.startsWith("kill ") || input.startsWith("nano ") ||
input.startsWith("tail ") ||
if (input.startsWith("kill ") || input.startsWith("tail ") ||
input.startsWith("mem ") || input.startsWith("check ")) {
//All Scripts
for (var i = 0; i < currServ.scripts.length; ++i) {
@ -354,6 +444,18 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
return allPos;
}
if (input.startsWith("nano ")) {
//Scripts and text files and .fconf
for (var i = 0; i < currServ.scripts.length; ++i) {
allPos.push(currServ.scripts[i].filename);
}
for (var i = 0; i < currServ.textFiles.length; ++i) {
allPos.push(currServ.textFiles[i].fn);
}
allPos.push(".fconf");
return allPos;
}
if (input.startsWith("rm ")) {
for (var i = 0; i < currServ.scripts.length; ++i) {
allPos.push(currServ.scripts[i].filename);
@ -420,23 +522,113 @@ let Terminal = {
commandHistory: [],
commandHistoryIndex: 0,
finishAction: function(cancelled = false) {
if (Terminal.hackFlag) {
Terminal.finishHack(cancelled);
} else if (Terminal.analyzeFlag) {
Terminal.finishAnalyze(cancelled);
}
},
resetTerminalInput: function() {
document.getElementById("terminal-input-td").innerHTML =
"<div id='terminal-input-header'>[" + Player.getCurrentServer().hostname + " ~]" + "$ </div>" +
'<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
var hdr = document.getElementById("terminal-input-header");
hdr.style.display = "inline";
//var lineWidth = document.getElementById("terminal-input-td").offsetWidth;
//var width = lineWidth - hdr.offsetWidth - 10;
//document.getElementById("terminal-input-text-box").style.width = width + "px";
},
modifyInput: function(mod) {
try {
var terminalInput = document.getElementById("terminal-input-text-box");
if (terminalInput == null) {return;}
terminalInput.focus();
var inputLength = terminalInput.value.length;
var start = terminalInput.selectionStart;
var end = terminalInput.selectionEnd;
var inputText = terminalInput.value;
switch(mod.toLowerCase()) {
case "backspace":
if (start > 0 && start <= inputLength+1) {
terminalInput.value = inputText.substr(0, start-1) + inputText.substr(start);
}
break;
case "deletewordbefore": //Delete rest of word before the cursor
for (var delStart = start-1; delStart > 0; --delStart) {
if (inputText.charAt(delStart) === " ") {
terminalInput.value = inputText.substr(0, delStart) + inputText.substr(start);
return;
}
}
break;
case "deletewordafter": //Delete rest of word after the cursor
for (var delStart = start+1; delStart <= text.length+1; ++delStart) {
if (inputText.charAt(delStart) === " ") {
terminalInput.value = inputText.substr(0, start) + inputText.substr(delStart);
return;
}
}
break;
case "clearafter": //Deletes everything after cursor
break;
case "clearbefore:": //Deleetes everything before cursor
break;
}
} catch(e) {
console.log("Exception in Terminal.modifyInput: " + e);
}
},
moveTextCursor: function(loc) {
try {
var terminalInput = document.getElementById("terminal-input-text-box");
if (terminalInput == null) {return;}
terminalInput.focus();
var inputLength = terminalInput.value.length;
var start = terminalInput.selectionStart;
var end = terminalInput.selectionEnd;
switch(loc.toLowerCase()) {
case "home":
terminalInput.setSelectionRange(0,0);
break;
case "end":
terminalInput.setSelectionRange(inputLength, inputLength);
break;
case "prevchar":
if (start > 0) {terminalInput.setSelectionRange(start-1, start-1);}
break;
case "prevword":
for (var i = start-2; i >= 0; --i) {
if (terminalInput.value.charAt(i) === " ") {
terminalInput.setSelectionRange(i+1, i+1);
return;
}
}
terminalInput.setSelectionRange(0, 0);
break;
case "nextchar":
terminalInput.setSelectionRange(start+1, start+1);
break;
case "nextword":
for (var i = start+1; i <= inputLength; ++i) {
if (terminalInput.value.charAt(i) === " ") {
terminalInput.setSelectionRange(i, i);
return;
}
}
terminalInput.setSelectionRange(inputLength, inputLength);
break;
default:
console.log("WARNING: Invalid loc argument in Terminal.moveTextCursor()");
break;
}
} catch(e) {
console.log("Exception in Terminal.moveTextCursor: " + e);
}
},
finishAction: function(cancelled = false) {
if (Terminal.hackFlag) {
Terminal.finishHack(cancelled);
} else if (Terminal.analyzeFlag) {
Terminal.finishAnalyze(cancelled);
}
},
//Complete the hack/analyze command
@ -484,7 +676,6 @@ let Terminal = {
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
$("#hack-progress").attr('id', "old-hack-progress");
Terminal.resetTerminalInput();
//document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
$('input[class=terminal-input]').prop('disabled', false);
Terminal.hackFlag = false;
@ -540,7 +731,6 @@ let Terminal = {
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
$("#hack-progress").attr('id', "old-hack-progress");
Terminal.resetTerminalInput();
//document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
$('input[class=terminal-input]').prop('disabled', false);
},
@ -835,13 +1025,45 @@ let Terminal = {
return;
}
var fn = commandArray[1];
if (fn.endsWith(".script")) {
if (fn === "*" || fn === "*.script" || fn === "*.txt") {
//Download all scripts as a zip
var zip = new JSZip();
if (fn === "*" || fn === "*.script") {
for (var i = 0; i < s.scripts.length; ++i) {
var file = new Blob([s.scripts[i].code], {type:"text/plain"});
zip.file(s.scripts[i].filename + ".js", file);
}
}
if (fn === "*" || fn === "*.txt") {
for (var i = 0; i < s.textFiles.length; ++i) {
var file = new Blob([s.textFiles[i].text], {type:"text/plain"});
zip.file(s.textFiles[i].fn, file);
}
}
var filename;
switch (fn) {
case "*.script":
filename = "bitburnerScripts.zip"; break;
case "*.txt":
filename = "bitburnerTexts.zip"; break;
default:
filename = "bitburnerFiles.zip"; break;
}
zip.generateAsync({type:"blob"}).then(function(content) {
FileSaver.saveAs(content, filename);
});
return;
} else if (fn.endsWith(".script")) {
//Download a single script
for (var i = 0; i < s.scripts.length; ++i) {
if (s.scripts[i].filename === fn) {
return s.scripts[i].download();
}
}
} else if (fn.endsWith(".txt")) {
//Download a single text file
var txtFile = getTextFile(fn, s);
if (txtFile !== null) {
return txtFile.download();
@ -984,23 +1206,28 @@ let Terminal = {
}
var filename = commandArray[1];
//Can only edit script files
if (filename.endsWith(".script") == false) {
post("Error: Only .script files are editable with nano (filename must end with .script)"); return;
}
//Script name is the filename without the .script at the end
var scriptname = filename.substr(0, filename.indexOf(".script"));
//Check if the script already exists
for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) {
if (filename == Player.getCurrentServer().scripts[i].filename) {
Engine.loadScriptEditorContent(scriptname, Player.getCurrentServer().scripts[i].code);
if (filename === ".fconf") {
var text = createFconf();
Engine.loadScriptEditorContent(filename, text);
return;
} else if (filename.endsWith(".script")) {
for (var i = 0; i < s.scripts.length; i++) {
if (filename == s.scripts[i].filename) {
Engine.loadScriptEditorContent(filename, s.scripts[i].code);
return;
}
}
Engine.loadScriptEditorContent(scriptname, "");
} else if (filename.endsWith(".txt")) {
for (var i = 0; i < s.textFiles.length; ++i) {
if (filename === s.textFiles[i].fn) {
Engine.loadScriptEditorContent(filename, s.textFiles[i].text);
return;
}
}
} else {
post("Error: Invalid file. Only scripts (.script), text files (.txt), or .fconf can be edited with nano"); return;
}
Engine.loadScriptEditorContent(filename);
break;
case "ps":
if (commandArray.length != 1) {

@ -23,6 +23,7 @@ import {Programs, displayCreateProgramContent,
import {displayFactionContent, joinFaction,
processPassiveFactionRepGain, Factions,
inviteToFaction, initFactions} from "./Faction.js";
import {FconfSettings} from "./Fconf.js";
import {Locations, displayLocationContent,
initLocationButtons} from "./Location.js";
import {displayGangContent, updateGangContent,
@ -55,8 +56,6 @@ import {StockMarket, StockSymbols,
displayStockMarketContent} from "./StockMarket.js";
import {Terminal, postNetburnerText, post} from "./Terminal.js";
/* Shortcuts to navigate through the game
* Alt-t - Terminal
* Alt-c - Character
@ -102,6 +101,10 @@ $(document).keydown(function(e) {
e.preventDefault();
Engine.loadCreateProgramContent();
} else if (e.keyCode == 70 && e.altKey) {
//Overriden by Fconf
if (Engine.currentPage === Engine.Page.Terminal && FconfSettings.ENABLE_BASH_HOTKEYS) {
return;
}
e.preventDefault();
Engine.loadFactionsContent();
} else if (e.keyCode == 65 && e.altKey) {
@ -715,47 +718,81 @@ let Engine = {
},
displayAugmentationsContent: function() {
//Purchased/queued augmentations
var queuedAugmentationsList = document.getElementById("queued-augmentations-list");
removeChildrenFromElement(Engine.Display.augmentationsContent);
Engine.Display.augmentationsContent.appendChild(createElement("h1", {
innerText:"Purchased Augmentations"
}));
while (queuedAugmentationsList.firstChild) {
queuedAugmentationsList.removeChild(queuedAugmentationsList.firstChild);
}
Engine.Display.augmentationsContent.appendChild(createElement("pre", {
width:"70%", whiteSpace:"pre-wrap", display:"block",
innerText:"Below is a list of all Augmentations you have purchased but not yet installed. Click the button below to install them.\n" +
"WARNING: Installing your Augmentations resets most of your progress, including:\n\n" +
"Stats/Skill levels and Experience\n" +
"Money\n" +
"Scripts on every computer but your home computer\n" +
"Purchased servers\n" +
"Hacknet Nodes\n" +
"Faction/Company reputation\n" +
"Stocks\n\n" +
"Installing Augmentations lets you start over with the perks and benefits granted by all " +
"of the Augmentations you have ever installed. Also, you will keep any scripts and RAM/Core upgrades " +
"on your home computer (but you will lose all programs besides NUKE.exe)."
}));
//Purchased/queued augmentations
var queuedAugmentationsList = createElement("ul", {
id:"queued-augmentations-list"
});
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
var augName = Player.queuedAugmentations[i].name;
var aug = Augmentations[augName];
var item = document.createElement("li");
var hElem = document.createElement("h2");
var pElem = document.createElement("p");
item.setAttribute("class", "installed-augmentation");
hElem.innerHTML = augName;
if (augName == AugmentationNames.NeuroFluxGovernor) {
hElem.innerHTML += " - Level " + (Player.queuedAugmentations[i].level);
var item = createElement("li", {class:"installed-augmentation"});
var displayName = augName;
if (augName === AugmentationNames.NeuroFluxGovernor) {
displayName += " - Level " + (Player.queuedAugmentations[i].level);
}
pElem.innerHTML = aug.info;
item.appendChild(hElem);
item.appendChild(pElem);
item.appendChild(createElement("h2", {innerHTML:displayName}));
item.appendChild(createElement("p", {innerHTML:aug.info}));
queuedAugmentationsList.appendChild(item);
}
Engine.Display.augmentationsContent.appendChild(queuedAugmentationsList);
//Install Augmentations button
var installButton = clearEventListeners("install-augmentations-button");
installButton.addEventListener("click", function() {
Engine.Display.augmentationsContent.appendChild(createElement("a", {
class:"a-link-button", innerText:"Install Augmentations",
tooltip:"'I never asked for this'",
clickListener:()=>{
installAugmentations();
return false;
});
//Installed augmentations
var augmentationsList = document.getElementById("augmentations-list");
while (augmentationsList.firstChild) {
augmentationsList.removeChild(augmentationsList.firstChild);
}
}));
//Backup button
Engine.Display.augmentationsContent.appendChild(createElement("a", {
class:"a-link-button flashing-button", innerText:"Backup Save (Export)",
tooltip:"It's always a good idea to backup/export your save!",
clickListener:()=>{
saveObject.exportGame();
return false;
}
}));
//Installed augmentations list
Engine.Display.augmentationsContent.appendChild(createElement("h1", {
innerText:"Installed Augmentations"
}));
Engine.Display.augmentationsContent.appendChild(createElement("p", {
width:"70%", whiteSpace:"pre-wrap",
innerText:"List of all Augmentations (including Source Files) that have been " +
"installed. You have gained the effects of these Augmentations"
}));
var augmentationsList = createElement("ul", {
id:"augmentations-list"
});
//Source Files - Temporary...Will probably put in a separate pane Later
for (var i = 0; i < Player.sourceFiles.length; ++i) {
@ -765,17 +802,13 @@ let Engine = {
console.log("ERROR: Invalid source file number: " + Player.sourceFiles[i].n);
continue;
}
var item = document.createElement("li");
var hElem = document.createElement("h2");
var pElem = document.createElement("p");
item.setAttribute("class", "installed-augmentation");
hElem.innerHTML = sourceFileObject.name + "<br>";
hElem.innerHTML += "Level " + (Player.sourceFiles[i].lvl) + " / 3";
pElem.innerHTML = sourceFileObject.info;
item.appendChild(hElem);
item.appendChild(pElem);
var item = createElement("li", {class:"installed-augmentation", });
item.appendChild(createElement("h2", {
innerHTML:sourceFileObject.name + "<br>" + "Level " + (Player.sourceFiles[i].lvl) + " / 3",
}));
item.appendChild(createElement("p", {
innerHTML:sourceFileObject.info,
}));
augmentationsList.appendChild(item);
}
@ -784,22 +817,17 @@ let Engine = {
var augName = Player.augmentations[i].name;
var aug = Augmentations[augName];
var item = document.createElement("li");
var hElem = document.createElement("h2");
var pElem = document.createElement("p");
item.setAttribute("class", "installed-augmentation");
hElem.innerHTML = augName;
if (augName == AugmentationNames.NeuroFluxGovernor) {
hElem.innerHTML += " - Level " + (Player.augmentations[i].level);
var item = createElement("li", {class:"installed-augmentation"});
var displayName = augName;
if (augName === AugmentationNames.NeuroFluxGovernor) {
displayName += " - Level " + (Player.augmentations[i].level);
}
pElem.innerHTML = aug.info;
item.appendChild(hElem);
item.appendChild(pElem);
item.appendChild(createElement("h2", {innerHTML:displayName}));
item.appendChild(createElement("p", {innerHTML:aug.info}));
augmentationsList.appendChild(item);
}
Engine.Display.augmentationsContent.appendChild(augmentationsList);
},
displayTutorialContent: function() {
@ -904,7 +932,9 @@ let Engine = {
//Corporation
if (Player.corporation instanceof Corporation) {
Player.corporation.process(numCycles);
//Stores cycles in a "buffer". Processed separately using Engine Counters
//This is to avoid constant DOM redraws when Corporation is catching up
Player.corporation.storeCycles(numCycles);
}
//Counters
@ -937,6 +967,7 @@ let Engine = {
messages: 150,
stockTick: 30, //Update stock prices
sCr: 1500,
corpProcess: 5,
},
decrementAllCounters: function(numCycles = 1) {
@ -1059,6 +1090,13 @@ let Engine = {
}
Engine.Counters.sCr = 1500;
}
if (Engine.Counters.corpProcess <= 0) {
if (Player.corporation instanceof Corporation) {
Player.corporation.process();
}
Engine.Counters.corpProcess = 5;
}
},
/* Calculates the hack progress for a manual (non-scripted) hack and updates the progress bar/time accordingly */

@ -83,6 +83,7 @@ function createElement(type, params={}) {
if (params.border) {el.style.border = params.border;}
if (params.float) {el.style.cssFloat = params.float;}
if (params.fontSize) {el.style.fontSize = params.fontSize;}
if (params.whiteSpace) {el.style.whiteSpace = params.whiteSpace;}
if (params.width) {el.style.width = params.width;}
if (params.backgroundColor) {
el.style.backgroundColor = params.backgroundColor

@ -25,13 +25,14 @@ function infiltrationSetText(txt) {
//ram argument is in GB
function infiltrationBoxCreate(inst) {
//Gain exp
Player.gainHackingExp(inst.hackingExpGained);
Player.gainStrengthExp(inst.strExpGained);
Player.gainDefenseExp(inst.defExpGained);
Player.gainDexterityExp(inst.dexExpGained);
Player.gainAgilityExp(inst.agiExpGained);
Player.gainCharismaExp(inst.chaExpGained);
Player.gainIntelligenceExp(inst.intExpGained);
var expMultiplier = 2 * inst.clearanceLevel / inst.maxClearanceLevel;
Player.gainHackingExp(inst.hackingExpGained * expMultiplier);
Player.gainStrengthExp(inst.strExpGained * expMultiplier);
Player.gainDefenseExp(inst.defExpGained * expMultiplier);
Player.gainDexterityExp(inst.dexExpGained * expMultiplier);
Player.gainAgilityExp(inst.agiExpGained * expMultiplier);
Player.gainCharismaExp(inst.chaExpGained * expMultiplier);
Player.gainIntelligenceExp(inst.intExpGained * expMultiplier);
var totalValue = 0;
for (var i = 0; i < inst.secretsStolen.length; ++i) {