Revert "Revert "Gang rework""

This reverts commit be0a08d70caacd9bc3a43faab2825cd5f3c68e1f.
This commit is contained in:
danielyxie 2018-10-23 13:55:42 -05:00
parent 66e7d88d0e
commit 61150f5823
41 changed files with 171074 additions and 1693 deletions

@ -82,3 +82,27 @@ button {
pointer-events: none; pointer-events: none;
} }
} }
/**
* This is a button that is meant to be used on accordions (accordion-header and accordion-panel classes)
* It has a black background so it does not clash with the default accordion coloring
*/
.accordion-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
&:hover,
&:active {
color: #fff;
text-decoration: none;
cursor: pointer;
}
/* TODO focus selector? */
}

48
css/gang.scss Normal file

@ -0,0 +1,48 @@
@import "mixins";
@import "theme";
/**
* Styling for the Gang mechanic UI (BitNode-2)
*/
#gang-container {
position: fixed;
padding: 6px;
p, pre {
font-size: $defaultFontSize * 0.9375;
}
select {
background-color: black;
color: white;
}
}
#gang-management-subpage > p {
padding: 4px;
}
.gang-member-info-div {
background-color: #555;
display: inline;
float: left;
width: 30%;
}
/**
* Showing owned upgrades in the Equipment Box
*/
.gang-owned-upgrades-div {
display: inline-block;
margin-left: 6px;
width: 75%;
}
.gang-owned-upgrade {
border: 1px solid white;
font-size: 12px;
margin: 1px;
padding: 1px;
}

@ -248,25 +248,6 @@
} }
} }
.active-scripts-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
&:hover,
&:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
}
/* Hacknet Nodes */ /* Hacknet Nodes */
#hacknet-nodes-container { #hacknet-nodes-container {
position: fixed; position: fixed;
@ -623,18 +604,3 @@
margin: 2px; margin: 2px;
padding: 0; padding: 0;
} }
/* Gang */
#gang-container {
position: fixed;
padding: 6px;
}
#gang-management-subpage > p {
padding: 4px;
}
.gang-member-info-div {
float: left;
background-color: #555;
}

@ -114,6 +114,29 @@ a:visited {
position: absolute; position: absolute;
z-index: 99; z-index: 99;
} }
/* Positioned to left of element rather than right */
.tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99;
}
} }
/* Same thing as a normal tooltip except its a bit higher */ /* Same thing as a normal tooltip except its a bit higher */
@ -132,23 +155,6 @@ a:visited {
z-index: 99; z-index: 99;
} }
/* Similar to a normal tooltip except its positioned on the left of the element
rather than the right to avoid exceeding the elements normal width */
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 40%;
bottom: -10%;
position: absolute;
z-index: 99;
}
.tooltip:hover .tooltiptext, .tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh, .tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft { .tooltip:hover .tooltiptextleft {
@ -157,13 +163,14 @@ a:visited {
/* help tip. Question mark that opens popup with info/details */ /* help tip. Question mark that opens popup with info/details */
.help-tip { .help-tip {
content: '?'; background-color: black;
padding: 1px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff; border: 1px solid #fff;
border-radius: 5px; border-radius: 5px;
color: #fff;
content: '?';
display: inline-block; display: inline-block;
margin-left: 3px;
padding: 1px;
} }
.help-tip-big { .help-tip-big {
@ -412,7 +419,7 @@ a:visited {
&:after { &:after {
content: '\02795'; /* "plus" sign (+) */ content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125; font-size: $defaultFontSize * 0.875;
float: right; float: right;
color: transparent; color: transparent;
text-shadow: 0 0 0 #fff; text-shadow: 0 0 0 #fff;
@ -479,3 +486,7 @@ a:visited {
.charisma-purple { .charisma-purple {
color: $my-stat-cha-color; color: $my-stat-cha-color;
} }
.smallfont {
font-size: $defaultFontSize * 0.8125;
}

56961
dist/engine.bundle.js vendored

File diff suppressed because one or more lines are too long

142
dist/engine.css vendored

@ -94,7 +94,8 @@ a:visited {
/* Tool tips (when hovering over an element */ /* Tool tips (when hovering over an element */
.tooltip { .tooltip {
display: inline-block; display: inline-block;
position: relative; } position: relative;
/* Positioned to left of element rather than right */ }
.tooltip .tooltiptext { .tooltip .tooltiptext {
visibility: hidden; visibility: hidden;
width: 300px; width: 300px;
@ -107,6 +108,24 @@ a:visited {
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
z-index: 99; } z-index: 99; }
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99; }
/* Same thing as a normal tooltip except its a bit higher */ /* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh { .tooltip .tooltiptexthigh {
@ -122,21 +141,6 @@ a:visited {
position: absolute; position: absolute;
z-index: 99; } z-index: 99; }
/* Similar to a normal tooltip except its positioned on the left of the element
rather than the right to avoid exceeding the elements normal width */
.tooltip .tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 40%;
bottom: -10%;
position: absolute;
z-index: 99; }
.tooltip:hover .tooltiptext, .tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh, .tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft { .tooltip:hover .tooltiptextleft {
@ -144,13 +148,14 @@ a:visited {
/* help tip. Question mark that opens popup with info/details */ /* help tip. Question mark that opens popup with info/details */
.help-tip { .help-tip {
content: '?'; background-color: black;
padding: 1px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff; border: 1px solid #fff;
border-radius: 5px; border-radius: 5px;
display: inline-block; } color: #fff;
content: '?';
display: inline-block;
margin-left: 3px;
padding: 1px; }
.help-tip-big { .help-tip-big {
content: '?'; content: '?';
@ -418,7 +423,7 @@ a:visited {
.accordion-header:after { .accordion-header:after {
content: '\2795'; content: '\2795';
/* "plus" sign (+) */ /* "plus" sign (+) */
font-size: 13px; font-size: 14px;
float: right; float: right;
color: transparent; color: transparent;
text-shadow: 0 0 0 #fff; text-shadow: 0 0 0 #fff;
@ -472,6 +477,9 @@ a:visited {
.charisma-purple { .charisma-purple {
color: #a671d1; } color: #a671d1; }
.smallfont {
font-size: 13px; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/** /**
@ -546,6 +554,29 @@ button {
.std-button-bought:active { .std-button-bought:active {
pointer-events: none; } pointer-events: none; }
/**
* This is a button that is meant to be used on accordions (accordion-header and accordion-panel classes)
* It has a black background so it does not clash with the default accordion coloring
*/
.accordion-button {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: 1px 1px 3px #000;
-moz-box-shadow: 1px 1px 3px #000;
box-shadow: 1px 1px 3px #000;
color: #aaa;
font-size: 16px;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
/* TODO focus selector? */ }
.accordion-button:hover, .accordion-button:active {
color: #fff;
text-decoration: none;
cursor: pointer; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/** /**
@ -921,24 +952,6 @@ button {
color: #fff; color: #fff;
margin-left: 5%; } margin-left: 5%; }
.active-scripts-button {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-box-shadow: 1px 1px 3px #000;
-moz-box-shadow: 1px 1px 3px #000;
box-shadow: 1px 1px 3px #000;
color: #aaa;
font-size: 16px;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000; }
.active-scripts-button:hover, .active-scripts-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer; }
/* Hacknet Nodes */ /* Hacknet Nodes */
#hacknet-nodes-container { #hacknet-nodes-container {
position: fixed; position: fixed;
@ -1227,18 +1240,6 @@ button {
margin: 2px; margin: 2px;
padding: 0; } padding: 0; }
/* Gang */
#gang-container {
position: fixed;
padding: 6px; }
#gang-management-subpage > p {
padding: 4px; }
.gang-member-info-div {
float: left;
background-color: #555; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/* Both Work in progress and BitNode stuff */ /* Both Work in progress and BitNode stuff */
@ -2040,5 +2041,42 @@ button {
-webkit-hyphens: auto; -webkit-hyphens: auto;
-moz-hyphens: auto; } -moz-hyphens: auto; }
/* COLORS */
/* Attributes */
/**
* Styling for the Gang mechanic UI (BitNode-2)
*/
#gang-container {
position: fixed;
padding: 6px; }
#gang-container p, #gang-container pre {
font-size: 15px; }
#gang-container select {
background-color: black;
color: white; }
#gang-management-subpage > p {
padding: 4px; }
.gang-member-info-div {
background-color: #555;
display: inline;
float: left;
width: 30%; }
/**
* Showing owned upgrades in the Equipment Box
*/
.gang-owned-upgrades-div {
display: inline-block;
margin-left: 6px;
width: 75%; }
.gang-owned-upgrade {
border: 1px solid white;
font-size: 12px;
margin: 1px;
padding: 1px; }
/*# sourceMappingURL=engine.css.map*/ /*# sourceMappingURL=engine.css.map*/

111050
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -25,5 +25,6 @@ to reach out to the developer!
Trade Information eXchange (TIX) API <netscriptixapi> Trade Information eXchange (TIX) API <netscriptixapi>
Singularity Functions <netscriptsingularityfunctions> Singularity Functions <netscriptsingularityfunctions>
Bladeburner API <netscriptbladeburnerapi> Bladeburner API <netscriptbladeburnerapi>
Gang API <netscriptgangapi>
Coding Contract API <netscriptcodingcontractapi> Coding Contract API <netscriptcodingcontractapi>
Miscellaneous <netscriptmisc> Miscellaneous <netscriptmisc>

@ -13,6 +13,7 @@ hack
:param string hostname/ip: IP or hostname of the target server to hack :param string hostname/ip: IP or hostname of the target server to hack
:returns: The amount of money stolen if the hack is successful, and zero otherwise :returns: The amount of money stolen if the hack is successful, and zero otherwise
:RAM cost: 0.1 GB
Function that is used to try and hack servers to steal money and gain hacking experience. The runtime for this command depends Function that is used to try and hack servers to steal money and gain hacking experience. The runtime for this command depends
on your hacking level and the target server's security level. In order to hack a server you must first gain root access on your hacking level and the target server's security level. In order to hack a server you must first gain root access
@ -35,6 +36,7 @@ grow
:param string hostname/ip: IP or hostname of the target server to grow :param string hostname/ip: IP or hostname of the target server to grow
:returns: The number by which the money on the server was multiplied for the growth :returns: The number by which the money on the server was multiplied for the growth
:RAM cost: 0.15 GB
Use your hacking skills to increase the amount of money available on a server. The runtime for this command depends on your hacking Use your hacking skills to increase the amount of money available on a server. The runtime for this command depends on your hacking
level and the target server's security level. When grow() completes, the money available on a target server will be increased by a level and the target server's security level. When grow() completes, the money available on a target server will be increased by a
@ -57,6 +59,7 @@ weaken
:param string hostname.ip: IP or hostname of the target server to weaken :param string hostname.ip: IP or hostname of the target server to weaken
:returns: The amount by which the target server's security level was decreased. This is equivalent to 0.05 multiplied :returns: The amount by which the target server's security level was decreased. This is equivalent to 0.05 multiplied
by the number of script threads by the number of script threads
:RAM cost: 0.15 GB
Use your hacking skills to attack a server's security, lowering the server's security level. The runtime for this command Use your hacking skills to attack a server's security, lowering the server's security level. The runtime for this command
depends on your hacking level and the target server's security level. This function lowers the security level of the target depends on your hacking level and the target server's security level. This function lowers the security level of the target
@ -75,6 +78,7 @@ sleep
.. js:function:: sleep(n) .. js:function:: sleep(n)
:param number n: Number of milliseconds to sleep :param number n: Number of milliseconds to sleep
:RAM cost: 0 GB
Suspends the script for n milliseconds. Suspends the script for n milliseconds.
@ -84,6 +88,7 @@ print
.. js:function:: print(x) .. js:function:: print(x)
:param x: Value to be printed :param x: Value to be printed
:RAM cost: 0 GB
Prints a value or a variable to the script's logs. Prints a value or a variable to the script's logs.
@ -93,6 +98,7 @@ tprint
.. js:function:: tprint(x) .. js:function:: tprint(x)
:param x: Value to be printed :param x: Value to be printed
:RAM cost: 0 GB
Prints a value or a variable to the Terminal Prints a value or a variable to the Terminal
@ -101,6 +107,8 @@ clearLog
.. js:function:: clearLog() .. js:function:: clearLog()
:RAM cost: 0 GB
Clears the script's logs Clears the script's logs
disableLog disableLog
@ -109,6 +117,7 @@ disableLog
.. js:function:: disableLog(fn) .. js:function:: disableLog(fn)
:param string fn: Name of function for which to disable logging :param string fn: Name of function for which to disable logging
:RAM cost: 0 GB
Disables logging for the given function. Logging can be disabled for Disables logging for the given function. Logging can be disabled for
all functions by passing 'ALL' as the argument. all functions by passing 'ALL' as the argument.
@ -125,6 +134,7 @@ enableLog
.. js:function:: enableLog(fn) .. js:function:: enableLog(fn)
:param string fn: Name of function for which to enable logging :param string fn: Name of function for which to enable logging
:RAM cost: 0 GB
Re-enables logging for the given function. If 'ALL' is passed into this function Re-enables logging for the given function. If 'ALL' is passed into this function
as an argument, then it will revert the effects of disableLog('ALL') as an argument, then it will revert the effects of disableLog('ALL')
@ -135,6 +145,7 @@ isLogEnabled
.. js:function:: isLogEnabled(fn) .. js:function:: isLogEnabled(fn)
:param string fn: Name of function to check :param string fn: Name of function to check
:RAM cost: 0 GB
Returns a boolean indicating whether or not logging is enabled for that Returns a boolean indicating whether or not logging is enabled for that
function (or 'ALL') function (or 'ALL')
@ -144,6 +155,8 @@ getScriptLogs
.. js:function:: getScriptLogs() .. js:function:: getScriptLogs()
:RAM cost: 0 GB
Returns the script's logs. The logs are returned as an array, where each Returns the script's logs. The logs are returned as an array, where each
line is an element in the array. The most recently logged line is at the line is an element in the array. The most recently logged line is at the
end of the array. end of the array.
@ -158,6 +171,7 @@ scan
:param string hostname/ip: IP or hostname of the server to scan :param string hostname/ip: IP or hostname of the server to scan
:param boolean: Optional boolean specifying whether the function should output hostnames (if true) or IP addresses (if false) :param boolean: Optional boolean specifying whether the function should output hostnames (if true) or IP addresses (if false)
:RAM cost: 0.2 GB
Returns an array containing the hostnames or IPs of all servers that are one node way from the specified target server. The Returns an array containing the hostnames or IPs of all servers that are one node way from the specified target server. The
hostnames/IPs in the returned array are strings. hostnames/IPs in the returned array are strings.
@ -168,6 +182,7 @@ nuke
.. js:function:: nuke(hostname/ip) .. js:function:: nuke(hostname/ip)
:param string hostname/ip: IP or hostname of the target server :param string hostname/ip: IP or hostname of the target server
:RAM cost: 0 GB
Runs the NUKE.exe program on the target server. NUKE.exe must exist on your home computer. Runs the NUKE.exe program on the target server. NUKE.exe must exist on your home computer.
@ -181,6 +196,7 @@ brutessh
.. js:function:: brutessh(hostname/ip) .. js:function:: brutessh(hostname/ip)
:param string hostname/ip: IP or hostname of the target server :param string hostname/ip: IP or hostname of the target server
:RAM cost: 0 GB
Runs the BruteSSH.exe program on the target server. BruteSSH.exe must exist on your home computer. Runs the BruteSSH.exe program on the target server. BruteSSH.exe must exist on your home computer.
@ -194,6 +210,7 @@ ftpcrack
.. js:function:: ftpcrack(hostname/ip) .. js:function:: ftpcrack(hostname/ip)
:param string hostname/ip: IP or hostname of the target server :param string hostname/ip: IP or hostname of the target server
:RAM cost: 0 GB
Runs the FTPCrack.exe program on the target server. FTPCrack.exe must exist on your home computer. Runs the FTPCrack.exe program on the target server. FTPCrack.exe must exist on your home computer.
@ -207,6 +224,7 @@ relaysmtp
.. js:function:: relaysmtp(hostname/ip) .. js:function:: relaysmtp(hostname/ip)
:param string hostname/ip: IP or hostname of the target server :param string hostname/ip: IP or hostname of the target server
:RAM cost: 0 GB
Runs the relaySMTP.exe program on the target server. relaySMTP.exe must exist on your home computer. Runs the relaySMTP.exe program on the target server. relaySMTP.exe must exist on your home computer.
@ -220,6 +238,7 @@ httpworm
.. js:function:: httpworm(hostname/ip) .. js:function:: httpworm(hostname/ip)
:param string hostname/ip: IP or hostname of the target server :param string hostname/ip: IP or hostname of the target server
:RAM cost: 0 GB
Runs the HTTPWorm.exe program on the target server. HTTPWorm.exe must exist on your home computer. Runs the HTTPWorm.exe program on the target server. HTTPWorm.exe must exist on your home computer.
@ -233,6 +252,7 @@ sqlinject
.. js:function:: sqlinject(hostname/ip) .. js:function:: sqlinject(hostname/ip)
:param string hostname/ip: IP or hostname of the target server :param string hostname/ip: IP or hostname of the target server
:RAM cost: 0 GB
Runs the SQLInject.exe program on the target server. SQLInject.exe must exist on your home computer. Runs the SQLInject.exe program on the target server. SQLInject.exe must exist on your home computer.
@ -250,6 +270,7 @@ run
:param args...: :param args...:
Additional arguments to pass into the new script that is being run. Note that if any arguments are being Additional arguments to pass into the new script that is being run. Note that if any arguments are being
passed into the new script, then the second argument *numThreads* must be filled in with a value. passed into the new script, then the second argument *numThreads* must be filled in with a value.
:RAM cost: 1 GB
Run a script as a separate process. This function can only be used to run scripts located on the current server (the server Run a script as a separate process. This function can only be used to run scripts located on the current server (the server
running the script that calls this function). running the script that calls this function).
@ -282,6 +303,7 @@ exec
:param args...: :param args...:
Additional arguments to pass into the new script that is being run. Note that if any arguments are being Additional arguments to pass into the new script that is being run. Note that if any arguments are being
passed into the new script, then the third argument *numThreads* must be filled in with a value. passed into the new script, then the third argument *numThreads* must be filled in with a value.
:RAM cost: 1.3 GB
Run a script as a separate process on a specified server. This is similar to the *run* function except Run a script as a separate process on a specified server. This is similar to the *run* function except
that it can be used to run a script on any server, instead of just the current server. that it can be used to run a script on any server, instead of just the current server.
@ -311,6 +333,7 @@ spawn
:param number numThreads: Number of threads to spawn new script with. Will be rounded to nearest integer :param number numThreads: Number of threads to spawn new script with. Will be rounded to nearest integer
:param args...: :param args...:
Additional arguments to pass into the new script that is being run. Additional arguments to pass into the new script that is being run.
:RAM cost: 2 GB
Terminates the current script, and then after a delay of about 20 seconds it will execute the newly-specified script. Terminates the current script, and then after a delay of about 20 seconds it will execute the newly-specified script.
The purpose of this function is to execute a new script without being constrained by the RAM usage of the current one. The purpose of this function is to execute a new script without being constrained by the RAM usage of the current one.
@ -330,6 +353,7 @@ kill
:param string script: Filename of the script to kill :param string script: Filename of the script to kill
:param string hostname/ip: IP or hostname of the server on which to kill the script :param string hostname/ip: IP or hostname of the server on which to kill the script
:param args...: Arguments to identify which script to kill :param args...: Arguments to identify which script to kill
:RAM cost: 0.5 GB
Kills the script on the target server specified by the script's name and arguments. Remember that scripts Kills the script on the target server specified by the script's name and arguments. Remember that scripts
are uniquely identified by both their name and arguments. For example, if *foo.script* is run with the argument 1, then this are uniquely identified by both their name and arguments. For example, if *foo.script* is run with the argument 1, then this
@ -357,6 +381,7 @@ killall
.. js:function:: killall(hostname/ip) .. js:function:: killall(hostname/ip)
:param string hostname/ip: IP or hostname of the server on which to kill all scripts :param string hostname/ip: IP or hostname of the server on which to kill all scripts
:RAM cost: 0.5 GB
Kills all running scripts on the specified server. This function returns true if any scripts were killed, and Kills all running scripts on the specified server. This function returns true if any scripts were killed, and
false otherwise. In other words, it will return true if there are any scripts running on the target server. false otherwise. In other words, it will return true if there are any scripts running on the target server.
@ -367,6 +392,8 @@ exit
.. js:function:: exit() .. js:function:: exit()
:RAM cost: 0 GB
Terminates the current script immediately Terminates the current script immediately
scp scp
@ -379,6 +406,7 @@ scp
Hostname or IP of the source server, which is the server from which the file will be copied. Hostname or IP of the source server, which is the server from which the file will be copied.
This argument is optional and if it's omitted the source will be the current server. This argument is optional and if it's omitted the source will be the current server.
:param string destination: Hostname or IP of the destination server, which is the server to which the file will be copied. :param string destination: Hostname or IP of the destination server, which is the server to which the file will be copied.
:RAM cost: 0.6 GB
Copies a script or literature (.lit) file(s) to another server. The *files* argument can be either a string specifying a Copies a script or literature (.lit) file(s) to another server. The *files* argument can be either a string specifying a
single file to copy, or an array of strings specifying multiple files to copy. single file to copy, or an array of strings specifying multiple files to copy.
@ -405,6 +433,7 @@ ls
:param string hostname/ip: Hostname or IP of the target server :param string hostname/ip: Hostname or IP of the target server
:param string grep: a substring to search for in the filename :param string grep: a substring to search for in the filename
:RAM cost: 0 GB
Returns an array with the filenames of all files on the specified server (as strings). The returned array Returns an array with the filenames of all files on the specified server (as strings). The returned array
is sorted in alphabetic order is sorted in alphabetic order
@ -416,6 +445,7 @@ ps
:param string ip: Hostname or IP address of the target server. :param string ip: Hostname or IP address of the target server.
If not specified, it will be the current server's IP by default If not specified, it will be the current server's IP by default
:RAM cost: 0 GB
Returns an array with general information about all scripts running on the specified Returns an array with general information about all scripts running on the specified
target server. The information for each server is given in an object with target server. The information for each server is given in an object with
@ -443,6 +473,7 @@ hasRootAccess
.. js:function:: hasRootAccess(hostname/ip) .. js:function:: hasRootAccess(hostname/ip)
:param string hostname/ip: Hostname or IP of the target server :param string hostname/ip: Hostname or IP of the target server
:RAM cost: 0.05 GB
Returns a boolean indicating whether or not the player has root access to the specified target server. Returns a boolean indicating whether or not the player has root access to the specified target server.
@ -457,6 +488,8 @@ getHostname
.. js:function:: getHostname() .. js:function:: getHostname()
:RAM cost: 0.05 GB
Returns a string with the hostname of the server that the script is running on Returns a string with the hostname of the server that the script is running on
getHackingLevel getHackingLevel
@ -464,6 +497,8 @@ getHackingLevel
.. js:function:: getHackingLevel() .. js:function:: getHackingLevel()
:RAM cost: 0.05 GB
Returns the player's current hacking level Returns the player's current hacking level
getHackingMultipliers getHackingMultipliers
@ -471,8 +506,10 @@ getHackingMultipliers
.. js:function:: getHackingMultipliers() .. js:function:: getHackingMultipliers()
:RAM cost: 4 GB
Returns an object containing the Player's hacking related multipliers. These multipliers are Returns an object containing the Player's hacking related multipliers. These multipliers are
returned in fractional forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure:: returned in decimal forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure::
{ {
chance: Player's hacking chance multiplier, chance: Player's hacking chance multiplier,
@ -492,8 +529,10 @@ getHacknetMultipliers
.. js:function:: getHacknetMultipliers() .. js:function:: getHacknetMultipliers()
:RAM cost: 4 GB
Returns an object containing the Player's hacknet related multipliers. These multipliers are Returns an object containing the Player's hacknet related multipliers. These multipliers are
returned in fractional forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure:: returned in decimal forms, not percentages (e.g. 1.5 instead of 150%). The object has the following structure::
{ {
production: Player's hacknet production multiplier, production: Player's hacknet production multiplier,
@ -517,6 +556,7 @@ getServerMoneyAvailable
.. js:function:: getServerMoneyAvailable(hostname/ip) .. js:function:: getServerMoneyAvailable(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the amount of money available on a server. **Running this function on the home computer will return Returns the amount of money available on a server. **Running this function on the home computer will return
the player's money.** the player's money.**
@ -532,6 +572,7 @@ getServerMaxMoney
.. js:function:: getServerMaxMoney(hostname/ip) .. js:function:: getServerMaxMoney(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the maximum amount of money that can be available on a server Returns the maximum amount of money that can be available on a server
@ -541,6 +582,7 @@ getServerGrowth
.. js:function:: getServerGrowth(hostname/ip) .. js:function:: getServerGrowth(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the server's instrinsic "growth parameter". This growth parameter is a number Returns the server's instrinsic "growth parameter". This growth parameter is a number
between 1 and 100 that represents how quickly the server's money grows. This parameter affects the between 1 and 100 that represents how quickly the server's money grows. This parameter affects the
@ -553,6 +595,7 @@ getServerSecurityLevel
.. js:function:: getServerSecurityLevel(hostname/ip) .. js:function:: getServerSecurityLevel(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the security level of the target server. A server's security level is denoted by a number, typically Returns the security level of the target server. A server's security level is denoted by a number, typically
between 1 and 100 (but it can go above 100). between 1 and 100 (but it can go above 100).
@ -563,6 +606,7 @@ getServerBaseSecurityLevel
.. js:function:: getServerBaseSecurityLevel(hostname/ip) .. js:function:: getServerBaseSecurityLevel(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the base security level of the target server. This is the security level that the server starts out with. Returns the base security level of the target server. This is the security level that the server starts out with.
This is different than *getServerSecurityLevel()* because *getServerSecurityLevel()* returns the current This is different than *getServerSecurityLevel()* because *getServerSecurityLevel()* returns the current
@ -575,6 +619,7 @@ getServerMinSecurityLevel
.. js:function:: getServerMinSecurityLevel(hostname/ip) .. js:function:: getServerMinSecurityLevel(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the minimum security level of the target server Returns the minimum security level of the target server
@ -584,6 +629,7 @@ getServerRequiredHackingLevel
.. js:function:: getServerRequiredHackingLevel(hostname/ip) .. js:function:: getServerRequiredHackingLevel(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the required hacking level of the target server Returns the required hacking level of the target server
@ -593,6 +639,7 @@ getServerNumPortsRequired
.. js:function:: getServerNumPortsRequired(hostname/ip) .. js:function:: getServerNumPortsRequired(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns the number of open ports required to successfully run NUKE.exe on the specified server. Returns the number of open ports required to successfully run NUKE.exe on the specified server.
@ -602,6 +649,7 @@ getServerRam
.. js:function:: getServerRam(hostname/ip) .. js:function:: getServerRam(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns an array with two elements that gives information about a server's memory (RAM). The first Returns an array with two elements that gives information about a server's memory (RAM). The first
element in the array is the amount of RAM that the server has total (in GB). The second element in element in the array is the amount of RAM that the server has total (in GB). The second element in
@ -619,6 +667,7 @@ serverExists
.. js:function:: serverExists(hostname/ip) .. js:function:: serverExists(hostname/ip)
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 0.1 GB
Returns a boolean denoting whether or not the specified server exists Returns a boolean denoting whether or not the specified server exists
@ -631,6 +680,7 @@ fileExists
:param string hostname/ip: :param string hostname/ip:
Hostname or IP of target server. This is optional. If it is not specified then the Hostname or IP of target server. This is optional. If it is not specified then the
function will use the current server as the target server function will use the current server as the target server
:RAM cost: 0.1 GB
Returns a boolean indicating whether the specified file exists on the target server. The filename Returns a boolean indicating whether the specified file exists on the target server. The filename
for scripts is case-sensitive, but for other types of files it is not. For example, *fileExists("brutessh.exe")* for scripts is case-sensitive, but for other types of files it is not. For example, *fileExists("brutessh.exe")*
@ -655,6 +705,7 @@ isRunning
:param string filename: Filename of script to check. This is case-sensitive. :param string filename: Filename of script to check. This is case-sensitive.
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:param args...: Arguments to specify/identify which scripts to search for :param args...: Arguments to specify/identify which scripts to search for
:RAM cost: 0.1 GB
Returns a boolean indicating whether the specified script is running on the target server. Remember that a script is Returns a boolean indicating whether the specified script is running on the target server. Remember that a script is
uniquely identified by both its name and its arguments. uniquely identified by both its name and its arguments.
@ -681,6 +732,8 @@ getNextHacknetNodeCost
.. js:function:: getNextHacknetNodeCost() .. js:function:: getNextHacknetNodeCost()
:RAM cost: 0 GB
Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi` Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi`
purchaseHacknetNode purchaseHacknetNode
@ -688,6 +741,8 @@ purchaseHacknetNode
.. js:function:: purchaseHacknetNode() .. js:function:: purchaseHacknetNode()
:RAM cost: 0 GB
Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi` Deprecated (no longer usable). See :doc:`netscripthacknetnodeapi`
getPurchasedServerCost getPurchasedServerCost
@ -695,6 +750,8 @@ getPurchasedServerCost
.. js:function:: getPurchasedServerCost(ram) .. js:function:: getPurchasedServerCost(ram)
:RAM cost: 0.25 GB
:param number ram: Amount of RAM of a potential purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20) :param number ram: Amount of RAM of a potential purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20)
Returns the cost to purchase a server with the specified amount of *ram*. Returns the cost to purchase a server with the specified amount of *ram*.
@ -712,6 +769,7 @@ purchaseServer
:param string hostname: Hostname of the purchased server :param string hostname: Hostname of the purchased server
:param number ram: Amount of RAM of the purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20) :param number ram: Amount of RAM of the purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20)
:RAM cost: 2.25 GB
Purchased a server with the specified hostname and amount of RAM. Purchased a server with the specified hostname and amount of RAM.
@ -741,6 +799,7 @@ deleteServer
.. js:function:: deleteServer(hostname) .. js:function:: deleteServer(hostname)
:param string hostname: Hostname of the server to delete :param string hostname: Hostname of the server to delete
:RAM cost: 2.25 GB
Deletes one of your purchased servers, which is specified by its hostname. Deletes one of your purchased servers, which is specified by its hostname.
@ -757,6 +816,7 @@ getPurchasedServers
:param boolean hostname: :param boolean hostname:
Specifies whether hostnames or IP addresses should be returned. If it's true then hostnames will be returned, and if false Specifies whether hostnames or IP addresses should be returned. If it's true then hostnames will be returned, and if false
then IPs will be returned. If this argument is omitted then it is true by default then IPs will be returned. If this argument is omitted then it is true by default
:RAM cost: 2.25 GB
Returns an array with either the hostnames or IPs of all of the servers you have purchased. Returns an array with either the hostnames or IPs of all of the servers you have purchased.
@ -765,6 +825,8 @@ getPurchasedServerLimit
.. js:function:: getPurchasedServerLimit() .. js:function:: getPurchasedServerLimit()
:RAM cost: 0.05 GB
Returns the maximum number of servers you can purchase Returns the maximum number of servers you can purchase
getPurchasedServerMaxRam getPurchasedServerMaxRam
@ -772,6 +834,8 @@ getPurchasedServerMaxRam
.. js:function:: getPurchasedServerMaxRam() .. js:function:: getPurchasedServerMaxRam()
:RAM cost: 0.05 GB
Returns the maximum RAM that a purchased server can have Returns the maximum RAM that a purchased server can have
write write
@ -782,6 +846,7 @@ write
:param string/number port/fn: Port or text file/script that will be written to :param string/number port/fn: Port or text file/script that will be written to
:param string data: Data to write :param string data: Data to write
:param string mode: Defines the write mode. Only valid when writing to text files or scripts. :param string mode: Defines the write mode. Only valid when writing to text files or scripts.
:RAM cost: 1 GB
This function can be used to either write data to a port, a text file (.txt), or a script (.script, .js, .ns) This function can be used to either write data to a port, a text file (.txt), or a script (.script, .js, .ns)
@ -802,6 +867,7 @@ tryWrite
:param number port: Port to be written to :param number port: Port to be written to
:param string data: Data to try to write :param string data: Data to try to write
:returns: True if the data is successfully written to the port, and false otherwise :returns: True if the data is successfully written to the port, and false otherwise
:RAM cost: 1 GB
Attempts to write data to the specified Netscript Port. If the port is full, the data will Attempts to write data to the specified Netscript Port. If the port is full, the data will
not be written. Otherwise, the data will be written normally not be written. Otherwise, the data will be written normally
@ -812,6 +878,7 @@ read
.. js:function:: read(port/fn) .. js:function:: read(port/fn)
:param string/number port/fn: Port or text file to read from :param string/number port/fn: Port or text file to read from
:RAM cost: 1 GB
This function is used to read data from a port, a text file (.txt), or a script (.script, .js, .ns) This function is used to read data from a port, a text file (.txt), or a script (.script, .js, .ns)
@ -828,6 +895,7 @@ peek
.. js:function:: peek(port) .. js:function:: peek(port)
:param number port: Port to peek. Must be an integer between 1 and 20 :param number port: Port to peek. Must be an integer between 1 and 20
:RAM cost: 1 GB
This function is used to peek at the data from a port. It returns the first element in the specified port This function is used to peek at the data from a port. It returns the first element in the specified port
without removing that element. If the port is empty, the string "NULL PORT DATA" will be returned. without removing that element. If the port is empty, the string "NULL PORT DATA" will be returned.
@ -840,6 +908,7 @@ clear
.. js:function:: clear(port/fn) .. js:function:: clear(port/fn)
:param string/number port/fn: Port or text file to clear :param string/number port/fn: Port or text file to clear
:RAM cost: 1 GB
This function is used to clear data in a `Netscript Ports <http://bitburner.wikia.com/wiki/Netscript_Ports>`_ or a text file. This function is used to clear data in a `Netscript Ports <http://bitburner.wikia.com/wiki/Netscript_Ports>`_ or a text file.
@ -853,6 +922,7 @@ getPortHandle
.. js:function:: getPortHandle(port) .. js:function:: getPortHandle(port)
:param number port: Port number :param number port: Port number
:RAM cost: 10 GB
Get a handle to a Netscript Port. See more details here: :ref:`netscript_ports` Get a handle to a Netscript Port. See more details here: :ref:`netscript_ports`
@ -865,6 +935,7 @@ rm
:param string fn: Filename of file to remove. Must include the extension :param string fn: Filename of file to remove. Must include the extension
:returns: True if it successfully deletes the file, and false otherwise :returns: True if it successfully deletes the file, and false otherwise
:RAM cost: 1 GB
Removes the specified file from the current server. This function works for every file type except message (.msg) files. Removes the specified file from the current server. This function works for every file type except message (.msg) files.
@ -875,6 +946,7 @@ scriptRunning
:param string scriptname: Filename of script to check. This is case-sensitive. :param string scriptname: Filename of script to check. This is case-sensitive.
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 1 GB
Returns a boolean indicating whether any instance of the specified script is running on the target server, regardless of Returns a boolean indicating whether any instance of the specified script is running on the target server, regardless of
its arguments. its arguments.
@ -899,6 +971,7 @@ scriptKill
:param string scriptname: Filename of script to kill. This is case-sensitive. :param string scriptname: Filename of script to kill. This is case-sensitive.
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:RAM cost: 1 GB
Kills all scripts with the specified filename on the target server specified by *hostname/ip*, regardless of arguments. Returns Kills all scripts with the specified filename on the target server specified by *hostname/ip*, regardless of arguments. Returns
true if one or more scripts were successfully killed, and false if none were. true if one or more scripts were successfully killed, and false if none were.
@ -908,6 +981,8 @@ getScriptName
.. js:function:: getScriptName() .. js:function:: getScriptName()
:RAM cost: 0 GB
Returns the current script name Returns the current script name
getScriptRam getScriptRam
@ -917,6 +992,7 @@ getScriptRam
:param string scriptname: Filename of script. This is case-sensitive. :param string scriptname: Filename of script. This is case-sensitive.
:param string hostname/ip: Hostname or IP of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server. :param string hostname/ip: Hostname or IP of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server.
:RAM cost: 0.1 GB
Returns the amount of RAM required to run the specified script on the target server. Returns Returns the amount of RAM required to run the specified script on the target server. Returns
0 if the script does not exist. 0 if the script does not exist.
@ -928,6 +1004,7 @@ getHackTime
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:param number hackLvl: Optional hacking level for the calculation. Defaults to player's current hacking level :param number hackLvl: Optional hacking level for the calculation. Defaults to player's current hacking level
:RAM cost: 0.05 GB
Returns the amount of time in seconds it takes to execute the *hack()* Netscript function on the target server. Returns the amount of time in seconds it takes to execute the *hack()* Netscript function on the target server.
@ -941,6 +1018,7 @@ getGrowTime
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:param number hackLvl: Optional hacking level for the calculation. Defaults to player's current hacking level :param number hackLvl: Optional hacking level for the calculation. Defaults to player's current hacking level
:RAM cost: 0.05 GB
Returns the amount of time in seconds it takes to execute the *grow()* Netscript function on the target server. Returns the amount of time in seconds it takes to execute the *grow()* Netscript function on the target server.
@ -954,6 +1032,7 @@ getWeakenTime
:param string hostname/ip: Hostname or IP of target server :param string hostname/ip: Hostname or IP of target server
:param number hackLvl: Optional hacking level for the calculation. Defaults to player's current hacking level :param number hackLvl: Optional hacking level for the calculation. Defaults to player's current hacking level
:RAM cost: 0.05 GB
Returns the amount of time in seconds it takes to execute the *weaken()* Netscript function on the target server. Returns the amount of time in seconds it takes to execute the *weaken()* Netscript function on the target server.
@ -968,6 +1047,7 @@ getScriptIncome
:param string scriptname: Filename of script :param string scriptname: Filename of script
:param string hostname/ip: Server on which script is running :param string hostname/ip: Server on which script is running
:param args...: Arguments that the script is running with :param args...: Arguments that the script is running with
:RAM cost: 0.1 GB
Returns the amount of income the specified script generates while online (when the game is open, does not apply for offline income). Returns the amount of income the specified script generates while online (when the game is open, does not apply for offline income).
Remember that a script is uniquely identified by both its name and its arguments. So for example if you ran a script with the arguments Remember that a script is uniquely identified by both its name and its arguments. So for example if you ran a script with the arguments
@ -986,6 +1066,7 @@ getScriptExpGain
:param string scriptname: Filename of script :param string scriptname: Filename of script
:param string hostname/ip: Server on which script is running :param string hostname/ip: Server on which script is running
:param args...: Arguments that the script is running with :param args...: Arguments that the script is running with
:RAM cost: 0.1 GB
Returns the amount of hacking experience the specified script generates while online (when the game is open, does not apply for offline experience gains). Returns the amount of hacking experience the specified script generates while online (when the game is open, does not apply for offline experience gains).
Remember that a script is uniquely identified by both its name and its arguments. Remember that a script is uniquely identified by both its name and its arguments.
@ -997,6 +1078,8 @@ getTimeSinceLastAug
.. js:function:: getTimeSinceLastAug() .. js:function:: getTimeSinceLastAug()
:RAM cost: 0.05 GB
Returns the amount of time in milliseconds that have passed since you last installed Augmentations Returns the amount of time in milliseconds that have passed since you last installed Augmentations
sprintf sprintf
@ -1004,6 +1087,8 @@ sprintf
.. js:function:: sprintf() .. js:function:: sprintf()
:RAM cost: 0 GB
See `this link <https://github.com/alexei/sprintf.js>`_ for details. See `this link <https://github.com/alexei/sprintf.js>`_ for details.
vsprintf vsprintf
@ -1011,6 +1096,8 @@ vsprintf
.. js:function:: vsprintf() .. js:function:: vsprintf()
:RAM cost: 0 GB
See `this link <https://github.com/alexei/sprintf.js>`_ for details. See `this link <https://github.com/alexei/sprintf.js>`_ for details.
prompt prompt
@ -1019,6 +1106,7 @@ prompt
.. js:function:: prompt(txt) .. js:function:: prompt(txt)
:param string txt: Text to appear in the prompt dialog box :param string txt: Text to appear in the prompt dialog box
:RAM cost: 0 GB
Prompts the player with a dialog box with two options: "Yes" and "No". This function will return true if the player click "Yes" and Prompts the player with a dialog box with two options: "Yes" and "No". This function will return true if the player click "Yes" and
false if the player clicks "No". The script's execution is halted until the player selects one of the options. false if the player clicks "No". The script's execution is halted until the player selects one of the options.
@ -1031,6 +1119,7 @@ wget
:param string url: URL to pull data from :param string url: URL to pull data from
:param string target: Filename to write data to. Must be script or text file :param string target: Filename to write data to. Must be script or text file
:param string ip: Optional hostname/ip of server for target file. :param string ip: Optional hostname/ip of server for target file.
:RAM cost: 0 GB
Retrieves data from a URL and downloads it to a file on the specified server. The data can only Retrieves data from a URL and downloads it to a file on the specified server. The data can only
be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists, be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists,
@ -1057,4 +1146,6 @@ wget
getFavorToDonate getFavorToDonate
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
:RAM cost: 0.1 GB
Returns the amount of Faction favor required to be able to donate to a faction. Returns the amount of Faction favor required to be able to donate to a faction.

@ -0,0 +1,222 @@
Netscript Gang API
==================
Netscript provides the following API for interacting with the game's Gang mechanic.
The Gang API is **not** immediately available to the player and must be unlocked
later in the game
**WARNING: This page contains spoilers for the game**
The Gang API is unlocked in BitNode-2. Currently, BitNode-2 is the only location
where the Gang mechanic is accessible. This may change in the future
**Gang API functions must be accessed through the 'gang' namespace**
In :ref:`netscript1`::
gang.getMemberNames();
gang.recruitMember("Fry");
In :ref:`netscriptjs`::
ns.gang.getMemberNames();
ns.gang.recruitMember("Fry");
getMemberNames
--------------
.. js:function:: getMemberNames()
Get the names of all Gang members
:returns: An array of the names of all Gang members as strings
getGangInformation
------------------
.. js:function:: getGangInformation()
Get general information about the gang
:returns: An object with the gang information.
The object has the following structure::
{
faction: Name of faction that the gang belongs to ("Slum Snakes", etc.)
isHacking: Boolean indicating whether or not its a hacking gang
moneyGainRate: Money earned per second
power: Gang's power for territory warfare
respect: Gang's respect
respectGainRate: Respect earned per second
territory: Amount of territory held. Returned in decimal form, not percentage
territoryClashChance: Clash chance. Returned in decimal form, not percentage
wantedLevel: Gang's wanted level
wantedLevelGainRate: Wanted level gained/lost per second (negative for losses)
}
getMemberInformation
--------------------
.. js:function:: getMemberInformation(name)
:param string name: Name of member
Get stat and equipment-related information about a Gang Member
:returns: An object with the gang member information.
The object has the following structure::
{
agility: Agility stat
agilityEquipMult: Agility multiplier from equipment. Decimal form
agilityAscensionMult: Agility multiplier from ascension. Decimal form
augmentation: Array of names of all owned Augmentations
charisma: Charisma stat
charismaEquipMult: Charisma multiplier from equipment. Decimal form
charismaAscensionMult: Charisma multiplier from ascension. Decimal form
defense: Defense stat
defenseEquipMult: Defense multiplier from equipment. Decimal form
defenseAscensionMult: Defense multiplier from ascension. Decimal form
dexterity: Dexterity stat
dexterityEquipMult: Dexterity multiplier from equipment. Decimal form
dexterityAscensionMult: Dexterity multiplier from ascension. Decimal form
equipment: Array of names of all owned Non-Augmentation Equipment
hacking: Hacking stat
hackingEquipMult: Hacking multiplier from equipment. Decimal form
hackingAscensionMult: Hacking multiplier from ascension. Decimal form
strength: Strength stat
strengthEquipMult: Strength multiplier from equipment. Decimal form
strengthAscensionMult: Strength multiplier from ascension. Decimal form
task: Name of currently assigned task
}
canRecruitMember
----------------
.. js:function:: canRecruitMember()
:returns: Boolean indicating whether a member can currently be recruited
recruitMember
-------------
.. js:function:: recruitMember(name)
:param string name: Name of member to recruit
Attempt to recruit a new gang member.
Possible reasons for failure:
* Cannot currently recruit a new member
* There already exists a member with the specified name
:returns: True if the member was successfully recruited. False otherwise
getTaskNames
------------
.. js:function:: getTaskNames()
Get the name of all valid tasks that Gang members can be assigned to
:returns: Array of strings of all task names
setMemberTask
-------------
.. js:function:: setMemberTask(memberName, taskName)
:param string memberName: Name of Gang member to assign
:param string taskName: Task to assign
Attempts to assign the specified Gang Member to the specified task.
If an invalid task is specified, the Gang member will be set to idle ("Unassigned")
:returns: True if the Gang Member was successfully assigned to the task. False otherwise
getEquipmentNames
-----------------
.. js:function:: getEquipmentNames()
Get the name of all possible equipment/upgrades you can purchase for your
Gang Members. This includes Augmentations.
:returns: Array of strings of the names of all Equpiment/Augmentations
getEquipmentCost
----------------
.. js:function:: getEquipmentCost(equipName)
:param string equipName: Name of equipment
Get the amount of money it takes to purchase a piece of Equipment or an Augmentation.
If an invalid Equipment/Augmentation is specified, this function will return Infinity.
:returns: Cost to purchase the specified Equipment/Augmentation (number). Infinity
for invalid arguments
purchaseEquipment
-----------------
.. js:function:: purchaseEquipment(memberName, equipName)
:param string memberName: Name of Gang member to purchase the equipment for
:param string equipName: Name of Equipment/Augmentation to purchase
Attempt to purchase the specified Equipment/Augmentation for the specified
Gang member.
:returns: True if the equipment was successfully purchased. False otherwise
ascendMember
------------
.. js:function:: ascendMember(name)
:param string name: Name of member to ascend
Ascend the specified Gang Member.
:returns: An object with info about the ascension results.
The object has the following structure::
{
respect: Amount of respect lost from ascending
hack: Hacking multiplier gained from ascending. Decimal form
str: Strength multiplier gained from ascending. Decimal form
def: Defense multiplier gained from ascending. Decimal form
dex: Dexterity multiplier gained from ascending. Decimal form
agi: Agility multiplier gained from ascending. Decimal form
cha: Charisma multiplier gained from ascending. Decimal form
}
setTerritoryWarfare
-------------------
.. js:function:: setTerritoryWarfare(engage)
:param bool engage: Whether or not to engage in territory warfare
Set whether or not the gang should engage in territory warfare
getBonusTime
------------
.. js:function:: getBonusTime()
Returns the amount of accumulated "bonus time" (seconds) for the Gang mechanic.
"Bonus time" is accumulated when the game is offline or if the game is
inactive in the browser.
"Bonus time" makes the game progress faster, up to 10x the normal speed.
:returns: Bonus time for the Gang mechanic in seconds

@ -14,7 +14,7 @@ You can use the Singularity Functions in other BitNodes if and only if you have
Source-File 4 will open up additional Singularity Functions that you can use in other BitNodes. If your Source-File 4 is upgraded all the way to Source-File 4 will open up additional Singularity Functions that you can use in other BitNodes. If your Source-File 4 is upgraded all the way to
level 3, then you will be able to access all of the Singularity Functions. level 3, then you will be able to access all of the Singularity Functions.
Note that Singularity Functions require a lot of RAM outside of BitNode-4 (their RAM costs are multiplied by 10 if you are not in BitNode-4) Note that Singularity Functions require twice as much RAM outside of BitNode-4
universityCourse universityCourse
---------------- ----------------

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Bitburner</title> <title>Bitburner - development</title>
<link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="dist/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="dist/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="dist/favicon-16x16.png">
@ -109,7 +109,7 @@
<div id="script-editor-filename-wrapper"> <div id="script-editor-filename-wrapper">
<p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p> <p id="script-editor-filename-tag"> <strong style="background-color:#555;">Script name: </strong></p>
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/> <input id="script-editor-filename" type="text" maxlength="30" tabindex="1" />
</div> </div>
<div id="javascript-editor"></div> <div id="javascript-editor"></div>
@ -159,7 +159,7 @@
<fieldset> <fieldset>
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label> <label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"/> <input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr" />
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em> <em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
</fieldset> </fieldset>
</div> <!-- End script editor options panel --> </div> <!-- End script editor options panel -->
@ -170,7 +170,7 @@
<table id="terminal"> <table id="terminal">
<tr id="terminal-input"> <tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$ <td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/> <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" />
</td> </td>
</tr> </tr>
</table> </table>
@ -187,7 +187,7 @@
provides information about each script's production. The scripts are categorized by the hostname of the servers on which provides information about each script's production. The scripts are categorized by the hostname of the servers on which
they are running. </p> they are running. </p>
<p id="active-scripts-total-prod">Total online production of <p id="active-scripts-total-prod">Total online production of
Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br/> Active scripts: <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br />
Total online production since last Aug installation: <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span> Total online production since last Aug installation: <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span>
(<span class="money-gold"><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span>)</p> (<span class="money-gold"><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span>)</p>
<ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;"> <ul class="active-scripts-list" id="active-scripts-list" style="list-style: none;">
@ -201,19 +201,19 @@
The Hacknet is a global, decentralized network of machines. It is used by hackers all around The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced. fear of being traced.
<br/><br/> <br /><br />
Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its
resources to the Hacknet network. This allows you to take a small percentage of profits resources to the Hacknet network. This allows you to take a small percentage of profits
from hacks performed on the network. Essentially, you are renting out your Node's computing power. from hacks performed on the network. Essentially, you are renting out your Node's computing power.
<br/><br/> <br /><br />
Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded
in order to increase its computing power and thereby increase the profit you earn from it. in order to increase its computing power and thereby increase the profit you earn from it.
</p> </p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a> <a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br/> <br />
<div id="hacknet-nodes-money-multipliers-div"> <div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money"> <p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br/> <span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br />
<span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span> <span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span>
</p> </p>
<span id="hacknet-nodes-multipliers"> <span id="hacknet-nodes-multipliers">
@ -471,7 +471,8 @@
<!-- Tutorial content --> <!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container"> <div id="tutorial-container" class="generic-menupage-container">
<a id="tutorial-getting-started-link" class="a-link-button" href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a> <a id="tutorial-getting-started-link" class="a-link-button"
href="http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner" target="_blank"> Getting Started </a>
<a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a> <a id="tutorial-networking-link" class="a-link-button"> Servers & Networking </a>
<a id="tutorial-hacking-link" class="a-link-button"> Hacking </a> <a id="tutorial-hacking-link" class="a-link-button"> Hacking </a>
<a id="tutorial-scripts-link" class="a-link-button"> Scripts </a> <a id="tutorial-scripts-link" class="a-link-button"> Scripts </a>
@ -480,64 +481,13 @@
<a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a> <a id="tutorial-jobs-link" class="a-link-button"> Companies and Infiltration </a>
<a id="tutorial-factions-link" class="a-link-button"> Factions </a> <a id="tutorial-factions-link" class="a-link-button"> Factions </a>
<a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a> <a id="tutorial-augmentations-link" class="a-link-button"> Augmentations </a>
<a id="tutorial-shortcuts-link" class="a-link-button" href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a> <a id="tutorial-shortcuts-link" class="a-link-button"
href="https://bitburner.wikia.com/wiki/Shortcuts" target="_blank"> Keyboard Shortcuts </a>
<a id="tutorial-back-button" class="a-link-button"> Back </a> <a id="tutorial-back-button" class="a-link-button"> Back </a>
<p id="tutorial-text"> </p> <p id="tutorial-text"> </p>
</div> </div>
<!-- dev menu -->
<div id="dev-menu-container" class="generic-menupage-container">
<p id="dev-menu-text">If you see this menu you can pretty much break the game. It's recommended that you use this menu only to setup a save file appropriate to test a new feature or bug fix.</p>
<p id="dev-menu-text">Generic</p>
<a id="dev-need-money" class="a-link-button">Add $1000t</a>
<a id="dev-need-ram" class="a-link-button">Double home RAM</a>
<p id="dev-menu-text">Augmentation related: </p>
<!-- gets populated with the list of all augments -->
<select id="dev-menu-aug-dropdown" class="dropdown"></select>
<a id="dev-add-aug" class="a-link-button tooltip">Queue Augmentation<span class="tooltiptext">May require save + reload</span></a>
<input id="dev-sf-n" type="number" class="text-input" placeholder="SourceFile-N"><input id="dev-sf-lvl" type="number" class="text-input" placeholder="SourceFile-Lvl"><a id="dev-add-source-file" class="a-link-button tooltip"> Add/Remove source file <span class="tooltiptext">If Lvl == 0 the sf will be removed, calling it with another level will replace your current source file. You CAN set a source file higher than it's maximum level.</span></a>
<p id="dev-menu-text">Faction related: </p>
<select id="dev-menu-faction-dropdown" class="dropdown"></select>
<a id="dev-add-faction" class="a-link-button tooltip">Receive invite<span class="tooltiptext">May require save + reload</span></a>
<p id="dev-menu-text">Program related: </p>
<select id="dev-menu-connect-dropdown" class="dropdown"></select>
<a id="dev-connect" class="a-link-button tooltip">Connect<span class="tooltiptext">Connect to the target server.</span></a>
<select id="dev-menu-add-program-dropdown" class="dropdown"></select>
<a id="dev-add-program" class="a-link-button tooltip">Add Program<span class="tooltiptext">Add this program to the player home server, won't add the same program twice.</span></a>
<a id="dev-bit-flume" class="a-link-button tooltip">Trigger BitFlume<span class="tooltiptext">Quick escape to change BN, does not give SFs</span></a>
<p id="dev-menu-text">Server related: </p>
<a id="dev-open-all" class="a-link-button tooltip">NUKE + ports all servers<span class="tooltiptext">Opens all ports, nukes all servers, gains root access to everything (still need the appropriate hacking level)</span></a>
<a id="dev-min-security" class="a-link-button tooltip">minimize all servers security<span class="tooltiptext">All servers security will be set to their minimum security</span></a>
<a id="dev-max-money" class="a-link-button tooltip">maximize all servers money<span class="tooltiptext">Set all servers available money to maximum for that server</span></a>
<p id="dev-menu-text">Exp/stats related: </p>
<input id="dev-hacking-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-hacking" class="a-link-button tooltip">add hacking exp<span class="tooltiptext">Add that many hacking experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-strength-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-strength" class="a-link-button tooltip">add strength exp<span class="tooltiptext">Add that many strength experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-defense-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-defense" class="a-link-button tooltip">add defense exp<span class="tooltiptext">Add that many defense experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-dexterity-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-dexterity" class="a-link-button tooltip">add dexterity exp<span class="tooltiptext">Add that many dexterity experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-agility-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-agility" class="a-link-button tooltip">add agility exp<span class="tooltiptext">Add that many agility experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-charisma-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-charisma" class="a-link-button tooltip">add charisma exp<span class="tooltiptext">Add that many charisma experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-intelligence-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-intelligence" class="a-link-button tooltip">add intelligence exp<span class="tooltiptext">Add that many intelligence experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<a id="dev-enable-intelligence" class="a-link-button tooltip"> enable intelligence<span class="tooltiptext">Enables the intelligence stat</span></a>
<a id="dev-disable-intelligence" class="a-link-button tooltip"> disable intelligence<span class="tooltiptext">Disables the intelligence stat</span></a>
</div>
<!-- Location (visiting a location in World) --> <!-- Location (visiting a location in World) -->
<div id="location-container" class="generic-menupage-container"> <div id="location-container" class="generic-menupage-container">
<a id="location-return-to-world-button" class="a-link-button"> Return to World </a> <a id="location-return-to-world-button" class="a-link-button"> Return to World </a>
@ -623,7 +573,7 @@
<p id="location-slums-description"> <p id="location-slums-description">
You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and
other shadowy entities. The city's government and police have neglected this area for years... other shadowy entities. The city's government and police have neglected this area for years...
<br/><br/><br/> <br /><br /><br />
In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always
successful. Your chance at successfully committing a crime is determined by your stats. successful. Your chance at successfully committing a crime is determined by your stats.
</p> </p>
@ -670,7 +620,7 @@
<div id="stock-market-container" class="generic-menupage-container"> <div id="stock-market-container" class="generic-menupage-container">
<p> <p>
Welcome to the World Stock Exchange (WSE)! <br/><br/> Welcome to the World Stock Exchange (WSE)! <br /><br />
To begin trading, you must first purchase an account. WSE accounts will persist To begin trading, you must first purchase an account. WSE accounts will persist
after you 'reset' by installing Augmentations. after you 'reset' by installing Augmentations.
@ -683,7 +633,7 @@
TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE. TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE.
Purchasing access to the TIX API lets you write code to create your own algorithmic/automated Purchasing access to the TIX API lets you write code to create your own algorithmic/automated
trading strategies. trading strategies.
<br/><br/> <br /><br />
If you purchase access to the TIX API, you will retain that access even after If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations. you 'reset' by installing Augmentations.
</p> </p>
@ -693,7 +643,7 @@
<p> <p>
Four Sigma's (4S) Market Data Feed provides information about stocks Four Sigma's (4S) Market Data Feed provides information about stocks
that will help your trading strategies. that will help your trading strategies.
<br/><br/> <br /><br />
If you purchase access to 4S Market Data and/or the 4S TIX API, you will If you purchase access to 4S Market Data and/or the 4S TIX API, you will
retain that access even after you 'reset' by installing Augmentations. retain that access even after you 'reset' by installing Augmentations.
</p> </p>
@ -711,7 +661,7 @@
<a id="stock-market-mode" class="a-link-button tooltip"></a> <a id="stock-market-mode" class="a-link-button tooltip"></a>
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a> <a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a> <a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
<br/><br/> <br /><br />
<input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/> <input id="stock-market-watchlist-filter" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/>
<a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a> <a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a>
<ul id="stock-market-list" style="list-style:none;"> <ul id="stock-market-list" style="list-style:none;">
@ -741,7 +691,7 @@
<div id="yes-no-text-input-box-container" class="popup-box-container"> <div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content"> <div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"> </p> <p id="yes-no-text-input-box-text"> </p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30"/> <input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<button id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </button> <button id="yes-no-text-input-box-yes" class="popup-box-button"> Yes </button>
<button id="yes-no-text-input-box-no" class="popup-box-button"> No </button> <button id="yes-no-text-input-box-no" class="popup-box-button"> No </button>
</div> </div>
@ -753,7 +703,7 @@
<p id="faction-invitation-box-text"> </p> <p id="faction-invitation-box-text"> </p>
<p id="faction-invitation-box-message"> </p> <p id="faction-invitation-box-message"> </p>
<p id="faction-invitation-box-warning"> <p id="faction-invitation-box-warning">
Would you like to join? <br/> <br/> Would you like to join? <br /> <br />
Warning: Joining this faction may prevent you from joining other factions during this run! Warning: Joining this faction may prevent you from joining other factions during this run!
</p> </p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button> <button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
@ -766,8 +716,8 @@
<div id="infiltration-box-content" class="popup-box-content"> <div id="infiltration-box-content" class="popup-box-content">
<p id="infiltration-box-text"> </p> <p id="infiltration-box-text"> </p>
<button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br/><br/> <button id="infiltration-box-sell" class="a-link-button"> Sell on Black Market </button> <br /><br />
<select id="infiltration-faction-select"> </select> <br/> <select id="infiltration-faction-select"> </select> <br />
<button id="infiltration-box-faction" class="a-link-button"> Give to Faction for Reputation </button> <button id="infiltration-box-faction" class="a-link-button"> Give to Faction for Reputation </button>
</div> </div>
@ -853,7 +803,7 @@
<div id="game-options-content" class="game-options-box"> <div id="game-options-content" class="game-options-box">
<button id="game-options-close-button">&times;</button> <button id="game-options-close-button">&times;</button>
<h1> Game Options </h1> <h1> Game Options </h1>
<br/> <br />
<div id="game-options-left-panel"> <div id="game-options-left-panel">
<!-- Netscript execution time --> <!-- Netscript execution time -->
<fieldset> <fieldset>
@ -865,7 +815,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25"/> <input type ="range" max="100" min="10" step="1" name="settingsNSExecTimeRangeVal" id="settingsNSExecTimeRangeVal" value="25" />
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSExecTimeRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -879,7 +829,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50"/> <input type="range" max="100" min="20" step="1" name="settingsNSLogRangeVal" id="settingsNSLogRangeVal" value="50" />
<em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSLogRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -893,7 +843,7 @@
</span> </span>
</label> </label>
<input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50"/> <input type="range" max="100" min="20" step="1" name="settingsNSPortRangeVal" id="settingsNSPortRangeVal" value="50" />
<em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em> <em id="settingsNSPortRangeValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -905,7 +855,7 @@
</span> </span>
</label> </label>
<input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60"/> <input type="range" max="600" min="0" step="1" name="settingsAutosaveIntervalVal" id="settingsAutosaveIntervalVal" value="60" />
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em> <em id="settingsAutosaveIntervalValLabel" style="font-style: normal;"></em>
</fieldset> </fieldset>
@ -1017,7 +967,7 @@
<a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a> <a id="save-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Save Game </a>
<a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a> <a id="delete-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Delete Game </a>
<a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a> <a id="export-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Export Game </a>
<input type="file" id="import-game-file-selector" name="file"/> <input type="file" id="import-game-file-selector" name="file" />
<a id="import-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Import Game </a> <a id="import-game-link" class="a-link-button" style="display:inline-block;width:46%;"> Import Game </a>
<a id="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;"> <a id="debug-delete-scripts-link" class="a-link-button tooltip" style="display:block;width:46%;">
(DEBUG) Delete Active Scripts (DEBUG) Delete Active Scripts

@ -92,15 +92,23 @@ let NetscriptFunctions =
"installAugmentations|" + "installAugmentations|" +
// TIX API // TIX API
"getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|shortStock|sellShort|" + "getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|" +
"placeOrder|cancelOrder|" + "shortStock|sellShort|" +
"placeOrder|cancelOrder|getStockVolatility|getStockForecast|" +
// Hacknet Node API // Hacknet Node API
"hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" + "hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" +
"upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" + "upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" +
"getRamUpgradeCost|getCoreUpgradeCost|" + "getRamUpgradeCost|getCoreUpgradeCost|" +
// Bladeburner functions // Gang API
"gang|" +
"getMemberNames|getGangInformation|getMemberInformation|canRecruitMember|" +
"recruitMember|getTaskNames|setMemberTask|getEquipmentNames|" +
"getEquipmentCost|purchaseEquipment|ascendMember|setTerritoryWarfare|" +
"getBonusTime|" +
// Bladeburner API
"bladeburner|getContractNames|getOperationNames|getBlackOpNames|" + "bladeburner|getContractNames|getOperationNames|getBlackOpNames|" +
"getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" + "getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" +
"getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" + "getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" +

@ -152,7 +152,7 @@ function addActiveScriptsItem(workerscript) {
panel.appendChild(createElement("br")); panel.appendChild(createElement("br"));
panel.appendChild(createElement("span", { panel.appendChild(createElement("span", {
innerText: "Log", innerText: "Log",
class: "active-scripts-button", class: "accordion-button",
margin: "4px", margin: "4px",
padding: "4px", padding: "4px",
clickListener: () => { clickListener: () => {
@ -162,7 +162,7 @@ function addActiveScriptsItem(workerscript) {
})); }));
panel.appendChild(createElement("span", { panel.appendChild(createElement("span", {
innerText: "Kill Script", innerText: "Kill Script",
class: "active-scripts-button", class: "accordion-button",
margin: "4px", margin: "4px",
padding: "4px", padding: "4px",
clickListener: () => { clickListener: () => {

@ -1,8 +1,7 @@
import {BitNodeMultipliers} from "./BitNodeMultipliers"; import {BitNodeMultipliers} from "./BitNodeMultipliers";
import {CONSTANTS} from "./Constants"; import {CONSTANTS} from "./Constants";
import {Engine} from "./engine"; import {Engine} from "./engine";
import {Factions, getNextNeurofluxLevel, import {Factions, factionExists} from "./Faction";
factionExists} from "./Faction";
import {hasBladeburnerSF} from "./NetscriptFunctions"; import {hasBladeburnerSF} from "./NetscriptFunctions";
import {addWorkerScript} from "./NetscriptWorker"; import {addWorkerScript} from "./NetscriptWorker";
import {Player} from "./Player"; import {Player} from "./Player";
@ -1029,9 +1028,25 @@ function initAugmentations() {
"This is a special augmentation because it can be leveled up infinitely. Each level of this augmentation " + "This is a special augmentation because it can be leveled up infinitely. Each level of this augmentation " +
"increases ALL of the player's multipliers by 1%." "increases ALL of the player's multipliers by 1%."
}); });
var nextLevel = getNextNeurofluxLevel();
NeuroFluxGovernor.level = nextLevel - 1; // Set the Augmentation's level to the currently-installed level
mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, NeuroFluxGovernor.level); let currLevel = 0;
for (let i = 0; i < Player.augmentations.length; ++i) {
if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
currLevel = Player.augmentations[i].level;
}
}
NeuroFluxGovernor.level = currLevel;
// To set the price/rep req of the NeuroFlux, we have to take into account NeuroFlux
// levels that are purchased but not yet installed
let nextLevel = currLevel;
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
if (Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
++nextLevel;
}
}
mult = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel);
NeuroFluxGovernor.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost; NeuroFluxGovernor.baseRepRequirement = 500 * mult * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
NeuroFluxGovernor.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost; NeuroFluxGovernor.baseCost = 750e3 * mult * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
if (augmentationExists(AugmentationNames.NeuroFluxGovernor)) { if (augmentationExists(AugmentationNames.NeuroFluxGovernor)) {
@ -2380,7 +2395,7 @@ function applyAugmentation(aug, reapply=false) {
return; return;
} }
if (aug.name == AugmentationNames.NeuroFluxGovernor) { if (aug.name === AugmentationNames.NeuroFluxGovernor) {
for (var i = 0; i < Player.augmentations.length; ++i) { for (var i = 0; i < Player.augmentations.length; ++i) {
if (Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor) { if (Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
//Already have this aug, just upgrade the level //Already have this aug, just upgrade the level

@ -28,7 +28,9 @@ function initBitNodes() {
"left behind from the collapse of Western government in the 2050's. As society and civlization broke down, " + "left behind from the collapse of Western government in the 2050's. As society and civlization broke down, " +
"people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " + "people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " +
"factions quickly rose to the top of the modern world.<br><br>" + "factions quickly rose to the top of the modern world.<br><br>" +
"In this BitNode:<br><br>The maximum amount of money available on a server is significantly decreased<br>" + "In this BitNode:<br><br>" +
"Your hacking level is reduced by 25%<br>" +
"The growth rate and maximum amount of money available on servers is significantly decreased<br>" +
"The amount of money gained from crimes and Infiltration is tripled<br>" + "The amount of money gained from crimes and Infiltration is tripled<br>" +
"Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, " + "Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, " +
"NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs " + "NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs " +
@ -214,6 +216,8 @@ function initBitNodeMultipliers() {
case 1: //Source Genesis (every multiplier is 1) case 1: //Source Genesis (every multiplier is 1)
break; break;
case 2: //Rise of the Underworld case 2: //Rise of the Underworld
BitNodeMultipliers.HackingLevelMultiplier = 0.75;
BitNodeMultipliers.ServerGrowthRate = 0.75;
BitNodeMultipliers.ServerMaxMoney = 0.2; BitNodeMultipliers.ServerMaxMoney = 0.2;
BitNodeMultipliers.ServerStartingMoney = 0.4; BitNodeMultipliers.ServerStartingMoney = 0.4;
BitNodeMultipliers.CrimeMoney = 3; BitNodeMultipliers.CrimeMoney = 3;

@ -1768,8 +1768,9 @@ Bladeburner.prototype.createOverviewContent = function() {
}); });
DomElems.overviewStaminaHelpTip = createElement("div", { DomElems.overviewStaminaHelpTip = createElement("div", {
innerText:"?", class:"help-tip", class:"help-tip",
clickListener:()=>{ innerText:"?",
clickListener: ()=> {
dialogBoxCreate("Performing actions will use up your stamina.<br><br>" + dialogBoxCreate("Performing actions will use up your stamina.<br><br>" +
"Your max stamina is determined primarily by your agility stat.<br><br>" + "Your max stamina is determined primarily by your agility stat.<br><br>" +
"Your stamina gain rate is determined by both your agility and your " + "Your stamina gain rate is determined by both your agility and your " +
@ -1781,7 +1782,7 @@ Bladeburner.prototype.createOverviewContent = function() {
"your success rate would be multipled by 85% (100 - 15).<br><br>" + "your success rate would be multipled by 85% (100 - 15).<br><br>" +
"Your max stamina and stamina gain rate can also be increased by " + "Your max stamina and stamina gain rate can also be increased by " +
"training, or through skills and Augmentation upgrades."); "training, or through skills and Augmentation upgrades.");
} },
}); });
DomElems.overviewGen1 = createElement("p", { DomElems.overviewGen1 = createElement("p", {
@ -3335,6 +3336,38 @@ Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript
return false; return false;
} }
// Special logic for Black Ops
if (actionId.type === ActionTypes["BlackOp"]) {
// Can't start a BlackOp if you don't have the required rank
let action = this.getActionObject(actionId);
if (action.reqdRank > this.rank) {
workerScript.log(`Failed to start Black Op ${actionId.name} due to insufficient rank`);
return false;
}
// Can't start a BlackOp if you haven't done the one before it
var blackops = [];
for (const nm in BlackOperations) {
if (BlackOperations.hasOwnProperty(nm)) {
blackops.push(nm);
}
}
blackops.sort(function(a, b) {
return (BlackOperations[a].reqdRank - BlackOperations[b].reqdRank); // Sort black ops in intended order
});
let i = blackops.indexOf(actionId.name);
if (i === -1) {
workerScript.log("ERROR: Invalid Black Operation name passed into bladeburner.startAction(). Note that this name is case-sensitive & whitespace-sensitive");
return false;
}
if (i > 0 && this.blackops[blackops[i-1]] == null) {
workerScript.log(`ERROR: Cannot attempt Black Operation ${actionId.name} because you have not done the preceding one`);
return false;
}
}
try { try {
this.startAction(actionId); this.startAction(actionId);
if (workerScript.shouldLog("startAction")) { if (workerScript.shouldLog("startAction")) {
@ -3436,9 +3469,14 @@ Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name,
switch (actionId.type) { switch (actionId.type) {
case ActionTypes["Contract"]: case ActionTypes["Contract"]:
case ActionTypes["Operation"]: case ActionTypes["Operation"]:
return actionObj.count;
case ActionTypes["BlackOp"]: case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]: case ActionTypes["BlackOperation"]:
return actionObj.count; if (this.blackops[name] != null) {
return 0;
} else {
return 1;
}
case ActionTypes["Training"]: case ActionTypes["Training"]:
case ActionTypes["Field Analysis"]: case ActionTypes["Field Analysis"]:
case ActionTypes["FieldAnalysis"]: case ActionTypes["FieldAnalysis"]:

@ -48,7 +48,7 @@ let CONSTANTS = {
/* Netscript Constants */ /* Netscript Constants */
//RAM Costs for different commands //RAM Costs for different commands
ScriptBaseRamCost: 1.6, ScriptBaseRamCost: 1.6,
ScriptDomRamCost: 100, ScriptDomRamCost: 25,
ScriptWhileRamCost: 0, ScriptWhileRamCost: 0,
ScriptForRamCost: 0, ScriptForRamCost: 0,
ScriptIfRamCost: 0, ScriptIfRamCost: 0,
@ -91,6 +91,10 @@ let CONSTANTS = {
ScriptSingularityFn2RamCost: 2, ScriptSingularityFn2RamCost: 2,
ScriptSingularityFn3RamCost: 3, ScriptSingularityFn3RamCost: 3,
ScriptSingularityFnRamMult: 2, // Multiplier for RAM cost outside of BN-4
ScriptGangApiBaseRamCost: 4,
ScriptBladeburnerApiBaseRamCost: 4, ScriptBladeburnerApiBaseRamCost: 4,
NumNetscriptPorts: 20, NumNetscriptPorts: 20,
@ -191,13 +195,6 @@ let CONSTANTS = {
"-Miscellaneous Nodes slowly raise their defense over time<br><br>" + "-Miscellaneous Nodes slowly raise their defense over time<br><br>" +
"-Nodes slowly regenerate health over time.", "-Nodes slowly regenerate health over time.",
/* Gang constant */
GangRespectToReputationRatio: 2, //Respect is divided by this to get rep gain
MaximumGangMembers: 20,
GangRecruitCostMultiplier: 2,
GangTerritoryUpdateTimer: 150,
/* Time Constants */ /* Time Constants */
MillisecondsPer20Hours: 72000000, MillisecondsPer20Hours: 72000000,
GameCyclesPer20Hours: 72000000 / 200, GameCyclesPer20Hours: 72000000 / 200,
@ -506,11 +503,34 @@ let CONSTANTS = {
LatestUpdate: LatestUpdate:
` `
v0.40.5 v0.41.0
* Added codingcontract.getContractType() Netscript function * WARNING: In NetscriptJS, defining a function called print() is no longer possible
* Bug Fix: codingcontract.getData() Netscript function now returns arrays by value rather than reference * Gang Mechanic Changes (BitNode-2):
* Bug Fix: Decreased highest possible data value for 'Find Largest Prime Factor' Coding Contract (to avoid hangs when solving it) *** Added a Gang Netscript API
* Bug Fix: Fixed a bug that caused game to freeze during Coding Contract generation *** Added new 'ascension' mechanic for Gang Members
*** The first three gang members are now 'free' (can be recruited instantly)
*** Maximum number of increased Gang Members increased from 20 to 40
*** Changed the formula for calculating respect needed to recruit the next gang member
*** Added a new category of upgrades for Gang Members: Augmentations
*** Non-Augmentation Gang member upgrades are now significantly weaker
*** Reputation for your Gang faction can no longer be gained through Infiltration
*** Re-worked the territory 'warfare' mechanic so that player can choose when to engage in it
*** Gang Members can now be killed during territory 'warfare'
*** Changed BitNode-2 Multipliers to make hacking slightly less profitable
*** Gang Member Equipment + Upgrades now get cheaper as your gang grows in power and respect
*** The effects of Source-File 2 are now slightly more powerful
* RAM Cost of accessing the global document object lowered from 100 GB to 25 GB
* RAM Cost to use Singularity Functions outside of BitNode-4 lowered by 75%. They now only cost twice as much as they do in BitNode-4
* b1t_flum3.exe now takes significantly less time to create
* Improved number formatting for Player 'work' actions (including crimes, etc.). These numbers should also adhere to locale settings now (by Kline-)
* Bug Fix: Calling print() in NetscriptJS no longer brings up the print dialog
* Bug Fix: Fixed a bug that sometimes caused a blank black screen when destroying/resetting/switching BitNodes
* Bug Fix: Netscript calls that throw errors will now no longer cause the 'concurrent calls' error if they are caught in the script. i.e. try/catch should now work properly in scripts
* Bug Fix: Fixed a bug where sometimes the NeuroFlux Governor Augmentation level would be incorrectly calculated when the game was loaded
* Bug Fix: Fixed a bug where calling the scp() Netscript function with invalid hostname/ips would throw an unclear error message
* Bug Fix: Bladeburner API function getActionCountRemaining() should now work properly for BlackOps
* Bug Fix: Black Ops can no longer be attempted out-of-order or without the required rank via Bladeburner API
* RAM cost for basic Netscript functions added to documentation (by CBJamo)
` `
} }

@ -86,7 +86,7 @@ const Programs = {
level: 1, level: 1,
tooltip:"This program creates a portal to the BitNode Nexus (allows you to restart and switch BitNodes)", tooltip:"This program creates a portal to the BitNode Nexus (allows you to restart and switch BitNodes)",
req: function() {return Player.sourceFiles.length > 0 && Player.hacking_skill >= 1}, req: function() {return Player.sourceFiles.length > 0 && Player.hacking_skill >= 1},
time: CONSTANTS.MillisecondsPerFiveMinutes / 5, time: CONSTANTS.MillisecondsPerFiveMinutes / 20,
}), }),
// special because you can't create it. // special because you can't create it.
Flight: new Program("fl1ght.exe"), Flight: new Program("fl1ght.exe"),

432
src/DevMenu.js Normal file

@ -0,0 +1,432 @@
import {AugmentationNames} from "./Augmentations"
import {Programs} from "./CreateProgram"
import {Factions} from "./Faction";
import {Player} from "./Player";
import {AllServers} from "./Server";
import {hackWorldDaemon} from "./RedPill";
import {Terminal} from "./Terminal";
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
import {createElement} from "../utils/uiHelpers/createElement";
import {removeElementById} from "../utils/uiHelpers/removeElementById";
const devMenuContainerId = "dev-menu-container";
export function createDevMenu() {
if (process.env.NODE_ENV !== "development") {
throw new Error("Cannot create Dev Menu because you are not in a dev build");
}
const devMenuText = createElement("h1", {
display: "block",
innerText: "Development Menu - Only meant to be used for testing/debugging",
});
// Generic
const genericHeader = createElement("h2", {
display: "block",
innerText: "Generic"
});
const addMoney = createElement("button", {
class: "std-button",
clickListener: () => {
Player.gainMoney(1e15);
},
display: "block",
innerText: "Add $1000t",
});
const addRam = createElement("button", {
class: "std-button",
clickListener: () => {
Player.getHomeComputer().maxRam *= 2;
},
display: "block",
innerText: "Double Home Computer RAM",
});
const triggerBitflume = createElement("button", {
class: "std-button",
clickListener: () => {
hackWorldDaemon(Player.bitNodeN, true);
},
innerText: "Trigger BitFlume",
});
const destroyCurrentBitnode = createElement("button", {
class: "std-button",
clickListener: () => {
hackWorldDaemon(Player.bitNodeN);
},
innerText: "Destroy Current BitNode",
tooltip: "Will grant Source-File for the BitNode",
})
// Experience / stats
const statsHeader = createElement("h2", {
display: "block",
innerText: "Experience/Stats"
});
const statsHackingExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- hacking exp",
type: "number",
});
const statsHackingExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsHackingExpInput.value);
Player.gainHackingExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Hacking Exp",
});
const statsStrengthExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- strength exp",
type: "number",
});
const statsStrengthExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsStrengthExpInput.value);
Player.gainStrengthExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Strength Exp",
});
const statsDefenseExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- defense exp",
type: "number",
});
const statsDefenseExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsDefenseExpInput.value);
Player.gainDefenseExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Defense Exp",
});
const statsDexterityExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- dexterity exp",
type: "number",
});
const statsDexterityExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsDexterityExpInput.value);
Player.gainDexterityExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Dexterity Exp",
});
const statsAgilityExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- agility exp",
type: "number",
});
const statsAgilityExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsAgilityExpInput.value);
Player.gainAgilityExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Agility Exp",
});
const statsCharismaExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- charisma exp",
type: "number",
});
const statsCharismaExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsCharismaExpInput.value);
Player.gainCharismaExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Charisma Exp",
});
const statsIntelligenceExpInput = createElement("input", {
class: "text-input",
margin: "5px",
placeholder: "+/- intelligence exp",
type: "number",
});
const statsIntelligenceExpButton = createElement("button", {
class: "std-button",
clickListener: () => {
const exp = parseInt(statsIntelligenceExpInput.value);
Player.gainIntelligenceExp(exp);
Player.updateSkillLevels();
},
innerText: "Add Intelligence Exp",
});
const statsEnableIntelligenceButton = createElement("button", {
class: "std-button",
clickListener: () => {
Player.intelligence = 1;
},
innerText: "Enable Intelligence"
});
const statsDisableIntelligenceButton = createElement("button", {
class: "std-button",
clickListener: () => {
Player.intelligence = 0;
},
innerText: "Disable Intelligence"
});
// Factions
const factionsHeader = createElement("h2", {innerText: "Factions"});
const factionsDropdown = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const i in Factions) {
factionsDropdown.options[factionsDropdown.options.length] = new Option(Factions[i].name, Factions[i].name);
}
const factionsAddButton = createElement("button", {
class: "std-button",
clickListener: () => {
const facName = factionsDropdown.options[factionsDropdown.selectedIndex].value;
Player.receiveInvite(facName);
},
innerText: "Receive Invite to Faction",
});
// Augmentations / Source Files
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
const augmentationsDropdown = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const i in AugmentationNames) {
const augName = AugmentationNames[i];
augmentationsDropdown.options[augmentationsDropdown.options.length] = new Option(augName, augName);
}
const augmentationsQueueButton = createElement("button", {
class: "std-button",
clickListener: () => {
Player.queueAugmentation(augmentationsDropdown.options[augmentationsDropdown.selectedIndex].value);
},
innerText: "Queue Augmentation",
})
// Programs
const programsHeader = createElement("h2", {innerText: "Programs"});
const programsAddDropdown = createElement("select", {
class: "dropdown",
margin: "5px",
});
for (const i in Programs) {
const progName = Programs[i].name;
programsAddDropdown.options[programsAddDropdown.options.length] = new Option(progName, progName);
}
const programsAddButton = createElement("button", {
class: "std-button",
clickListener: () => {
const program = programsAddDropdown.options[programsAddDropdown.selectedIndex].value;
if(!Player.hasProgram(program)) {
Player.getHomeComputer().programs.push(program);
}
},
innerText: "Add Program",
})
// Servers
const serversHeader = createElement("h2", {innerText: "Servers"});
const serversOpenAll = createElement("button", {
class: "std-button",
clickListener: () => {
for (const i in AllServers) {
AllServers[i].hasAdminRights = true;
AllServers[i].sshPortOpen = true;
AllServers[i].ftpPortOpen = true;
AllServers[i].smtpPortOpen = true;
AllServers[i].httpPortOpen = true;
AllServers[i].sqlPortOpen = true;
AllServers[i].openPortCount = 5;
}
},
display: "block",
innerText: "Get Admin Rights to all servers",
});
const serversMinSecurityAll = createElement("button", {
class: "std-button",
clickListener: () => {
for (const i in AllServers) {
AllServers[i].hackDifficulty = AllServers[i].minDifficulty;
}
},
display: "block",
innerText: "Set all servers to min security",
});
const serversMaxMoneyAll = createElement("button", {
class: "std-button",
clickListener: () => {
for (const i in AllServers) {
AllServers[i].moneyAvailable = AllServers[i].moneyMax;
}
},
display: "block",
innerText: "Set all servers to max money",
});
const serversConnectToDropdown = createElement("select", {class: "dropdown"});
for (const i in AllServers) {
const hn = AllServers[i].hostname;
serversConnectToDropdown.options[serversConnectToDropdown.options.length] = new Option(hn, hn);
}
const serversConnectToButton = createElement("button", {
class: "std-button",
clickListener: () => {
const host = serversConnectToDropdown.options[serversConnectToDropdown.selectedIndex].value;
Terminal.connectToServer(host);
},
innerText: "Connect to server",
});
// Bladeburner
const bladeburnerHeader = createElement("h2", {innerText: "Bladeburner"});
const bladeburnerGainRankInput = createElement("input", {
class: "text-input",
placeholder: "Rank to gain (or negative to lose rank)",
type: "number",
});
const bladeburnerGainRankButton = createElement("button", {
class: "std-button",
clickListener: () => {
try {
const rank = parseInt(bladeburnerGainRankInput.value);
Player.bladeburner.changeRank(rank);
} catch(e) {
exceptionAlert(`Failed to change Bladeburner Rank in dev menu: ${e}`);
}
},
innerText: "Gain Bladeburner Rank",
});
// Gang
const gangHeader = createElement("h2", {innerText: "Gang"});
const gangStoredCyclesInput = createElement("input", {
class: "text-input",
placeholder: "# Cycles to add",
type: "number",
});
const gangAddStoredCycles = createElement("button", {
class: "std-button",
clickListener: () => {
try {
const cycles = parseInt(gangStoredCyclesInput.value);
Player.gang.storedCycles += cycles;
} catch(e) {
exceptionAlert(`Failed to add stored cycles to gang mechanic: ${e}`);
}
},
innerText: "Add cycles to Gang mechanic",
})
// Add everything to container, then append to main menu
const devMenuContainer = createElement("div", {
class: "generic-menupage-container",
id: devMenuContainerId,
});
devMenuContainer.appendChild(devMenuText);
devMenuContainer.appendChild(genericHeader);
devMenuContainer.appendChild(addMoney);
devMenuContainer.appendChild(addRam);
devMenuContainer.appendChild(triggerBitflume);
devMenuContainer.appendChild(destroyCurrentBitnode);
devMenuContainer.appendChild(statsHeader);
devMenuContainer.appendChild(statsHackingExpInput);
devMenuContainer.appendChild(statsHackingExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsStrengthExpInput);
devMenuContainer.appendChild(statsStrengthExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsDefenseExpInput);
devMenuContainer.appendChild(statsDefenseExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsDexterityExpInput);
devMenuContainer.appendChild(statsDexterityExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsAgilityExpInput);
devMenuContainer.appendChild(statsAgilityExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsCharismaExpInput);
devMenuContainer.appendChild(statsCharismaExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsIntelligenceExpInput);
devMenuContainer.appendChild(statsIntelligenceExpButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(statsEnableIntelligenceButton);
devMenuContainer.appendChild(statsDisableIntelligenceButton);
devMenuContainer.appendChild(factionsHeader);
devMenuContainer.appendChild(factionsDropdown);
devMenuContainer.appendChild(factionsAddButton);
devMenuContainer.appendChild(augmentationsHeader);
devMenuContainer.appendChild(augmentationsDropdown);
devMenuContainer.appendChild(augmentationsQueueButton);
devMenuContainer.appendChild(programsHeader);
devMenuContainer.appendChild(programsAddDropdown);
devMenuContainer.appendChild(programsAddButton);
devMenuContainer.appendChild(serversHeader);
devMenuContainer.appendChild(serversOpenAll);
devMenuContainer.appendChild(serversMinSecurityAll);
devMenuContainer.appendChild(serversMaxMoneyAll);
devMenuContainer.appendChild(serversConnectToDropdown);
devMenuContainer.appendChild(serversConnectToButton);
devMenuContainer.appendChild(bladeburnerHeader);
devMenuContainer.appendChild(bladeburnerGainRankInput);
devMenuContainer.appendChild(bladeburnerGainRankButton);
devMenuContainer.appendChild(createElement("br"));
devMenuContainer.appendChild(gangHeader);
devMenuContainer.appendChild(gangStoredCyclesInput);
devMenuContainer.appendChild(gangAddStoredCycles);
devMenuContainer.appendChild(createElement("br"));
const entireGameContainer = document.getElementById("entire-game-container");
if (entireGameContainer == null) {
throw new Error("Could not find entire-game-container DOM element");
}
entireGameContainer.appendChild(devMenuContainer);
}
export function closeDevMenu() {
removeElementById(devMenuContainerId);
}

@ -734,27 +734,21 @@ function purchaseAugmentation(aug, fac, sing=false) {
} }
function getNextNeurofluxLevel() { function getNextNeurofluxLevel() {
var aug = Augmentations[AugmentationNames.NeuroFluxGovernor]; // Get current Neuroflux level based on Player's augmentations
if (aug == null) { let currLevel = 0;
for (var i = 0; i < Player.augmentations.length; ++i) { for (var i = 0; i < Player.augmentations.length; ++i) {
if (Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor) { if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
aug = Player.augmentations[i]; currLevel = Player.augmentations[i].level;
} }
} }
if (aug == null) {
console.log("WARNING: Could not find NeuroFlux Governor aug. This is OK if " + // Account for purchased but uninstalled Augmentations
"it happens during the loading/initialization of the game, but probably " +
"indicates something seriously wrong at other times");
return 1;
}
}
var nextLevel = aug.level + 1;
for (var i = 0; i < Player.queuedAugmentations.length; ++i) { for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) { if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
++nextLevel; ++currLevel;
} }
} }
return nextLevel; return currLevel + 1;
} }
function processPassiveFactionRepGain(numCycles) { function processPassiveFactionRepGain(numCycles) {

File diff suppressed because it is too large Load Diff

@ -28,10 +28,6 @@ import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoTxtInpBoxClose} from "../utils/YesNoBox"; yesNoTxtInpBoxClose} from "../utils/YesNoBox";
function displayLocationContent() { function displayLocationContent() {
if (Engine.Debug) {
console.log("displayLocationContent() called with location " + Player.location)
}
var returnToWorld = document.getElementById("location-return-to-world-button"); var returnToWorld = document.getElementById("location-return-to-world-button");
var locationName = document.getElementById("location-name"); var locationName = document.getElementById("location-name");
@ -1811,7 +1807,7 @@ function initLocationButtons() {
yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel"; yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel";
yesBtn.addEventListener("click", ()=>{ yesBtn.addEventListener("click", ()=>{
if (Player.money.lt(cost)) { if (Player.money.lt(cost)) {
dialogBoxCreate("You do not have enough mone to purchase an additional CPU Core for your home computer!"); dialogBoxCreate("You do not have enough money to purchase an additional CPU Core for your home computer!");
} else { } else {
Player.loseMoney(cost); Player.loseMoney(cost);
Player.getHomeComputer().cpuCores++; Player.getHomeComputer().cpuCores++;

@ -9,7 +9,7 @@ function unknownBladeburnerActionErrorMessage(functionName, actionType, actionNa
} }
function unknownBladeburnerExceptionMessage(functionName, err) { function unknownBladeburnerExceptionMessage(functionName, err) {
return `Bladeburner.${functionName}() failed with exception: ` + err; return `bladeburner.${functionName}() failed with exception: ` + err;
} }
function checkBladeburnerAccess(workerScript, functionName) { function checkBladeburnerAccess(workerScript, functionName) {

@ -46,7 +46,8 @@ import {TextFile, getTextFile, createTextFile} from "./TextFile";
import {unknownBladeburnerActionErrorMessage, import {unknownBladeburnerActionErrorMessage,
unknownBladeburnerExceptionMessage, unknownBladeburnerExceptionMessage,
checkBladeburnerAccess} from "./NetscriptBladeburner.js"; checkBladeburnerAccess} from "./NetscriptBladeburner";
import * as nsGang from "./NetscriptGang";
import {WorkerScript, workerScripts, import {WorkerScript, workerScripts,
killWorkerScript, NetscriptPorts} from "./NetscriptWorker"; killWorkerScript, NetscriptPorts} from "./NetscriptWorker";
import {makeRuntimeRejectMsg, netscriptDelay, import {makeRuntimeRejectMsg, netscriptDelay,
@ -882,12 +883,12 @@ function NetscriptFunctions(workerScript) {
} }
destServer = getServer(ip2); destServer = getServer(ip2);
if (destServer == null) { if (destServer == null) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Invalid hostname/ip passed into scp() command: " + ip); throw makeRuntimeRejectMsg(workerScript, `ERROR: Invalid hostname/ip passed into scp() command: ${ip2}`);
} }
currServ = getServer(ip1); currServ = getServer(ip1);
if (currServ == null) { if (currServ == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find server ip for this script. This is a bug please contact game developer"); throw makeRuntimeRejectMsg(workerScript, `ERROR: Invalid hostname/ip passed into scp() command: ${ip1}`);
} }
} else if (arguments.length === 2) { //scriptname, destination } else if (arguments.length === 2) { //scriptname, destination
if (scriptname === undefined || ip1 === undefined) { if (scriptname === undefined || ip1 === undefined) {
@ -895,7 +896,7 @@ function NetscriptFunctions(workerScript) {
} }
destServer = getServer(ip1); destServer = getServer(ip1);
if (destServer == null) { if (destServer == null) {
throw makeRuntimeRejectMsg(workerScript, "ERROR: Invalid hostname/ip passed into scp() command: " + ip); throw makeRuntimeRejectMsg(workerScript, `ERROR: Invalid hostname/ip passed into scp() command: ${ip1}`);
} }
currServ = getServer(workerScript.serverIp); currServ = getServer(workerScript.serverIp);
@ -1101,7 +1102,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeRejectMsg(workerScript, "ps() failed. Invalid IP or hostname passed in: " + ip); throw makeRuntimeRejectMsg(workerScript, "ps() failed. Invalid IP or hostname passed in: " + ip);
} }
const processes = []; const processes = [];
for(const i in server.runningScripts) { for (const i in server.runningScripts) {
const script = server.runningScripts[i]; const script = server.runningScripts[i];
processes.push({filename:script.filename, threads: script.threads, args: script.args.slice()}) processes.push({filename:script.filename, threads: script.threads, args: script.args.slice()})
} }
@ -2313,7 +2314,7 @@ function NetscriptFunctions(workerScript) {
/* Singularity Functions */ /* Singularity Functions */
universityCourse : function(universityName, className) { universityCourse : function(universityName, className) {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("universityCourse", ramCost); return updateStaticRam("universityCourse", ramCost);
} }
@ -2402,7 +2403,7 @@ function NetscriptFunctions(workerScript) {
gymWorkout : function(gymName, stat) { gymWorkout : function(gymName, stat) {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("gymWorkout", ramCost); return updateStaticRam("gymWorkout", ramCost);
} }
@ -2504,7 +2505,7 @@ function NetscriptFunctions(workerScript) {
travelToCity(cityname) { travelToCity(cityname) {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("travelToCity", ramCost); return updateStaticRam("travelToCity", ramCost);
} }
@ -2541,7 +2542,7 @@ function NetscriptFunctions(workerScript) {
purchaseTor() { purchaseTor() {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("purchaseTor", ramCost); return updateStaticRam("purchaseTor", ramCost);
} }
@ -2585,7 +2586,7 @@ function NetscriptFunctions(workerScript) {
}, },
purchaseProgram(programName) { purchaseProgram(programName) {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("purchaseProgram", ramCost); return updateStaticRam("purchaseProgram", ramCost);
} }
@ -2637,7 +2638,7 @@ function NetscriptFunctions(workerScript) {
}, },
getStats : function() { getStats : function() {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 4; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 4;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getStats", ramCost); return updateStaticRam("getStats", ramCost);
} }
@ -2661,7 +2662,7 @@ function NetscriptFunctions(workerScript) {
}, },
getCharacterInformation : function() { getCharacterInformation : function() {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 4; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 4;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getCharacterInformation", ramCost); return updateStaticRam("getCharacterInformation", ramCost);
} }
@ -2697,7 +2698,7 @@ function NetscriptFunctions(workerScript) {
}, },
isBusy : function() { isBusy : function() {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 4; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 4;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("isBusy", ramCost); return updateStaticRam("isBusy", ramCost);
} }
@ -2712,7 +2713,7 @@ function NetscriptFunctions(workerScript) {
}, },
stopAction : function() { stopAction : function() {
var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 2; var ramCost = CONSTANTS.ScriptSingularityFn1RamCost / 2;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("stopAction", ramCost); return updateStaticRam("stopAction", ramCost);
} }
@ -2734,7 +2735,7 @@ function NetscriptFunctions(workerScript) {
}, },
upgradeHomeRam : function() { upgradeHomeRam : function() {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("upgradeHomeRam", ramCost); return updateStaticRam("upgradeHomeRam", ramCost);
} }
@ -2766,7 +2767,7 @@ function NetscriptFunctions(workerScript) {
}, },
getUpgradeHomeRamCost : function() { getUpgradeHomeRamCost : function() {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 2; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 2;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getUpgradeHomeRamCost", ramCost); return updateStaticRam("getUpgradeHomeRamCost", ramCost);
} }
@ -2782,7 +2783,7 @@ function NetscriptFunctions(workerScript) {
}, },
workForCompany : function() { workForCompany : function() {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("workForCompany", ramCost); return updateStaticRam("workForCompany", ramCost);
} }
@ -2823,7 +2824,7 @@ function NetscriptFunctions(workerScript) {
}, },
applyToCompany : function(companyName, field) { applyToCompany : function(companyName, field) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("applyToCompany", ramCost); return updateStaticRam("applyToCompany", ramCost);
} }
@ -2904,7 +2905,7 @@ function NetscriptFunctions(workerScript) {
}, },
getCompanyRep : function(companyName) { getCompanyRep : function(companyName) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 2; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 2;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getCompanyRep", ramCost); return updateStaticRam("getCompanyRep", ramCost);
} }
@ -2925,7 +2926,7 @@ function NetscriptFunctions(workerScript) {
}, },
getCompanyFavor : function(companyName) { getCompanyFavor : function(companyName) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getCompanyFavor", ramCost); return updateStaticRam("getCompanyFavor", ramCost);
} }
@ -2946,7 +2947,7 @@ function NetscriptFunctions(workerScript) {
}, },
getCompanyFavorGain : function(companyName) { getCompanyFavorGain : function(companyName) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getCompanyFavorGain", ramCost); return updateStaticRam("getCompanyFavorGain", ramCost);
} }
@ -2967,7 +2968,7 @@ function NetscriptFunctions(workerScript) {
}, },
checkFactionInvitations : function() { checkFactionInvitations : function() {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("checkFactionInvitations", ramCost); return updateStaticRam("checkFactionInvitations", ramCost);
} }
@ -2983,7 +2984,7 @@ function NetscriptFunctions(workerScript) {
}, },
joinFaction : function(name) { joinFaction : function(name) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("joinFaction", ramCost); return updateStaticRam("joinFaction", ramCost);
} }
@ -3022,7 +3023,7 @@ function NetscriptFunctions(workerScript) {
}, },
workForFaction : function(name, type) { workForFaction : function(name, type) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("workForFaction", ramCost); return updateStaticRam("workForFaction", ramCost);
} }
@ -3122,7 +3123,7 @@ function NetscriptFunctions(workerScript) {
}, },
getFactionRep : function(name) { getFactionRep : function(name) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getFactionRep", ramCost); return updateStaticRam("getFactionRep", ramCost);
} }
@ -3143,7 +3144,7 @@ function NetscriptFunctions(workerScript) {
}, },
getFactionFavor : function(name) { getFactionFavor : function(name) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getFactionFavor", ramCost); return updateStaticRam("getFactionFavor", ramCost);
} }
@ -3164,7 +3165,7 @@ function NetscriptFunctions(workerScript) {
}, },
getFactionFavorGain: function(name) { getFactionFavorGain: function(name) {
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost; var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getFactionFavorGain", ramCost); return updateStaticRam("getFactionFavorGain", ramCost);
} }
@ -3185,7 +3186,7 @@ function NetscriptFunctions(workerScript) {
}, },
donateToFaction : function(name, amt) { donateToFaction : function(name, amt) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("donateToFaction", ramCost); return updateStaticRam("donateToFaction", ramCost);
} }
@ -3224,7 +3225,7 @@ function NetscriptFunctions(workerScript) {
}, },
createProgram : function(name) { createProgram : function(name) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("createProgram", ramCost); return updateStaticRam("createProgram", ramCost);
} }
@ -3278,7 +3279,7 @@ function NetscriptFunctions(workerScript) {
}, },
commitCrime : function(crimeRoughName) { commitCrime : function(crimeRoughName) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("commitCrime", ramCost); return updateStaticRam("commitCrime", ramCost);
} }
@ -3335,7 +3336,7 @@ function NetscriptFunctions(workerScript) {
}, },
getCrimeChance : function(crimeRoughName) { getCrimeChance : function(crimeRoughName) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getCrimeChance", ramCost); return updateStaticRam("getCrimeChance", ramCost);
} }
@ -3356,7 +3357,7 @@ function NetscriptFunctions(workerScript) {
}, },
getOwnedAugmentations : function(purchased=false) { getOwnedAugmentations : function(purchased=false) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getOwnedAugmentations", ramCost); return updateStaticRam("getOwnedAugmentations", ramCost);
} }
@ -3380,7 +3381,7 @@ function NetscriptFunctions(workerScript) {
}, },
getOwnedSourceFiles : function() { getOwnedSourceFiles : function() {
let ramCost = CONSTANTS.ScriptSingularityFn3RamCost; let ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getOwnedSourceFiles", ramCost); return updateStaticRam("getOwnedSourceFiles", ramCost);
} }
@ -3399,7 +3400,7 @@ function NetscriptFunctions(workerScript) {
}, },
getAugmentationsFromFaction : function(facname) { getAugmentationsFromFaction : function(facname) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getAugmentationsFromFaction", ramCost); return updateStaticRam("getAugmentationsFromFaction", ramCost);
} }
@ -3425,7 +3426,7 @@ function NetscriptFunctions(workerScript) {
}, },
getAugmentationCost : function(name) { getAugmentationCost : function(name) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getAugmentationCost", ramCost); return updateStaticRam("getAugmentationCost", ramCost);
} }
@ -3447,7 +3448,7 @@ function NetscriptFunctions(workerScript) {
}, },
purchaseAugmentation : function(faction, name) { purchaseAugmentation : function(faction, name) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("purchaseAugmentation", ramCost); return updateStaticRam("purchaseAugmentation", ramCost);
} }
@ -3512,7 +3513,7 @@ function NetscriptFunctions(workerScript) {
}, },
installAugmentations : function(cbScript) { installAugmentations : function(cbScript) {
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost; var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
if (Player.bitNodeN !== 4) {ramCost *= 8;} if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("installAugmentations", ramCost); return updateStaticRam("installAugmentations", ramCost);
} }
@ -3534,7 +3535,249 @@ function NetscriptFunctions(workerScript) {
return true; return true;
}, },
//Bladeburner API // Gang API
gang : {
getMemberNames : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getMemberNames", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getMemberNames", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getMemberNames");
try {
const names = [];
for (const member of Player.gang.members) {
names.push(member.name);
}
return names;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberNames", e));
}
},
getGangInformation : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getGangInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getGangInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getGangInformation");
try {
return {
faction: Player.gang.facName,
isHacking: Player.gang.isHackingGang,
moneyGainRate: Player.gang.moneyGainRate,
power: Player.gang.getPower(),
respect: Player.gang.respect,
respectGainRate: Player.gang.respectGainRate,
territory: Player.gang.getTerritory(),
territoryClashChance: Player.gang.territoryClashChance,
territoryWarfareEngaged: Player.gang.territoryWarfareEngaged,
wantedLevel: Player.gang.wanted,
wantedLevelGainRate: Player.gang.wantedGainRate,
}
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getGangInformation", e));
}
},
getMemberInformation : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("getMemberInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getMemberInformation", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getMemberInformation");
try {
for (const member of Player.gang.members) {
if (member.name === name) {
return {
agility: member.agi,
agilityEquipMult: member.agi_mult,
agilityAscensionMult: member.agi_asc_mult,
augmentations: member.augmentations.slice(),
charisma: member.cha,
charismaEquipMult: member.cha_mult,
charismaAscensionMult: member.cha_asc_mult,
defense: member.def,
defenseEquipMult: member.def_mult,
defenseAscensionMult: member.def_asc_mult,
dexterity: member.dex,
dexterityEquipMult: member.dex_mult,
dexterityAscensionMult: member.dex_asc_mult,
equipment: member.upgrades.slice(),
hacking: member.hack,
hackingEquipMult: member.hack_mult,
hackingAscensionMult: member.hack_asc_mult,
strength: member.str,
strengthEquipMult: member.str_mult,
strengthAscensionMult: member.str_asc_mult,
task: member.task.name,
}
}
}
workerScript.log(`Invalid argument passed to gang.getMemberInformation(). No gang member could be found with name ${name}`);
return {}; // Member could not be found
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getMemberInformation", e));
}
},
canRecruitMember : function() {
if (workerScript.checkingRam) {
return updateStaticRam("canRecruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("canRecruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "canRecruitMember");
try {
return Player.gang.canRecruitMember();
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("canRecruitMember", e));
}
},
recruitMember : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("recruitMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "recruitMember");
try {
return Player.gang.recruitMember(name);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("recruitMember", e));
}
},
getTaskNames : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getTaskNames", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getTaskNames", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getTaskNames");
try {
const tasks = Player.gang.getAllTaskNames();
tasks.unshift("Unassigned");
return tasks;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getTaskNames", e));
}
},
setMemberTask : function(memberName, taskName) {
if (workerScript.checkingRam) {
return updateStaticRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("setMemberTask", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "setMemberTask");
try {
for (const member of Player.gang.members) {
if (member.name === memberName) {
return member.assignToTask(taskName);
}
}
workerScript.log(`Invalid argument passed to gang.setMemberTask(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setMemberTask", e));
}
},
getEquipmentNames : function() {
if (workerScript.checkingRam) {
return updateStaticRam("getEquipmentNames", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getEquipmentNames", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getEquipmentNames");
try {
return Player.gang.getAllUpgradeNames();
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentNames", e));
}
},
getEquipmentCost : function(equipName) {
if (workerScript.checkingRam) {
return updateStaticRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("getEquipmentCost", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "getEquipmentCost");
try {
return Player.gang.getUpgradeCost(equipName);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getEquipmentCost", e));
}
},
purchaseEquipment : function(memberName, equipName) {
if (workerScript.checkingRam) {
return updateStaticRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("purchaseEquipment", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "purchaseEquipment");
try {
for (const member in Player.gang.members) {
if (member.name === memberName) {
return member.buyUpgrade(equipName, Player, Player.gang);
}
}
workerScript.log(`Invalid argument passed to gang.purchaseEquipment(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("purchaseEquipment", e));
}
},
ascendMember : function(name) {
if (workerScript.checkingRam) {
return updateStaticRam("ascendMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("ascendMember", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "ascendMember");
try {
for (const member in Player.gang.members) {
if (member.name === name) {
return Player.gang.ascendMember(member, workerScript);
}
}
workerScript.log(`Invalid argument passed to gang.ascendMember(). No gang member could be found with name ${memberName}`);
return false;
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("ascendMember", e));
}
},
setTerritoryWarfare : function(engage) {
if (workerScript.checkingRam) {
return updateStaticRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2);
}
updateDynamicRam("setTerritoryWarfare", CONSTANTS.ScriptGangApiBaseRamCost / 2);
nsGang.checkGangApiAccess(workerScript, "setTerritoryWarfare");
try {
if (engage) {
Player.gang.territoryWarfareEngaged = true;
} else {
Player.gang.territoryWarfareEngaged = false;
}
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("setTerritoryWarfare", e));
}
},
getBonusTime : function() {
if (workerScript.checkingRam) { return 0; }
nsGang.checkGangApiAccess(workerScript, "getBonusTime");
try {
return Math.round(Player.gang.storedCycles / 5);
} catch(e) {
throw makeRuntimeRejectMsg(workerScript, nsGang.unknownGangApiExceptionMessage("getBonusTime", e));
}
},
}, // end gang namespace
// Bladeburner API
bladeburner : { bladeburner : {
getContractNames : function() { getContractNames : function() {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {

15
src/NetscriptGang.js Normal file

@ -0,0 +1,15 @@
import {Player} from "./Player";
import {Gang} from "./Gang";
import {makeRuntimeRejectMsg} from "./NetscriptEvaluator";
export function unknownGangApiExceptionMessage(functionName, err) {
return `gang.${functionName}() failed with exception: ` + err;
}
export function checkGangApiAccess(workerScript, functionName) {
const accessDenied = `gang.${functionName}() failed because you do not currently have a Gang`;
const hasAccess = Player.gang instanceof Gang;
if (!hasAccess) {
throw makeRuntimeRejectMsg(workerScript, accessDenied);
}
}

@ -31,8 +31,6 @@ export async function executeJSScript(scripts = [], workerScript) {
loadedModule = script.module; loadedModule = script.module;
let ns = workerScript.env.vars; let ns = workerScript.env.vars;
//ns.threads = workerScript.threads;
//ns.args = workerScript.args;
try { try {
// TODO: putting await in a non-async function yields unhelpful // TODO: putting await in a non-async function yields unhelpful
@ -75,7 +73,7 @@ export function _getScriptUrls(script, scripts, seen) {
// import {foo} from "blob://<uuid>" // import {foo} from "blob://<uuid>"
// //
// Where the blob URL contains the script content. // Where the blob URL contains the script content.
const transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))([^'"]+)('|";)/g, let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))([^'"]+)('|";)/g,
(unmodified, prefix, filename, suffix) => { (unmodified, prefix, filename, suffix) => {
const isAllowedImport = scripts.some(s => s.filename == filename); const isAllowedImport = scripts.some(s => s.filename == filename);
if (!isAllowedImport) return unmodified; if (!isAllowedImport) return unmodified;
@ -92,6 +90,9 @@ export function _getScriptUrls(script, scripts, seen) {
} }
); );
// We automatically define a print function() in the NetscriptJS module so that
// accidental calls to window.print() do not bring up the "print screen" dialog
transformedCode += `\n\nfunction print() {throw new Error("Invalid call to window.print(). Did you mean to use Netscript's print()?");}`
// If we successfully transformed the code, create a blob url for it and // If we successfully transformed the code, create a blob url for it and
// push that URL onto the top of the stack. // push that URL onto the top of the stack.

@ -14,7 +14,6 @@ import {NetscriptPort} from "./NetscriptPort";
import {AllServers} from "./Server"; import {AllServers} from "./Server";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
//TODO Maybe escodegen might be better?
import {generate} from 'escodegen'; import {generate} from 'escodegen';
import {parse, Node} from "../utils/acorn"; import {parse, Node} from "../utils/acorn";
@ -138,7 +137,18 @@ function startNetscript2Script(workerScript) {
throw workerScript; throw workerScript;
} }
runningFn = propName; runningFn = propName;
let result = f(...args);
// If the function throws an error, clear the runningFn flag first, and then re-throw it
// This allows people to properly catch errors thrown by NS functions without getting
// the concurrent call error above
let result;
try {
result = f(...args);
} catch(e) {
runningFn = null;
throw(e);
}
if (result && result.finally !== undefined) { if (result && result.finally !== undefined) {
return result.finally(function () { return result.finally(function () {
runningFn = null; runningFn = null;

@ -20,17 +20,14 @@ import {AllServers, Server, AddToAllServers} from "./Server";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import {SpecialServerIps, SpecialServerNames} from "./SpecialServerIps"; import {SpecialServerIps, SpecialServerNames} from "./SpecialServerIps";
import {SourceFiles, applySourceFile} from "./SourceFile"; import {SourceFiles, applySourceFile} from "./SourceFile";
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import {numeralWrapper} from "./ui/numeralFormat"; import {numeralWrapper} from "./ui/numeralFormat";
import {dialogBoxCreate} from "../utils/DialogBox"; import {dialogBoxCreate} from "../utils/DialogBox";
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners"; import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
import {createRandomIp} from "../utils/IPAddress"; import {createRandomIp} from "../utils/IPAddress";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver"; Generic_fromJSON} from "../utils/JSONReviver";
import {formatNumber, import {convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions";
convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions";
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
@ -721,17 +718,17 @@ PlayerObject.prototype.work = function(numCycles) {
var txt = document.getElementById("work-in-progress-text"); var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName +
" at " + this.companyName + " (Current Company Reputation: " + " at " + this.companyName + " (Current Company Reputation: " +
formatNumber(companyRep, 0) + ")<br><br>" + numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"You have earned: <br><br>" + "You have earned: <br><br>" +
"$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * CYCLES_PER_SEC, 2) + " / sec) <br><br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec) <br><br>" +
formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * CYCLES_PER_SEC, 4) + " / sec) reputation for this company <br><br>" + numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this company <br><br>" +
formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp <br><br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp <br><br>" +
formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp <br><br> " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp <br><br> " +
formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp <br><br>" + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp <br><br>" +
"You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " +
"but you will only gain half of the reputation you've earned so far." "but you will only gain half of the reputation you've earned so far."
} }
@ -750,14 +747,14 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) {
this.updateSkillLevels(); this.updateSkillLevels();
var txt = "You earned a total of: <br>" + var txt = "You earned a total of: <br>" +
"$" + formatNumber(this.workMoneyGained, 2) + "<br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "<br>" +
formatNumber(this.workRepGained, 4) + " reputation for the company <br>" + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the company <br>" +
formatNumber(this.workHackExpGained, 4) + " hacking exp <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp <br>" +
formatNumber(this.workStrExpGained, 4) + " strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " agility exp <br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp <br>" +
formatNumber(this.workChaExpGained, 4) + " charisma exp<br>"; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp<br>";
if (cancelled) { if (cancelled) {
txt = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " <br><br> " + txt = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " <br><br> " +
@ -774,14 +771,14 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) {
if (sing) { if (sing) {
var res = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + var res = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " +
"earned $" + formatNumber(this.workMoneyGained, 2) + ", " + "earned $" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + ", " +
formatNumber(this.workRepGained, 4) + " reputation, " + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation, " +
formatNumber(this.workHackExpGained, 4) + " hacking exp, " + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " +
formatNumber(this.workStrExpGained, 4) + " strength exp, " + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " +
formatNumber(this.workDefExpGained, 4) + " defense exp, " + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " +
formatNumber(this.workDexExpGained, 4) + " dexterity exp, " + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " +
formatNumber(this.workAgiExpGained, 4) + " agility exp, and " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " +
formatNumber(this.workChaExpGained, 4) + " charisma exp."; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp.";
this.resetWorkStatus(); this.resetWorkStatus();
return res; return res;
} }
@ -843,17 +840,17 @@ PlayerObject.prototype.workPartTime = function(numCycles) {
var txt = document.getElementById("work-in-progress-text"); var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName + txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName +
" at " + Player.companyName + " (Current Company Reputation: " + " at " + Player.companyName + " (Current Company Reputation: " +
formatNumber(companyRep, 0) + ")<br><br>" + numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"You have earned: <br><br>" + "You have earned: <br><br>" +
"$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * CYCLES_PER_SEC, 2) + " / sec) <br><br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec) <br><br>" +
formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * CYCLES_PER_SEC, 4) + " / sec) reputation for this company <br><br>" + numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this company <br><br>" +
formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp <br><br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp <br><br>" +
formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp <br><br> " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp <br><br> " +
formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp <br><br>" + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp <br><br>" +
"You will automatically finish after working for 8 hours. You can cancel earlier if you wish, <br>" + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, <br>" +
"and there will be no penalty because this is a part-time job."; "and there will be no penalty because this is a part-time job.";
@ -868,14 +865,14 @@ PlayerObject.prototype.finishWorkPartTime = function(sing=false) {
this.updateSkillLevels(); this.updateSkillLevels();
var txt = "You earned a total of: <br>" + var txt = "You earned a total of: <br>" +
"$" + formatNumber(this.workMoneyGained, 2) + "<br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "<br>" +
formatNumber(this.workRepGained, 4) + " reputation for the company <br>" + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the company <br>" +
formatNumber(this.workHackExpGained, 4) + " hacking exp <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp <br>" +
formatNumber(this.workStrExpGained, 4) + " strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " agility exp <br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp <br>" +
formatNumber(this.workChaExpGained, 4) + " charisma exp<br>"; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp<br>";
txt = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br> " + txt; txt = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br> " + txt;
if (!sing) {dialogBoxCreate(txt);} if (!sing) {dialogBoxCreate(txt);}
@ -886,14 +883,14 @@ PlayerObject.prototype.finishWorkPartTime = function(sing=false) {
if (sing) { if (sing) {
var res = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + var res = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " +
"earned a total of " + "earned a total of " +
"$" + formatNumber(this.workMoneyGained, 2) + ", " + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + ", " +
formatNumber(this.workRepGained, 4) + " reputation, " + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation, " +
formatNumber(this.workHackExpGained, 4) + " hacking exp, " + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " +
formatNumber(this.workStrExpGained, 4) + " strength exp, " + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " +
formatNumber(this.workDefExpGained, 4) + " defense exp, " + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " +
formatNumber(this.workDexExpGained, 4) + " dexterity exp, " + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " +
formatNumber(this.workAgiExpGained, 4) + " agility exp, and " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " +
formatNumber(this.workChaExpGained, 4) + " charisma exp"; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp";
this.resetWorkStatus(); this.resetWorkStatus();
return res; return res;
} }
@ -1012,17 +1009,17 @@ PlayerObject.prototype.workForFaction = function(numCycles) {
var txt = document.getElementById("work-in-progress-text"); var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently " + this.currentWorkFactionDescription + " for your faction " + faction.name + txt.innerHTML = "You are currently " + this.currentWorkFactionDescription + " for your faction " + faction.name +
" (Current Faction Reputation: " + formatNumber(faction.playerReputation, 0) + "). <br>" + " (Current Faction Reputation: " + numeralWrapper.format(faction.playerReputation, '0,0') + "). <br>" +
"You have been doing this for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" + "You have been doing this for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"You have earned: <br><br>" + "You have earned: <br><br>" +
"$" + formatNumber(this.workMoneyGained, 2) + " (" + formatNumber(this.workMoneyGainRate * CYCLES_PER_SEC, 2) + " / sec) <br><br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " (" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec) <br><br>" +
formatNumber(this.workRepGained, 4) + " (" + formatNumber(this.workRepGainRate * CYCLES_PER_SEC, 4) + " / sec) reputation for this faction <br><br>" + numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this faction <br><br>" +
formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp <br><br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp <br><br>" +
formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp <br><br> " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp <br><br> " +
formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp <br><br>" + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp <br><br>" +
"You will automatically finish after working for 20 hours. You can cancel earlier if you wish.<br>" + "You will automatically finish after working for 20 hours. You can cancel earlier if you wish.<br>" +
"There is no penalty for cancelling earlier."; "There is no penalty for cancelling earlier.";
@ -1038,14 +1035,14 @@ PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) {
var txt = "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " <br><br> " + var txt = "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " <br><br> " +
"You earned a total of: <br>" + "You earned a total of: <br>" +
"$" + formatNumber(this.workMoneyGained, 2) + "<br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "<br>" +
formatNumber(this.workRepGained, 4) + " reputation for the faction <br>" + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the faction <br>" +
formatNumber(this.workHackExpGained, 4) + " hacking exp <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp <br>" +
formatNumber(this.workStrExpGained, 4) + " strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " agility exp <br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp <br>" +
formatNumber(this.workChaExpGained, 4) + " charisma exp<br>"; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp<br>";
if (!sing) {dialogBoxCreate(txt);} if (!sing) {dialogBoxCreate(txt);}
var mainMenu = document.getElementById("mainmenu-container"); var mainMenu = document.getElementById("mainmenu-container");
@ -1058,13 +1055,13 @@ PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) {
if (sing) { if (sing) {
var res="You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " + var res="You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " +
"You earned " + "You earned " +
formatNumber(this.workRepGained, 4) + " rep, " + numeralWrapper.format(this.workRepGained, '0,0.0000') + " rep, " +
formatNumber(this.workHackExpGained, 4) + " hacking exp, " + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " +
formatNumber(this.workStrExpGained, 4) + " str exp, " + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " +
formatNumber(this.workDefExpGained, 4) + " def exp, " + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " +
formatNumber(this.workDexExpGained, 4) + " dex exp, " + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " +
formatNumber(this.workAgiExpGained, 4) + " agi exp, and " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, and " +
formatNumber(this.workChaExpGained, 4) + " cha exp."; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp.";
this.resetWorkStatus(); this.resetWorkStatus();
return res; return res;
} }
@ -1350,14 +1347,14 @@ PlayerObject.prototype.takeClass = function(numCycles) {
var txt = document.getElementById("work-in-progress-text"); var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You have been " + className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" + txt.innerHTML = "You have been " + className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"This has cost you: <br>" + "This has cost you: <br>" +
"$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyLossRate * CYCLES_PER_SEC, 2) + " / sec) <br><br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyLossRate * CYCLES_PER_SEC, '0,0.00') + " / sec) <br><br>" +
"You have gained: <br>" + "You have gained: <br>" +
formatNumber(this.workHackExpGained, 4) + " (" + formatNumber(this.workHackExpGainRate * CYCLES_PER_SEC, 4) + " / sec) hacking exp <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp <br>" +
formatNumber(this.workStrExpGained, 4) + " (" + formatNumber(this.workStrExpGainRate * CYCLES_PER_SEC, 4) + " / sec) strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " (" + formatNumber(this.workDefExpGainRate * CYCLES_PER_SEC, 4) + " / sec) defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " (" + formatNumber(this.workDexExpGainRate * CYCLES_PER_SEC, 4) + " / sec) dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " (" + formatNumber(this.workAgiExpGainRate * CYCLES_PER_SEC, 4) + " / sec) agility exp <br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp <br>" +
formatNumber(this.workChaExpGained, 4) + " (" + formatNumber(this.workChaExpGainRate * CYCLES_PER_SEC, 4) + " / sec) charisma exp <br>" + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp <br>" +
"You may cancel at any time"; "You may cancel at any time";
} }
@ -1373,14 +1370,14 @@ PlayerObject.prototype.finishClass = function(sing=false) {
this.updateSkillLevels(); this.updateSkillLevels();
var txt = "After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", <br>" + var txt = "After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", <br>" +
"you spent a total of $" + formatNumber(this.workMoneyGained * -1, 2) + ". <br><br>" + "you spent a total of $" + numeralWrapper.format(this.workMoneyGained * -1, '0,0.00') + ". <br><br>" +
"You earned a total of: <br>" + "You earned a total of: <br>" +
formatNumber(this.workHackExpGained, 4) + " hacking exp <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp <br>" +
formatNumber(this.workStrExpGained, 4) + " strength exp <br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp <br>" +
formatNumber(this.workDefExpGained, 4) + " defense exp <br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp <br>" +
formatNumber(this.workDexExpGained, 4) + " dexterity exp <br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp <br>" +
formatNumber(this.workAgiExpGained, 4) + " agility exp <br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp <br>" +
formatNumber(this.workChaExpGained, 4) + " charisma exp<br>"; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp<br>";
if (!sing) {dialogBoxCreate(txt);} if (!sing) {dialogBoxCreate(txt);}
var mainMenu = document.getElementById("mainmenu-container"); var mainMenu = document.getElementById("mainmenu-container");
@ -1391,14 +1388,14 @@ PlayerObject.prototype.finishClass = function(sing=false) {
Engine.loadLocationContent(); Engine.loadLocationContent();
if (sing) { if (sing) {
var res="After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", " + var res="After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", " +
"you spent a total of $" + formatNumber(this.workMoneyGained * -1, 2) + ". " + "you spent a total of $" + numeralWrapper.format(this.workMoneyGained * -1, '0,0.00') + ". " +
"You earned a total of: " + "You earned a total of: " +
formatNumber(this.workHackExpGained, 3) + " hacking exp, " + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " +
formatNumber(this.workStrExpGained, 3) + " strength exp, " + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " +
formatNumber(this.workDefExpGained, 3) + " defense exp, " + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " +
formatNumber(this.workDexExpGained, 3) + " dexterity exp, " + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " +
formatNumber(this.workAgiExpGained, 3) + " agility exp, and " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " +
formatNumber(this.workChaExpGained, 3) + " charisma exp"; numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp";
this.resetWorkStatus(); this.resetWorkStatus();
return res; return res;
} }
@ -1489,23 +1486,23 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) { if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) {
this.singFnCrimeWorkerScript.scriptRef.log("Crime successful! Gained " + this.singFnCrimeWorkerScript.scriptRef.log("Crime successful! Gained " +
numeralWrapper.format(this.workMoneyGained, "$0.000a") + ", " + numeralWrapper.format(this.workMoneyGained, "$0.000a") + ", " +
formatNumber(this.workHackExpGained, 3) + " hack exp, " + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hack exp, " +
formatNumber(this.workStrExpGained, 3) + " str exp, " + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " +
formatNumber(this.workDefExpGained, 3) + " def exp, " + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " +
formatNumber(this.workDexExpGained, 3) + " dex exp, " + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " +
formatNumber(this.workAgiExpGained, 3) + " agi exp, " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, " +
formatNumber(this.workChaExpGained, 3) + " cha exp."); numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp.");
} }
} else { } else {
dialogBoxCreate("Crime successful! <br><br>" + dialogBoxCreate("Crime successful! <br><br>" +
"You gained:<br>"+ "You gained:<br>"+
"$" + formatNumber(this.workMoneyGained, 2) + "<br>" + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "<br>" +
formatNumber(this.workHackExpGained, 4) + " hacking experience <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking experience <br>" +
formatNumber(this.workStrExpGained, 4) + " strength experience<br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength experience<br>" +
formatNumber(this.workDefExpGained, 4) + " defense experience<br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense experience<br>" +
formatNumber(this.workDexExpGained, 4) + " dexterity experience<br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity experience<br>" +
formatNumber(this.workAgiExpGained, 4) + " agility experience<br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility experience<br>" +
formatNumber(this.workChaExpGained, 4) + " charisma experience"); numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma experience");
} }
} else { } else {
@ -1519,22 +1516,22 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
if (this.committingCrimeThruSingFn) { if (this.committingCrimeThruSingFn) {
if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) { if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) {
this.singFnCrimeWorkerScript.scriptRef.log("Crime failed! Gained " + this.singFnCrimeWorkerScript.scriptRef.log("Crime failed! Gained " +
formatNumber(this.workHackExpGained, 3) + " hack exp, " + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hack exp, " +
formatNumber(this.workStrExpGained, 3) + " str exp, " + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " +
formatNumber(this.workDefExpGained, 3) + " def exp, " + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " +
formatNumber(this.workDexExpGained, 3) + " dex exp, " + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " +
formatNumber(this.workAgiExpGained, 3) + " agi exp, " + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, " +
formatNumber(this.workChaExpGained, 3) + " cha exp."); numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp.");
} }
} else { } else {
dialogBoxCreate("Crime failed! <br><br>" + dialogBoxCreate("Crime failed! <br><br>" +
"You gained:<br>"+ "You gained:<br>"+
formatNumber(this.workHackExpGained, 4) + " hacking experience <br>" + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking experience <br>" +
formatNumber(this.workStrExpGained, 4) + " strength experience<br>" + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength experience<br>" +
formatNumber(this.workDefExpGained, 4) + " defense experience<br>" + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense experience<br>" +
formatNumber(this.workDexExpGained, 4) + " dexterity experience<br>" + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity experience<br>" +
formatNumber(this.workAgiExpGained, 4) + " agility experience<br>" + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility experience<br>" +
formatNumber(this.workChaExpGained, 4) + " charisma experience"); numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma experience");
} }
} }
@ -1912,10 +1909,10 @@ PlayerObject.prototype.reapplyAllAugmentations = function(resetMultipliers=true)
this.augmentations[i].name = "Hacknet Node NIC Architecture Neural-Upload"; this.augmentations[i].name = "Hacknet Node NIC Architecture Neural-Upload";
} }
var augName = this.augmentations[i].name; const augName = this.augmentations[i].name;
var aug = Augmentations[augName]; var aug = Augmentations[augName];
if (aug == null) { if (aug == null) {
console.log("WARNING: Invalid augmentation name"); console.log(`WARNING: Invalid augmentation name in Player.reapplyAllAugmentations(). Aug ${augName} will be skipped`);
continue; continue;
} }
aug.owned = true; aug.owned = true;

@ -314,8 +314,8 @@ function prestigeSourceFile() {
stockMarketList.removeChild(stockMarketList.firstChild); stockMarketList.removeChild(stockMarketList.firstChild);
} }
if (Player.inGang()) { Player.gang.clearUI(); }
Player.gang = null; Player.gang = null;
deleteGangDisplayContent();
Player.corporation = null; Player.corporation = null;
Player.bladeburner = null; Player.bladeburner = null;

@ -18,7 +18,6 @@ import {yesNoBoxCreate, yesNoBoxGetYesButton,
//Returns promise //Returns promise
function writeRedPillLine(line) { function writeRedPillLine(line) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var container = document.getElementById("red-pill-content"); var container = document.getElementById("red-pill-content");
var pElem = document.createElement("p"); var pElem = document.createElement("p");
container.appendChild(pElem); container.appendChild(pElem);
@ -54,6 +53,10 @@ function writeRedPillLetter(pElem, line, i=0) {
let redPillFlag = false; let redPillFlag = false;
function hackWorldDaemon(currentNodeNumber, flume=false) { function hackWorldDaemon(currentNodeNumber, flume=false) {
// Clear Red Pill screen first
var container = document.getElementById("red-pill-content");
removeChildrenFromElement(container);
redPillFlag = true; redPillFlag = true;
Engine.loadRedPillContent(); Engine.loadRedPillContent();
return writeRedPillLine("[ERROR] SEMPOOL INVALID").then(function() { return writeRedPillLine("[ERROR] SEMPOOL INVALID").then(function() {
@ -301,7 +304,7 @@ function createBitNodeYesNoEventListeners(newBitNode, destroyedBitNode, flume=fa
Player.gainIntelligenceExp(-5); Player.gainIntelligenceExp(-5);
} }
redPillFlag = false; redPillFlag = false;
var container = document.getElementById("red-pill-container"); var container = document.getElementById("red-pill-content");
removeChildrenFromElement(container); removeChildrenFromElement(container);
//Set new Bit Node //Set new Bit Node

6
src/SaveObject.js Normal file → Executable file

@ -24,7 +24,7 @@ import {Reviver, Generic_toJSON,
import {createElement} from "../utils/uiHelpers/createElement"; import {createElement} from "../utils/uiHelpers/createElement";
import {createPopup} from "../utils/uiHelpers/createPopup"; import {createPopup} from "../utils/uiHelpers/createPopup";
import {createStatusText} from "./ui/createStatusText"; import {createStatusText} from "./ui/createStatusText";
import {formatNumber} from "../utils/StringHelperFunctions"; import {numeralWrapper} from "./ui/numeralFormat";
import {removeElementById} from "../utils/uiHelpers/removeElementById"; import {removeElementById} from "../utils/uiHelpers/removeElementById";
import Decimal from "decimal.js"; import Decimal from "decimal.js";
@ -517,8 +517,8 @@ function loadImportedGame(saveObj, saveString) {
Player.lastUpdate = Engine._lastUpdate; Player.lastUpdate = Engine._lastUpdate;
Engine.start(); //Run main game loop and Scripts loop Engine.start(); //Run main game loop and Scripts loop
dialogBoxCreate("While you were offline, your scripts generated <span class='money-gold'>$" + dialogBoxCreate("While you were offline, your scripts generated <span class='money-gold'>$" +
formatNumber(offlineProductionFromScripts, 2) + "</span> and your Hacknet Nodes generated <span class='money-gold'>$" + numeralWrapper.format(offlineProductionFromScripts, '0,0.00') + "</span> and your Hacknet Nodes generated <span class='money-gold'>$" +
formatNumber(offlineProductionFromHacknetNodes, 2) + "</span>"); numeralWrapper.format(offlineProductionFromHacknetNodes, '0,0.00') + "</span>");
return true; return true;
} }

@ -219,7 +219,8 @@ function scriptEditorInit() {
}); });
//Get functions from namespaces //Get functions from namespaces
if (name === "bladeburner" || name === "hacknet") { const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang"];
if (namespaces.includes(name)) {
let namespace = fns[name]; let namespace = fns[name];
if (typeof namespace !== "object") {continue;} if (typeof namespace !== "object") {continue;}
let namespaceFns = Object.keys(namespace); let namespaceFns = Object.keys(namespace);
@ -557,6 +558,8 @@ async function parseOnlyRamCalculate(server, code, workerScript) {
func = workerScript.env.vars.bladeburner[ref]; func = workerScript.env.vars.bladeburner[ref];
} else if (ref in workerScript.env.vars.codingcontract) { } else if (ref in workerScript.env.vars.codingcontract) {
func = workerScript.env.vars.codingcontract[ref]; func = workerScript.env.vars.codingcontract[ref];
} else if (ref in workerScript.env.vars.gang) {
func = workerScript.env.vars.gang[ref];
} else { } else {
func = workerScript.env.get(ref); func = workerScript.env.get(ref);
} }

@ -27,9 +27,9 @@ function initSourceFiles() {
"Level 3: 28%"); "Level 3: 28%");
SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " + SourceFiles["SourceFile2"] = new SourceFile(2, "This Source-File increases the player's crime success rate, crime money, and charisma " +
"multipliers by:<br><br>" + "multipliers by:<br><br>" +
"Level 1: 20%<br>" + "Level 1: 24%<br>" +
"Level 2: 30%<br>" + "Level 2: 36%<br>" +
"Level 3: 35%"); "Level 3: 42%");
SourceFiles["SourceFile3"] = new SourceFile(3,"This Source-File lets you create corporations on other BitNodes (although " + SourceFiles["SourceFile3"] = new SourceFile(3,"This Source-File lets you create corporations on other BitNodes (although " +
"some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" + "some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" +
"Level 1: 8%<br>" + "Level 1: 8%<br>" +
@ -126,7 +126,7 @@ function applySourceFile(srcFile) {
case 2: //Rise of the Underworld case 2: //Rise of the Underworld
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (20 / (Math.pow(2, i))); mult += (24 / (Math.pow(2, i)));
} }
var incMult = 1 + (mult / 100); var incMult = 1 + (mult / 100);
Player.crime_money_mult *= incMult; Player.crime_money_mult *= incMult;

277
src/data/gangmembertasks.ts Normal file

@ -0,0 +1,277 @@
/* tslint:disable:max-line-length */
/**
* Defines the parameters that can be used to initialize and describe a GangMemberTask
* (defined in Gang.js)
*/
export interface IGangMemberTaskMetadata {
/**
* Description of the task
*/
desc: string;
/**
* Whether or not this task is meant for Combat-type gangs
*/
isCombat: boolean;
/**
* Whether or not this task is for Hacking-type gangs
*/
isHacking: boolean;
/**
* Name of the task
*/
name: string;
/**
* An object containing weighting parameters for the task. These parameters are used for
* various calculations (respect gain, wanted gain, etc.)
*/
params?: any;
}
/**
* Array of metadata for all Gang Member tasks. Used to construct the global GangMemberTask
* objects in Gang.js
*/
export const gangMemberTasksMetadata: IGangMemberTaskMetadata[] = [
{
desc: "This gang member is currently idle",
isCombat: true,
isHacking: true,
name: "Unassigned",
params: {hackWeight: 100}, // This is just to get by the weight check in the GangMemberTask constructor
},
{
desc: "Assign this gang member to create and distribute ransomware<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: false,
isHacking: true,
name: "Ransomware",
params: {baseRespect: 0.00005, baseWanted: 0.00001, baseMoney: 1, hackWeight: 100, difficulty: 1},
},
{
desc: "Assign this gang member to attempt phishing scams and attacks<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: false,
isHacking: true,
name: "Phishing",
params: {baseRespect: 0.00008, baseWanted: 0.001, baseMoney: 2.5, hackWeight: 85, chaWeight: 15, difficulty: 3.5},
},
{
desc: "Assign this gang member to attempt identity theft<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "Identity Theft",
params: {baseRespect: 0.0001, baseWanted: 0.01, baseMoney: 6, hackWeight: 80, chaWeight: 20, difficulty: 5},
},
{
desc: "Assign this gang member to carry out DDoS attacks<br><br>Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "DDoS Attacks",
params: {baseRespect: 0.0004, baseWanted: 0.05, hackWeight: 100, difficulty: 8},
},
{
desc: "Assign this gang member to create and distribute malicious viruses<br><br>Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "Plant Virus",
params: {baseRespect: 0.0006, baseWanted: 0.05, hackWeight: 100, difficulty: 12},
},
{
desc: "Assign this gang member to commit financial fraud and digital counterfeiting<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: false,
isHacking: true,
name: "Fraud & Counterfeiting",
params: {baseRespect: 0.0005, baseWanted: 0.1, baseMoney: 15, hackWeight: 80, chaWeight: 20, difficulty: 20},
},
{
desc: "Assign this gang member to launder money<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: false,
isHacking: true,
name: "Money Laundering",
params: {baseRespect: 0.0006, baseWanted: 0.2, baseMoney: 40, hackWeight: 75, chaWeight: 25, difficulty: 25},
},
{
desc: "Assign this gang member to commit acts of cyberterrorism<br><br>Greatly increases respect - Greatly increases wanted level",
isCombat: false,
isHacking: true,
name: "Cyberterrorism",
params: {baseRespect: 0.001, baseWanted: 0.5, hackWeight: 80, chaWeight: 20, difficulty: 36},
},
{
desc: "Assign this gang member to be an ethical hacker for corporations<br><br>Earns money - Lowers wanted level",
isCombat: false,
isHacking: true,
name: "Ethical Hacking",
params: {baseWanted: -0.001, baseMoney: 1, hackWeight: 90, chaWeight: 10, difficulty: 1},
},
{
desc: "Assign this gang member to mug random people on the streets<br><br>Earns money - Slightly increases respect - Very slightly increases wanted level",
isCombat: true,
isHacking: false,
name: "Mug People",
params: {
baseRespect: 0.00005, baseWanted: 0.00001, baseMoney: 1.2,
strWeight: 25, defWeight: 25, dexWeight: 25, agiWeight: 10, chaWeight: 15,
difficulty: 1,
},
},
{
desc: "Assign this gang member to sell drugs<br><br>Earns money - Slightly increases respect - Slightly increases wanted level - Scales slightly with territory",
isCombat: true,
isHacking: false,
name: "Deal Drugs",
params: {
baseRespect: 0.00008, baseWanted: 0.001, baseMoney: 5,
agiWeight: 20, dexWeight: 20, chaWeight: 60,
difficulty: 3.5,
territory: {
money: 1.1,
respect: 1,
wanted: 1.15,
},
},
},
{
desc: "Assign this gang member to extort civilians in your territory<br><br>Earns money - Slightly increases respect - Increases wanted - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Strongarm Civilians",
params: {
baseRespect: 0.00004, baseWanted: 0.0001, baseMoney: 2.5,
hackWeight: 10, strWeight: 25, defWeight: 25, dexWeight: 20, agiWeight: 10, chaWeight: 10,
difficulty: 5,
territory: {
money: 2,
respect: 1.1,
wanted: 1.5
}
}
},
{
desc: "Assign this gang member to run cons<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: true,
isHacking: false,
name: "Run a Con",
params: {
baseRespect: 0.00015, baseWanted: 0.01, baseMoney: 12.5,
strWeight: 5, defWeight: 5, agiWeight: 25, dexWeight: 25, chaWeight: 40,
difficulty: 14,
},
},
{
desc: "Assign this gang member to commit armed robbery on stores, banks and armored cars<br><br>Earns money - Increases respect - Increases wanted level",
isCombat: true,
isHacking: false,
name: "Armed Robbery",
params: {
baseRespect: 0.00015, baseWanted: 0.05, baseMoney: 32,
hackWeight: 20, strWeight: 15, defWeight: 15, agiWeight: 10, dexWeight: 20, chaWeight: 20,
difficulty: 20,
},
},
{
desc: "Assign this gang member to traffick illegal arms<br><br>Earns money - Increases respect - Increases wanted level - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Traffick Illegal Arms",
params: {
baseRespect: 0.0003, baseWanted: 0.1, baseMoney: 50,
hackWeight: 15, strWeight: 20, defWeight: 20, dexWeight: 20, chaWeight: 25,
difficulty: 28,
territory: {
money: 1.2,
respect: 1.3,
wanted: 1.25,
},
},
},
{
desc: "Assign this gang member to threaten and black mail high-profile targets<br><br>Earns money - Slightly increases respect - Slightly increases wanted level",
isCombat: true,
isHacking: false,
name: "Threaten & Blackmail",
params: {
baseRespect: 0.0002, baseWanted: 0.05, baseMoney: 20,
hackWeight: 25, strWeight: 25, dexWeight: 25, chaWeight: 25,
difficulty: 28,
},
},
{
desc: "Assign this gang member to engage in human trafficking operations<br><br>Earns money - Increases respect - Increases wanted level - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Human Trafficking",
params: {
baseRespect: 0.005, baseWanted: 0.2, baseMoney: 100,
hackWeight: 30, strWeight: 5, defWeight: 5, dexWeight: 30, chaWeight: 30,
difficulty: 36,
territory: {
money: 1.5,
respect: 1.5,
wanted: 1.6,
}
}
},
{
desc: "Assign this gang member to commit acts of terrorism<br><br>Greatly increases respect - Greatly increases wanted level - Scales heavily with territory",
isCombat: true,
isHacking: false,
name: "Terrorism",
params: {
baseRespect: 0.001, baseWanted: 1,
hackWeight: 20, strWeight: 20, defWeight: 20, dexWeight: 20, chaWeight: 20,
difficulty: 36,
territory: {
money: 1,
respect: 2,
wanted: 2,
},
},
},
{
desc: "Assign this gang member to be a vigilante and protect the city from criminals<br><br>Decreases wanted level",
isCombat: true,
isHacking: true,
name: "Vigilante Justice",
params: {
baseWanted: -0.001,
hackWeight: 20, strWeight: 20, defWeight: 20, dexWeight: 20, agiWeight: 20,
difficulty: 1,
territory: {
money: 1,
respect: 1,
wanted: 0.9, // Gets harder with more territory
},
},
},
{
desc: "Assign this gang member to increase their combat stats (str, def, dex, agi)",
isCombat: true,
isHacking: true,
name: "Train Combat",
params: {
strWeight: 25, defWeight: 25, dexWeight: 25, agiWeight: 25,
difficulty: 5
},
},
{
desc: "Assign this gang member to train their hacking skills",
isCombat: true,
isHacking: true,
name: "Train Hacking",
params: {hackWeight: 100, difficulty: 8},
},
{
desc: "Assign this gang member to engage in territorial warfare with other gangs. Members assigned to this task will help increase your gang's territory and will defend your territory from being taken.",
isCombat: true,
isHacking: true,
name: "Territory Warfare",
params: {
hackWeight: 15, strWeight: 20, defWeight: 20, dexWeight: 20, agiWeight: 20, chaWeight: 5,
difficulty: 3
},
},
];

@ -0,0 +1,191 @@
/**
* Defines the parameters that can be used to initialize and describe a GangMemberUpgrade
* (defined in Gang.js)
*/
export interface IGangMemberUpgradeMetadata {
cost: number;
mults: any;
name: string;
upgType: string;
}
/**
* Array of metadata for all Gang Member upgrades. Used to construct the global GangMemberUpgrade
* objects in Gang.js
*/
export const gangMemberUpgradesMetadata: IGangMemberUpgradeMetadata[] = [
{
cost: 1e6,
mults: {str: 1.04, def: 1.04},
name: "Baseball Bat",
upgType: "w",
},
{
cost: 12e6,
mults: {str: 1.08, def: 1.08, dex: 1.08},
name: "Katana",
upgType: "w",
},
{
cost: 25e6,
mults: {str: 1.1, def: 1.1, dex: 1.1, agi: 1.1},
name: "Glock 18C",
upgType: "w",
},
{
cost: 50e6,
mults: {str: 1.12, def: 1.12, agi: 1.1},
name: "P90C",
upgType: "w",
},
{
cost: 60e6,
mults: {str: 1.2, def: 1.2},
name: "Steyr AUG",
upgType: "w",
},
{
cost: 100e6,
mults: {str: 1.25, def: 1.25},
name: "AK-47",
upgType: "w",
},
{
cost: 150e6,
mults: {str: 1.3, def: 1.3},
name: "M15A10 Assault Rifle",
upgType: "w",
},
{
cost: 225e6,
mults: {str: 1.3, dex: 1.3, agi: 1.3},
name: "AWM Sniper Rifle",
upgType: "w",
},
{
cost: 2e6,
mults: {def: 1.04},
name: "Bulletproof Vest",
upgType: "a",
},
{
cost: 5e6,
mults: {def: 1.08},
name: "Full Body Armor",
upgType: "a",
},
{
cost: 25e6,
mults: {def: 1.15, agi: 1.15},
name: "Liquid Body Armor",
upgType: "a",
},
{
cost: 40e6,
mults: {def: 1.2},
name: "Graphene Plating Armor",
upgType: "a",
},
{
cost: 3e6,
mults: {agi: 1.04, cha: 1.04},
name: "Ford Flex V20",
upgType: "v",
},
{
cost: 9e6,
mults: {agi: 1.08, cha: 1.08},
name: "ATX1070 Superbike",
upgType: "v",
},
{
cost: 18e6,
mults: {agi: 1.12, cha: 1.12},
name: "Mercedes-Benz S9001",
upgType: "v",
},
{
cost: 30e6,
mults: {agi: 1.16, cha: 1.16},
name: "White Ferrari",
upgType: "v",
},
{
cost: 5e6,
mults: {hack: 1.05},
name: "NUKE Rootkit",
upgType: "r",
},
{
cost: 15e6,
mults: {hack: 1.1},
name: "Soulstealer Rootkit",
upgType: "r",
},
{
cost: 50e6,
mults: {hack: 1.15},
name: "Demon Rootkit",
upgType: "r",
},
{
cost: 10e9,
mults: {str: 1.3, dex: 1.3},
name: "Bionic Arms",
upgType: "g",
},
{
cost: 10e9,
mults: {agi: 1.6},
name: "Bionic Legs",
upgType: "g",
},
{
cost: 15e9,
mults: {str: 1.15, def: 1.15, dex: 1.15, agi: 1.15},
name: "Bionic Spine",
upgType: "g",
},
{
cost: 20e9,
mults: {str: 1.4, def: 1.4},
name: "BrachiBlades",
upgType: "g",
},
{
cost: 12e9,
mults: {str: 1.2, def: 1.2},
name: "Nanofiber Weave",
upgType: "g",
},
{
cost: 25e9,
mults: {str: 1.5, agi: 1.5},
name: "Synthetic Heart",
upgType: "g",
},
{
cost: 15e9,
mults: {str: 1.3, def: 1.3},
name: "Synfibril Muscle",
upgType: "g",
},
{
cost: 5e9,
mults: {hack: 1.05},
name: "BitWire",
upgType: "g",
},
{
cost: 10e9,
mults: {hack: 1.15},
name: "Neuralstimulator",
upgType: "g",
},
{
cost: 50e9,
mults: {str: 1.7, def: 1.7},
name: "Graphene Bone Lacings",
upgType: "g",
},
];

@ -33,6 +33,7 @@ import {displayCreateProgramContent,
getNumAvailableCreateProgram, getNumAvailableCreateProgram,
initCreateProgramButtons, initCreateProgramButtons,
Programs} from "./CreateProgram"; Programs} from "./CreateProgram";
import {createDevMenu, closeDevMenu} from "./DevMenu";
import {displayFactionContent, joinFaction, import {displayFactionContent, joinFaction,
processPassiveFactionRepGain, Factions, processPassiveFactionRepGain, Factions,
inviteToFaction, initFactions} from "./Faction"; inviteToFaction, initFactions} from "./Faction";
@ -40,8 +41,6 @@ import {FconfSettings} from "./Fconf";
import {displayLocationContent, import {displayLocationContent,
initLocationButtons} from "./Location"; initLocationButtons} from "./Location";
import {Locations} from "./Locations"; import {Locations} from "./Locations";
import {displayGangContent, updateGangContent,
Gang} from "./Gang";
import {displayHacknetNodesContent, processAllHacknetNodeEarnings, import {displayHacknetNodesContent, processAllHacknetNodeEarnings,
updateHacknetNodesContent} from "./HacknetNode"; updateHacknetNodesContent} from "./HacknetNode";
import {iTutorialStart} from "./InteractiveTutorial"; import {iTutorialStart} from "./InteractiveTutorial";
@ -89,6 +88,7 @@ import "../css/loader.scss";
import "../css/missions.scss"; import "../css/missions.scss";
import "../css/companymanagement.scss"; import "../css/companymanagement.scss";
import "../css/bladeburner.scss"; import "../css/bladeburner.scss";
import "../css/gang.scss";
/* Shortcuts to navigate through the game /* Shortcuts to navigate through the game
* Alt-t - Terminal * Alt-t - Terminal
@ -194,41 +194,6 @@ const Engine = {
tutorialFactionsButton: null, tutorialFactionsButton: null,
tutorialAugmentationsButton: null, tutorialAugmentationsButton: null,
tutorialBackButton: null, tutorialBackButton: null,
//Dev menu
devMenuGiveMoney: null,
devMenuGiveRam: null,
devMenuAugDropdown: null,
devMenuAddAug: null,
devMenuTriggerBitFlume: null,
devMenuFactionDropdown: null,
devMenuAddFaction: null,
devMenuOpen: null,
devMenuMinSecurity: null,
devMenuMaxMoney: null,
devMenuConnectDropdown: null,
devMenuConnect: null,
devMenuProgramsDropdown: null,
devMenuAddProgram: null,
devMenuHackingExp: null,
devMenuAddHacking: null,
devMenuStrengthExp: null,
devMenuAddStrength: null,
devMenuDefenseExp: null,
devMenuAddDefense: null,
devMenuDexterityExp: null,
devMenuAddDexterity: null,
devMenuAgilityExp: null,
devMenuAddAgility: null,
devMenuCharismaExp: null,
devMenuAddCharisma: null,
devMenuIntelligenceExp: null,
devMenuAddIntelligence: null,
devMenuEnableIntelligence: null,
devMenuDisableIntelligence: null,
devMenuSFN: null,
devMenuSFLvl: null,
devMenuAddSF: null,
}, },
//Display objects //Display objects
@ -254,7 +219,6 @@ const Engine = {
factionAugmentationsContent: null, factionAugmentationsContent: null,
augmentationsContent: null, augmentationsContent: null,
tutorialContent: null, tutorialContent: null,
devMenuContent: null,
infiltrationContent: null, infiltrationContent: null,
stockMarketContent: null, stockMarketContent: null,
locationContent: null, locationContent: null,
@ -365,8 +329,7 @@ const Engine = {
loadDevMenuContent: function() { loadDevMenuContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
Engine.Display.devMenuContent.style.display = "block"; createDevMenu();
Engine.displayDevMenuContent();
routing.navigateTo(Page.DevMenu); routing.navigateTo(Page.DevMenu);
document.getElementById("dev-menu-link").classList.add("active"); document.getElementById("dev-menu-link").classList.add("active");
}, },
@ -456,7 +419,7 @@ const Engine = {
loadGangContent: function() { loadGangContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
if (document.getElementById("gang-container") || Player.inGang()) { if (document.getElementById("gang-container") || Player.inGang()) {
displayGangContent(); Player.gang.displayGangContent(Player);
routing.navigateTo(Page.Gang); routing.navigateTo(Page.Gang);
} else { } else {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
@ -507,7 +470,6 @@ const Engine = {
Engine.Display.factionAugmentationsContent.style.display = "none"; Engine.Display.factionAugmentationsContent.style.display = "none";
Engine.Display.augmentationsContent.style.display = "none"; Engine.Display.augmentationsContent.style.display = "none";
Engine.Display.tutorialContent.style.display = "none"; Engine.Display.tutorialContent.style.display = "none";
Engine.Display.devMenuContent.style.display = "none";
Engine.Display.locationContent.style.display = "none"; Engine.Display.locationContent.style.display = "none";
Engine.Display.workInProgressContent.style.display = "none"; Engine.Display.workInProgressContent.style.display = "none";
Engine.Display.redPillContent.style.display = "none"; Engine.Display.redPillContent.style.display = "none";
@ -519,6 +481,9 @@ const Engine = {
document.getElementById("gang-container").style.display = "none"; document.getElementById("gang-container").style.display = "none";
} }
if (Player.inGang()) {
Player.gang.clearUI();
}
if (Player.corporation instanceof Corporation) { if (Player.corporation instanceof Corporation) {
Player.corporation.clearUI(); Player.corporation.clearUI();
} }
@ -551,12 +516,14 @@ const Engine = {
document.getElementById("bladeburner-menu-link").classList.remove("active"); document.getElementById("bladeburner-menu-link").classList.remove("active");
document.getElementById("corporation-menu-link").classList.remove("active"); document.getElementById("corporation-menu-link").classList.remove("active");
document.getElementById("gang-menu-link").classList.remove("active"); document.getElementById("gang-menu-link").classList.remove("active");
// Close dev menu
closeDevMenu();
}, },
displayCharacterOverviewInfo: function() { displayCharacterOverviewInfo: function() {
Engine.overview.update(); Engine.overview.update();
const save = document.getElementById("character-overview-save-button"); const save = document.getElementById("character-overview-save-button");
const flashClass = "flashing-button"; const flashClass = "flashing-button";
if(!Settings.AutosaveInterval) { if(!Settings.AutosaveInterval) {
@ -844,43 +811,6 @@ const Engine = {
document.getElementById("tutorial-text").style.display = "none"; document.getElementById("tutorial-text").style.display = "none";
}, },
displayDevMenuContent: function() {
Engine.Clickables.devMenuGiveMoney.style.display = "block";
Engine.Clickables.devMenuGiveRam.style.display = "block";
Engine.Clickables.devMenuAugDropdown.style.display = "block";
Engine.Clickables.devMenuAddAug.style.display = "block";
Engine.Clickables.devMenuTriggerBitFlume.style.display = "block";
Engine.Clickables.devMenuFactionDropdown.style.display = "block";
Engine.Clickables.devMenuAddFaction.style.display = "block";
Engine.Clickables.devMenuOpen.style.display = "block";
Engine.Clickables.devMenuMinSecurity.style.display = "block";
Engine.Clickables.devMenuMaxMoney.style.display = "block";
Engine.Clickables.devMenuConnectDropdown.style.display = "block";
Engine.Clickables.devMenuConnect.style.display = "block";
Engine.Clickables.devMenuProgramsDropdown.style.display = "block";
Engine.Clickables.devMenuAddProgram.style.display = "block";
Engine.Clickables.devMenuHackingExp.style.display = "block";
Engine.Clickables.devMenuAddHacking.style.display = "block";
Engine.Clickables.devMenuStrengthExp.style.display = "block";
Engine.Clickables.devMenuAddStrength.style.display = "block";
Engine.Clickables.devMenuDefenseExp.style.display = "block";
Engine.Clickables.devMenuAddDefense.style.display = "block";
Engine.Clickables.devMenuDexterityExp.style.display = "block";
Engine.Clickables.devMenuAddDexterity.style.display = "block";
Engine.Clickables.devMenuAgilityExp.style.display = "block";
Engine.Clickables.devMenuAddAgility.style.display = "block";
Engine.Clickables.devMenuCharismaExp.style.display = "block";
Engine.Clickables.devMenuAddCharisma.style.display = "block";
Engine.Clickables.devMenuIntelligenceExp.style.display = "block";
Engine.Clickables.devMenuAddIntelligence.style.display = "block";
Engine.Clickables.devMenuEnableIntelligence.style.display = "block";
Engine.Clickables.devMenuDisableIntelligence.style.display = "block";
Engine.Clickables.devMenuSFN.style.display = "block";
Engine.Clickables.devMenuSFLvl.style.display = "block";
Engine.Clickables.devMenuAddSF.style.display = "block";
},
//Displays the text when a section of the Tutorial is opened //Displays the text when a section of the Tutorial is opened
displayTutorialPage: function(text) { displayTutorialPage: function(text) {
document.getElementById("tutorial-getting-started-link").style.display = "none"; document.getElementById("tutorial-getting-started-link").style.display = "none";
@ -958,7 +888,7 @@ const Engine = {
//Gang, if applicable //Gang, if applicable
if (Player.bitNodeN == 2 && Player.inGang()) { if (Player.bitNodeN == 2 && Player.inGang()) {
Player.gang.process(numCycles); Player.gang.process(numCycles, Player);
} }
//Mission //Mission
@ -1075,8 +1005,8 @@ const Engine = {
} }
if (Engine.Counters.updateDisplaysLong <= 0) { if (Engine.Counters.updateDisplaysLong <= 0) {
if (routing.isOn(Page.Gang)) { if (routing.isOn(Page.Gang) && Player.inGang()) {
updateGangContent(); Player.gang.updateGangContent();
} else if (routing.isOn(Page.ScriptEditor)) { } else if (routing.isOn(Page.ScriptEditor)) {
updateScriptEditorContent(); updateScriptEditorContent();
} }
@ -1383,7 +1313,7 @@ const Engine = {
//Gang progress for BitNode 2 //Gang progress for BitNode 2
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) { if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
Player.gang.process(numCyclesOffline); Player.gang.process(numCyclesOffline, Player);
} }
//Bladeburner offline progress //Bladeburner offline progress
@ -1525,9 +1455,6 @@ const Engine = {
Engine.Display.tutorialContent = document.getElementById("tutorial-container"); Engine.Display.tutorialContent = document.getElementById("tutorial-container");
Engine.Display.tutorialContent.style.display = "none"; Engine.Display.tutorialContent.style.display = "none";
Engine.Display.devMenuContent = document.getElementById("dev-menu-container");
Engine.Display.devMenuContent.style.display = "none";
Engine.Display.infiltrationContent = document.getElementById("infiltration-container"); Engine.Display.infiltrationContent = document.getElementById("infiltration-container");
Engine.Display.infiltrationContent.style.display = "none"; Engine.Display.infiltrationContent.style.display = "none";
@ -1614,190 +1541,6 @@ const Engine = {
Engine.Clickables.tutorialBackButton.addEventListener("click", function() { Engine.Clickables.tutorialBackButton.addEventListener("click", function() {
Engine.displayTutorialContent(); Engine.displayTutorialContent();
}); });
// dev menu buttons
Engine.Clickables.devMenuGiveMoney = document.getElementById("dev-need-money");
Engine.Clickables.devMenuGiveMoney.addEventListener("click", function() {
Player.gainMoney(1e15);
});
Engine.Clickables.devMenuGiveRam = document.getElementById("dev-need-ram");
Engine.Clickables.devMenuGiveRam.addEventListener("click", function() {
Player.getHomeComputer().maxRam *= 2;
});
Engine.Clickables.devMenuAugDropdown = document.getElementById("dev-menu-aug-dropdown");
const augDD = Engine.Clickables.devMenuAugDropdown;
for(const i in AugmentationNames) {
augDD.options[augDD.options.length] = new Option(AugmentationNames[i], AugmentationNames[i]);
}
Engine.Clickables.devMenuAddAug = document.getElementById("dev-add-aug");
Engine.Clickables.devMenuAddAug.addEventListener("click", function() {
Player.queueAugmentation(augDD.options[augDD.selectedIndex].value);
});
Engine.Clickables.devMenuTriggerBitFlume = document.getElementById("dev-bit-flume");
Engine.Clickables.devMenuTriggerBitFlume.addEventListener("click", function() {
hackWorldDaemon(Player.bitNodeN, true);
});
Engine.Clickables.devMenuFactionDropdown = document.getElementById("dev-menu-faction-dropdown");
const facDD = Engine.Clickables.devMenuFactionDropdown;
for(const i in Factions) {
facDD.options[facDD.options.length] = new Option(Factions[i].name, Factions[i].name);
}
Engine.Clickables.devMenuAddFaction = document.getElementById("dev-add-faction");
Engine.Clickables.devMenuAddFaction.addEventListener("click", function() {
const factionName = facDD.options[facDD.selectedIndex].value;
Player.receiveInvite(factionName);
});
Engine.Clickables.devMenuOpen = document.getElementById("dev-open-all");
Engine.Clickables.devMenuOpen.addEventListener("click", function() {
for(const i in AllServers) {
AllServers[i].hasAdminRights = true;
AllServers[i].sshPortOpen = true;
AllServers[i].ftpPortOpen = true;
AllServers[i].smtpPortOpen = true;
AllServers[i].httpPortOpen = true;
AllServers[i].sqlPortOpen = true;
AllServers[i].openPortCount = 5;
}
});
Engine.Clickables.devMenuMinSecurity = document.getElementById("dev-min-security");
Engine.Clickables.devMenuMinSecurity.addEventListener("click", function() {
for(const i in AllServers) {
AllServers[i].hackDifficulty = AllServers[i].minDifficulty;
}
});
Engine.Clickables.devMenuMaxMoney = document.getElementById("dev-max-money");
Engine.Clickables.devMenuMaxMoney.addEventListener("click", function() {
for(const i in AllServers) {
AllServers[i].moneyAvailable = AllServers[i].moneyMax;
}
});
Engine.Clickables.devMenuConnectDropdown = document.getElementById("dev-menu-connect-dropdown");
const connectDD = Engine.Clickables.devMenuConnectDropdown;
for(const i in AllServers) {
connectDD.options[connectDD.options.length] = new Option(AllServers[i].hostname, AllServers[i].hostname);
}
Engine.Clickables.devMenuConnect = document.getElementById("dev-connect");
Engine.Clickables.devMenuConnect.addEventListener("click", function() {
const host = connectDD.options[connectDD.selectedIndex].value;
Terminal.connectToServer(host);
});
Engine.Clickables.devMenuProgramsDropdown = document.getElementById("dev-menu-add-program-dropdown");
const programsDD = Engine.Clickables.devMenuProgramsDropdown;
for(const i in Programs) {
programsDD.options[programsDD.options.length] = new Option(Programs[i].name, Programs[i].name);
}
Engine.Clickables.devMenuAddProgram = document.getElementById("dev-add-program");
Engine.Clickables.devMenuAddProgram.addEventListener("click", function() {
const program = programsDD.options[programsDD.selectedIndex].value;
if(!Player.hasProgram(program)) {
Player.getHomeComputer().programs.push(program);
}
});
Engine.Clickables.devMenuHackingExp = document.getElementById("dev-hacking-exp");
Engine.Clickables.devMenuAddHacking = document.getElementById("dev-add-hacking");
Engine.Clickables.devMenuAddHacking.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuHackingExp.value);
Player.gainHackingExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuStrengthExp = document.getElementById("dev-strength-exp");
Engine.Clickables.devMenuAddStrength = document.getElementById("dev-add-strength");
Engine.Clickables.devMenuAddStrength.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuStrengthExp.value);
Player.gainStrengthExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuDefenseExp = document.getElementById("dev-defense-exp");
Engine.Clickables.devMenuAddDefense = document.getElementById("dev-add-defense");
Engine.Clickables.devMenuAddDefense.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuDefenseExp.value);
Player.gainDefenseExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuDexterityExp = document.getElementById("dev-dexterity-exp");
Engine.Clickables.devMenuAddDexterity = document.getElementById("dev-add-dexterity");
Engine.Clickables.devMenuAddDexterity.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuDexterityExp.value);
Player.gainDexterityExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuAgilityExp = document.getElementById("dev-agility-exp");
Engine.Clickables.devMenuAddAgility = document.getElementById("dev-add-agility");
Engine.Clickables.devMenuAddAgility.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuAgilityExp.value);
Player.gainAgilityExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuCharismaExp = document.getElementById("dev-charisma-exp");
Engine.Clickables.devMenuAddCharisma = document.getElementById("dev-add-charisma");
Engine.Clickables.devMenuAddCharisma.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuCharismaExp.value);
Player.gainCharismaExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuIntelligenceExp = document.getElementById("dev-intelligence-exp");
Engine.Clickables.devMenuAddIntelligence = document.getElementById("dev-add-intelligence");
Engine.Clickables.devMenuAddIntelligence.addEventListener("click", function() {
const exp = parseInt(Engine.Clickables.devMenuIntelligenceExp.value);
Player.gainIntelligenceExp(exp);
Player.updateSkillLevels();
});
Engine.Clickables.devMenuEnableIntelligence = document.getElementById("dev-enable-intelligence");
Engine.Clickables.devMenuEnableIntelligence.addEventListener("click", function() {
Player.intelligence = 1;
});
Engine.Clickables.devMenuDisableIntelligence = document.getElementById("dev-disable-intelligence");
Engine.Clickables.devMenuDisableIntelligence.addEventListener("click", function() {
Player.intelligence = 0;
});
Engine.Clickables.devMenuSFN = document.getElementById("dev-sf-n");
Engine.Clickables.devMenuSFLvl = document.getElementById("dev-sf-lvl");
Engine.Clickables.devMenuAddSF = document.getElementById("dev-add-source-file");
Engine.Clickables.devMenuAddSF.addEventListener("click", function() {
const sfN = parseInt(Engine.Clickables.devMenuSFN.value);
const sfLvl = parseInt(Engine.Clickables.devMenuSFLvl.value);
let sfIndex = -1;
for(const i in Player.sourceFiles) {
if(Player.sourceFiles[i].n === sfN) {
sfIndex = i;
break;
}
}
if(sfIndex === -1) { // add fresh source file
Player.sourceFiles.push(new PlayerOwnedSourceFile(sfN, sfLvl));
} else if(sfLvl === 0) { // remove a source file.
if(sfIndex === -1) { // doesn't have it anyway.
return;
}
Player.sourceFiles.splice(sfIndex, 1);
} else { // set source file level
Player.sourceFiles[sfIndex].lvl=sfLvl;
}
});
}, },
/* Initialization */ /* Initialization */
@ -1899,7 +1642,7 @@ const Engine = {
this.classList.toggle("opened"); this.classList.toggle("opened");
const elems = [tutorial, options]; const elems = [tutorial, options];
const links = [tutorialLink, optionsLink]; const links = [tutorialLink, optionsLink];
if(process.env.NODE_ENV === "development") { if (process.env.NODE_ENV === "development") {
elems.push(document.getElementById("dev-tab")); elems.push(document.getElementById("dev-tab"));
links.push(document.getElementById("dev-menu-link")); links.push(document.getElementById("dev-menu-link"));
} }

@ -490,58 +490,6 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<p id="tutorial-text"> </p> <p id="tutorial-text"> </p>
</div> </div>
<!-- dev menu -->
<div id="dev-menu-container" class="generic-menupage-container">
<p id="dev-menu-text">If you see this menu you can pretty much break the game. It's recommended that you use this menu only to setup a save file appropriate to test a new feature or bug fix.</p>
<p id="dev-menu-text">Generic</p>
<a id="dev-need-money" class="a-link-button">Add $1000t</a>
<a id="dev-need-ram" class="a-link-button">Double home RAM</a>
<p id="dev-menu-text">Augmentation related: </p>
<!-- gets populated with the list of all augments -->
<select id="dev-menu-aug-dropdown" class="dropdown"></select>
<a id="dev-add-aug" class="a-link-button tooltip">Queue Augmentation<span class="tooltiptext">May require save + reload</span></a>
<input id="dev-sf-n" type="number" class="text-input" placeholder="SourceFile-N"><input id="dev-sf-lvl" type="number" class="text-input" placeholder="SourceFile-Lvl"><a id="dev-add-source-file" class="a-link-button tooltip"> Add/Remove source file <span class="tooltiptext">If Lvl == 0 the sf will be removed, calling it with another level will replace your current source file. You CAN set a source file higher than it's maximum level.</span></a>
<p id="dev-menu-text">Faction related: </p>
<select id="dev-menu-faction-dropdown" class="dropdown"></select>
<a id="dev-add-faction" class="a-link-button tooltip">Receive invite<span class="tooltiptext">May require save + reload</span></a>
<p id="dev-menu-text">Program related: </p>
<select id="dev-menu-connect-dropdown" class="dropdown"></select>
<a id="dev-connect" class="a-link-button tooltip">Connect<span class="tooltiptext">Connect to the target server.</span></a>
<select id="dev-menu-add-program-dropdown" class="dropdown"></select>
<a id="dev-add-program" class="a-link-button tooltip">Add Program<span class="tooltiptext">Add this program to the player home server, won't add the same program twice.</span></a>
<a id="dev-bit-flume" class="a-link-button tooltip">Trigger BitFlume<span class="tooltiptext">Quick escape to change BN, does not give SFs</span></a>
<p id="dev-menu-text">Server related: </p>
<a id="dev-open-all" class="a-link-button tooltip">NUKE + ports all servers<span class="tooltiptext">Opens all ports, nukes all servers, gains root access to everything (still need the appropriate hacking level)</span></a>
<a id="dev-min-security" class="a-link-button tooltip">minimize all servers security<span class="tooltiptext">All servers security will be set to their minimum security</span></a>
<a id="dev-max-money" class="a-link-button tooltip">maximize all servers money<span class="tooltiptext">Set all servers available money to maximum for that server</span></a>
<p id="dev-menu-text">Exp/stats related: </p>
<input id="dev-hacking-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-hacking" class="a-link-button tooltip">add hacking exp<span class="tooltiptext">Add that many hacking experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-strength-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-strength" class="a-link-button tooltip">add strength exp<span class="tooltiptext">Add that many strength experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-defense-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-defense" class="a-link-button tooltip">add defense exp<span class="tooltiptext">Add that many defense experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-dexterity-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-dexterity" class="a-link-button tooltip">add dexterity exp<span class="tooltiptext">Add that many dexterity experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-agility-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-agility" class="a-link-button tooltip">add agility exp<span class="tooltiptext">Add that many agility experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-charisma-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-charisma" class="a-link-button tooltip">add charisma exp<span class="tooltiptext">Add that many charisma experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<input id="dev-intelligence-exp" type="number" class="text-input" placeholder="+exp/-exp (int)">
<a id="dev-add-intelligence" class="a-link-button tooltip">add intelligence exp<span class="tooltiptext">Add that many intelligence experience point, use negative numbers to remove, don't worry about going under 0 exp</span></a>
<a id="dev-enable-intelligence" class="a-link-button tooltip"> enable intelligence<span class="tooltiptext">Enables the intelligence stat</span></a>
<a id="dev-disable-intelligence" class="a-link-button tooltip"> disable intelligence<span class="tooltiptext">Disables the intelligence stat</span></a>
</div>
<!-- Location (visiting a location in World) --> <!-- Location (visiting a location in World) -->
<div id="location-container" class="generic-menupage-container"> <div id="location-container" class="generic-menupage-container">
<a id="location-return-to-world-button" class="a-link-button"> Return to World </a> <a id="location-return-to-world-button" class="a-link-button"> Return to World </a>

@ -65,7 +65,8 @@ function infiltrationBoxCreate(inst) {
var selector = document.getElementById("infiltration-faction-select"); var selector = document.getElementById("infiltration-faction-select");
selector.innerHTML = ""; selector.innerHTML = "";
for (let i = 0; i < Player.factions.length; ++i) { for (let i = 0; i < Player.factions.length; ++i) {
if (Player.factions[i] === "Bladeburners") {continue;} if (Player.factions[i] === "Bladeburners") { continue; }
if (Player.inGang() && Player.gang.facName === Player.factions[i]) { continue; }
selector.innerHTML += "<option value='" + Player.factions[i] + selector.innerHTML += "<option value='" + Player.factions[i] +
"'>" + Player.factions[i] + "</option>"; "'>" + Player.factions[i] + "</option>";
} }

@ -27,4 +27,6 @@ export const KEY: IMap<number> = {
U: 85, U: 85,
UPARROW: 38, UPARROW: 38,
W: 87, W: 87,
"1": 49,
"2": 50,
}; };

@ -66,6 +66,7 @@ interface ICreateElementStyleOptions {
interface ICreateElementTooltipOptions { interface ICreateElementTooltipOptions {
tooltip?: string; tooltip?: string;
tooltipleft?: string; tooltipleft?: string;
tooltipsmall?: string;
} }
/** /**
@ -216,6 +217,12 @@ function setElementTooltip(el: HTMLElement, params: ICreateElementTooltipOptions
class: "tooltiptextleft", class: "tooltiptextleft",
innerHTML: params.tooltipleft, innerHTML: params.tooltipleft,
})); }));
} else if (params.tooltipsmall !== undefined) {
el.className += " tooltip";
el.appendChild(createElement("span", {
class: "tooltiptext smallfont",
innerHTML: params.tooltipsmall,
}))
} }
} }