mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +02:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d96ad9fa6e | ||
|
|
5dd32ef4e4 | ||
|
|
6dde89f3c4 | ||
|
|
9a9d2e1f81 | ||
|
|
d347bf568e | ||
|
|
62e2f0582a | ||
|
|
68eb68a89e | ||
|
|
13206a8c3e | ||
|
|
8b7f140115 | ||
|
|
16c8c78b54 | ||
|
|
cbb47772db | ||
|
|
0642491402 | ||
|
|
c7e34d4a56 | ||
|
|
8be63be17b | ||
|
|
08207ac79b | ||
|
|
6747a509ff | ||
|
|
c7c86240db | ||
|
|
ce0c3d71f4 | ||
|
|
5bb6a72c90 | ||
|
|
5a06c60c27 | ||
|
|
764c2533b4 | ||
|
|
a9cee6f907 | ||
|
|
a10100bf60 | ||
|
|
cedac23dfa | ||
|
|
f7c1d64033 | ||
|
|
7d6d0eac32 | ||
|
|
34768591b7 | ||
|
|
827c79f70c | ||
|
|
0415c7aa7c | ||
|
|
0c744d98b9 | ||
|
|
11cbda6974 | ||
|
|
e284f49747 | ||
|
|
7777c400a5 | ||
|
|
dae0448744 | ||
|
|
02a4e85353 | ||
|
|
3cbf225c98 | ||
|
|
8006e976a5 | ||
|
|
5613d371c9 | ||
|
|
7c9d6669f7 | ||
|
|
c6f0551709 | ||
|
|
f57eed4de1 | ||
|
|
b99711788f | ||
|
|
08aac8e35d | ||
|
|
e3579b7229 | ||
|
|
662d0dd5fb | ||
|
|
77c40b5d67 | ||
|
|
ee759a8dd6 | ||
|
|
ad9c7ec696 | ||
|
|
b554328a77 | ||
|
|
c421c57e56 | ||
|
|
fb42d5cd79 | ||
|
|
6203d8d6f4 | ||
|
|
d422028737 | ||
|
|
136d769d55 | ||
|
|
daaab1d6f1 | ||
|
|
4f7befb639 | ||
|
|
9976ed136c | ||
|
|
8c2e661e08 | ||
|
|
e6e598eeb4 | ||
|
|
4d9439a007 | ||
|
|
9951c8b18f | ||
|
|
800c673839 | ||
|
|
065544909b | ||
|
|
4eaf68c940 | ||
|
|
a14a694df3 | ||
|
|
3ab61cbaf3 | ||
|
|
f49aff05d7 | ||
|
|
e2371a0ef6 | ||
|
|
6a2b3ee52e | ||
|
|
5a45e3584d | ||
|
|
56ce83cce5 | ||
|
|
d126b6d8c5 | ||
|
|
7172ef6dae | ||
|
|
a8d0b6e13d | ||
|
|
d2d6453a78 | ||
|
|
89cdecb05f | ||
|
|
81fdff9068 | ||
|
|
b2ac383b69 | ||
|
|
7df4aac8e6 |
4
dist/engine.bundle.js
vendored
4
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/engineStyle.bundle.js
vendored
2
dist/engineStyle.bundle.js
vendored
@@ -1,2 +1,2 @@
|
||||
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([840,0]),o()}({779:function(n,t,o){},781:function(n,t,o){},783:function(n,t,o){},785:function(n,t,o){},787:function(n,t,o){},789:function(n,t,o){},791:function(n,t,o){},793:function(n,t,o){},795:function(n,t,o){},797:function(n,t,o){},799:function(n,t,o){},801:function(n,t,o){},803:function(n,t,o){},805:function(n,t,o){},807:function(n,t,o){},809:function(n,t,o){},811:function(n,t,o){},813:function(n,t,o){},815:function(n,t,o){},817:function(n,t,o){},819:function(n,t,o){},821:function(n,t,o){},823:function(n,t,o){},825:function(n,t,o){},827:function(n,t,o){},829:function(n,t,o){},831:function(n,t,o){},833:function(n,t,o){},835:function(n,t,o){},837:function(n,t,o){},840:function(n,t,o){"use strict";o.r(t);o(839),o(837),o(835),o(833),o(831),o(829),o(827),o(825),o(823),o(821),o(819),o(817),o(815),o(813),o(811),o(809),o(807),o(805),o(803),o(801),o(799),o(797),o(795),o(793),o(791),o(789),o(787),o(785),o(783),o(781),o(779)}});
|
||||
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([841,0]),o()}({780:function(n,t,o){},782:function(n,t,o){},784:function(n,t,o){},786:function(n,t,o){},788:function(n,t,o){},790:function(n,t,o){},792:function(n,t,o){},794:function(n,t,o){},796:function(n,t,o){},798:function(n,t,o){},800:function(n,t,o){},802:function(n,t,o){},804:function(n,t,o){},806:function(n,t,o){},808:function(n,t,o){},810:function(n,t,o){},812:function(n,t,o){},814:function(n,t,o){},816:function(n,t,o){},818:function(n,t,o){},820:function(n,t,o){},822:function(n,t,o){},824:function(n,t,o){},826:function(n,t,o){},828:function(n,t,o){},830:function(n,t,o){},832:function(n,t,o){},834:function(n,t,o){},836:function(n,t,o){},838:function(n,t,o){},841:function(n,t,o){"use strict";o.r(t);o(840),o(838),o(836),o(834),o(832),o(830),o(828),o(826),o(824),o(822),o(820),o(818),o(816),o(814),o(812),o(810),o(808),o(806),o(804),o(802),o(800),o(798),o(796),o(794),o(792),o(790),o(788),o(786),o(784),o(782),o(780)}});
|
||||
//# sourceMappingURL=engineStyle.bundle.js.map
|
||||
38
dist/vendor.bundle.js
vendored
38
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -56,8 +56,3 @@ through destroying BitNodes is:
|
||||
|
||||
* Source-Files
|
||||
* Scripts on the home computer
|
||||
|
||||
BitNode Details
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
TODO
|
||||
|
||||
@@ -47,7 +47,7 @@ List of all Source-Files
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
| BitNode-9: Coming Soon | |
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
| BitNode-10: Digital Carbon | * Each level of this grants a Duplicate Sleeve |
|
||||
| BitNode-10: Digital Carbon | * Each level of this grants a Duplicate Sleeve. |
|
||||
| | * Allows the player to access the :ref:`netscript_sleeveapi` in other BitNodes |
|
||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||
| BitNode-11: The Big Crash | * Company favor increases both the player's salary and reputation gain at that |
|
||||
|
||||
@@ -3,6 +3,63 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
|
||||
v0.51.8 - 2021-05-07 It was there all along (hydroflame)
|
||||
--------------------------------------------------------
|
||||
|
||||
**Servers**
|
||||
|
||||
* Update n00dles metadata
|
||||
|
||||
**Netscript**
|
||||
|
||||
* 'hashGainRate' use the correct 'usedRam' and 'maxRam'
|
||||
* Fix 'setActionAutolevel' logging.
|
||||
* Fix 'setActionLevel' not working at all.
|
||||
* Add 'installBackdoor' singularity function.
|
||||
|
||||
**Hacknet**
|
||||
|
||||
* Fix Hacknet Servers total production always displaying 0
|
||||
|
||||
**Documentation**
|
||||
|
||||
* Updated guide to no longer recommend BN12.
|
||||
* Fix documentation for maxNumNodes (@ModdedGamers)
|
||||
* Fix typo in 'sourcefiles.rst'
|
||||
* Fix typo in 'recommendedbitnodeorder.rst'
|
||||
* Fix 'getServer' documentation missing 'server' argument.
|
||||
* Fix missing ram cost in 'getData.rst'
|
||||
* Fix basic formulas examples.
|
||||
* Fix typo in BN11 description.
|
||||
* Fix formatting issue in Bladeburner (@Pimgd)
|
||||
|
||||
**Misc.**
|
||||
|
||||
* Fix negative money being displayed in full.
|
||||
* Fix Hacking Missions not working.
|
||||
* Fix Corporation tree not rendering.
|
||||
* Fix script being needlessly recompiled. This should save real ram (not game ram)
|
||||
* w0r1d_d43m0n can be backdoored
|
||||
* Coding Contracts title is click-to-copy (@Rodeth)
|
||||
* Covenant memory upgrade works better.
|
||||
* Fix Neuroflux not being correctly calculated when entering BN with SF12.
|
||||
* Delete Active Script now delete all active scripts, not just home.
|
||||
* Now you can 'cd' in directories that only contain '.txt' files.
|
||||
* Fix 'analyze' always saying players had root access
|
||||
* Passive faction rep no longer builds for special factions.
|
||||
* Donation option no longer appears for special factions.
|
||||
* Rephrased some milestones.
|
||||
* donation textbox now accepts money in the format '1b' and the like (@Dawe)
|
||||
* Fix being able to join hated factions simultaneously. (@Dawe)
|
||||
* 'ls' now displays files in multiple column. (Helps players with many files)
|
||||
* Bladeburner multiplers now appear under Character>Stats and
|
||||
Character>Augmentation when they are relevant.
|
||||
* Fix missing functions syntax highlight in codemirror.
|
||||
* Fix infiltration number formatting.
|
||||
* script income transfers to parent on death. This helps keep track of
|
||||
income for scripts that spawn short lived scripts.
|
||||
|
||||
v0.51.7 - 2021-04-28 n00dles
|
||||
----------------------------
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# The short X.Y version.
|
||||
version = '0.51'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.51.7'
|
||||
release = '0.51.8'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -323,7 +323,7 @@ Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File unlocks Sleeve technology in other BitNodes.
|
||||
Each level of this Source-File also grants you a Duplicate Sleeve
|
||||
Each level of this Source-File also grants you a Duplicate Sleeve.
|
||||
|
||||
Difficulty
|
||||
Hard
|
||||
@@ -373,9 +373,10 @@ Description
|
||||
Source-File
|
||||
:Max Level: Infinity
|
||||
|
||||
Each level of Source-File 12 will increase all of your multipliers by 1%. This effect
|
||||
is multiplicative with itself. In other words, level N of this Source-File will result
|
||||
in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)
|
||||
Each level of Source-File 12 will let you start with Neuroflux Governor
|
||||
equal to the level of this Source-File.
|
||||
|
||||
This BitNode is meant to be done passively or when waiting for new content.
|
||||
|
||||
Difficulty
|
||||
Initially very easy, but then it (obviously) becomes harder as you continue to do it.
|
||||
@@ -396,27 +397,22 @@ For fast progression
|
||||
1. Repeat **BitNode-1: Source Genesis** until you max out its Source-File. Its Source-File
|
||||
is extremely powerful, as it raises all multipliers by a significant amount.
|
||||
|
||||
2. Repeat **BitNode-12: The Recursion** several times. This BitNode will be extremely easy the
|
||||
first few times you tackle it, and its Source-File raises all multipliers. Furthermore,
|
||||
its effect stacks multiplicatively with itself and other Source-Files/Augmentations,
|
||||
which gets better as time goes on
|
||||
|
||||
3. Do **BitNode-5: Artificial Intelligence** once or twice. The intelligence stat it unlocks
|
||||
2. Do **BitNode-5: Artificial Intelligence** once or twice. The intelligence stat it unlocks
|
||||
will gradually build up as you continue to play the game, and will be helpful
|
||||
in the future. The Source-File also provides hacking multipliers, which are
|
||||
strong because hacking is typically one of the best ways of earning money.
|
||||
|
||||
4. (Optional) Consider doing **BitNode-4: The Singularity**. Its Source-File does not directly make you
|
||||
3. (Optional) Consider doing **BitNode-4: The Singularity**. Its Source-File does not directly make you
|
||||
more powerful in any way, but it does unlock :ref:`netscript_singularityfunctions` which
|
||||
let you automate significantly more aspects of the game.
|
||||
|
||||
5. Do **BitNode-3: Corporatocracy** once to unlock the Corporation mechanic. This mechanic
|
||||
4. Do **BitNode-3: Corporatocracy** once to unlock the Corporation mechanic. This mechanic
|
||||
has high profit potential.
|
||||
|
||||
6. Do **BitNode-6: Bladeburners** once to unlock the Bladeburners mechanic. The Bladeburner
|
||||
5. Do **BitNode-6: Bladeburners** once to unlock the Bladeburners mechanic. The Bladeburner
|
||||
mechanic is useful for some of the future BitNodes (such as 9 and 10).
|
||||
|
||||
7. Do **BitNode-9: Hacktocracy** to unlock the Hacknet Server mechanic. You can
|
||||
6. Do **BitNode-9: Hacktocracy** to unlock the Hacknet Server mechanic. You can
|
||||
consider repeating it as well, as its Level 2 and 3 effects are pretty helpful as well.
|
||||
|
||||
.. todo:: To be continued as more BitNodes get added
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
getServer() Netscript Function
|
||||
==========================================
|
||||
|
||||
.. js:function:: getServer()
|
||||
.. js:function:: getServer([hostname])
|
||||
|
||||
:RAM cost: 4 GB
|
||||
:param string hostname: Hostname of the server, defaults to host server.
|
||||
|
||||
If you are not in BitNode-5, then you must have Source-File 5-1 in order to run this function.
|
||||
|
||||
|
||||
15
doc/source/netscript/basicfunctions/getServerMaxRam.rst
Normal file
15
doc/source/netscript/basicfunctions/getServerMaxRam.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
getServerMaxRam() Netscript Function
|
||||
====================================
|
||||
|
||||
.. js:function:: getServerMaxRam(hostname)
|
||||
|
||||
:RAM cost: 0.05 GB
|
||||
:param string hostname: Hostname of target server.
|
||||
:returns: Total ram available on that server. In GB.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
maxRam = getServerMaxRam("helios"); // returns: 16
|
||||
print("helios has "+maxRam + "GB");
|
||||
@@ -3,6 +3,8 @@ getServerRam() Netscript Function
|
||||
|
||||
.. js:function:: getServerRam(hostname)
|
||||
|
||||
.. warning:: This function is deprecated.
|
||||
|
||||
:RAM cost: 0.1 GB
|
||||
:param string hostname: Hostname of target server.
|
||||
:returns: An array of 2 number, first number is the total RAM, second the
|
||||
|
||||
15
doc/source/netscript/basicfunctions/getServerUsedRam.rst
Normal file
15
doc/source/netscript/basicfunctions/getServerUsedRam.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
getServerUsedRam() Netscript Function
|
||||
=====================================
|
||||
|
||||
.. js:function:: getServerUsedRam(hostname)
|
||||
|
||||
:RAM cost: 0.05 GB
|
||||
:param string hostname: Hostname of target server.
|
||||
:returns: Used ram on that server. In GB.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
usedRam = getServerUsedRam("harakiri-sushi"); // returns: 5.6
|
||||
print("harakiri-sushi uses "+usedRam + "GB");
|
||||
@@ -15,7 +15,8 @@ ps() Netscript Function
|
||||
{
|
||||
filename: Script name,
|
||||
threads: Number of threads script is running with,
|
||||
args: Script's arguments
|
||||
args: Script's arguments,
|
||||
pid: Script's pid
|
||||
}
|
||||
|
||||
Example:
|
||||
@@ -23,7 +24,8 @@ ps() Netscript Function
|
||||
.. code-block:: javascript
|
||||
|
||||
processes = ps("home");
|
||||
for (let i = 0; i < ps.length; ++i) {
|
||||
tprint(ps[i].filename + ' ' + ps[i].threads);
|
||||
tprint(ps[i].args);
|
||||
for (let i = 0; i < processes.length; ++i) {
|
||||
tprint(processes[i].filename + ' ' + processes[i].threads);
|
||||
tprint(processes[i].args);
|
||||
tprint(processes[i].pid);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ getData() Netscript Function
|
||||
|
||||
.. js:function:: getData(filename[, hostname=current hostname])
|
||||
|
||||
:RAM cost: 5 GB
|
||||
:param string filename: Filename of the contract
|
||||
:param string hostname: Hostname of the server containing the contract.
|
||||
Optional. Defaults to current server if not provided
|
||||
|
||||
@@ -20,4 +20,4 @@ growPercent() Netscript Function
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
tprint(growPercent(getServer(), 50, getPlayer()))
|
||||
tprint(formulas.basic.growPercent(getServer(), 50, getPlayer()))
|
||||
@@ -21,4 +21,4 @@ growTime() Netscript Function
|
||||
|
||||
server = getServer();
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
tprint(growTime(server, getPlayer()));
|
||||
tprint(formulas.basic.growTime(server, getPlayer()));
|
||||
@@ -21,4 +21,4 @@ hackChance() Netscript Function
|
||||
|
||||
server = getServer();
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
tprint(hackChance(server, getPlayer()));
|
||||
tprint(formulas.basic.hackChance(server, getPlayer()));
|
||||
@@ -21,4 +21,4 @@ hackExp() Netscript Function
|
||||
|
||||
server = getServer();
|
||||
server.hackDifficulty = 99.9;
|
||||
tprint(hackExp(server, getPlayer()));
|
||||
tprint(formulas.basic.hackExp(server, getPlayer()));
|
||||
@@ -22,4 +22,4 @@ hackPercent() Netscript Function
|
||||
|
||||
server = getServer();
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
tprint(hackPercent(server, getPlayer()));
|
||||
tprint(formulas.basic.hackPercent(server, getPlayer()));
|
||||
@@ -21,4 +21,4 @@ hackTime() Netscript Function
|
||||
|
||||
server = getServer();
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
tprint(hackTime(server, getPlayer()));
|
||||
tprint(formulas.basic.hackTime(server, getPlayer()));
|
||||
@@ -21,4 +21,4 @@ weakenTime() Netscript Function
|
||||
|
||||
server = getServer();
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
tprint(weakenTime(server, getPlayer()));
|
||||
tprint(formulas.basic.weakenTime(server, getPlayer()));
|
||||
@@ -1,11 +1,12 @@
|
||||
hashGainRate() Netscript Function
|
||||
==========================================
|
||||
|
||||
.. js:function:: hashGainRate(level, ram, core[, mult])
|
||||
.. js:function:: hashGainRate(level, ramUsed, maxRam, core[, mult])
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:param number level: level of the server.
|
||||
:param number ram: ram of the server.
|
||||
:param number ramUsed: ram used on the server.
|
||||
:param number maxRam: max ram of the server.
|
||||
:param number core: cores of the server.
|
||||
:returns: Money per second that a server with those stats would gain per second.
|
||||
|
||||
@@ -18,7 +19,7 @@ hashGainRate() Netscript Function
|
||||
.. code-block:: javascript
|
||||
|
||||
server = hacknet.getNodeStats(1);
|
||||
currentRate = formulas.hacknetNodes.hashGainRate(server.level, server.ram, server.cores);
|
||||
levelRate = formulas.hacknetNodes.hashGainRate(server.level+1, server.ram, server.cores);
|
||||
ramRate = formulas.hacknetNodes.hashGainRate(server.level, server.ram*2, server.cores);
|
||||
coresRate = formulas.hacknetNodes.hashGainRate(server.level, server.ram, server.cores+1);
|
||||
currentRate = formulas.hacknetNodes.hashGainRate(server.level, 0, server.ram, server.cores);
|
||||
levelRate = formulas.hacknetNodes.hashGainRate(server.level+1, 0, server.ram, server.cores);
|
||||
ramRate = formulas.hacknetNodes.hashGainRate(server.level, 0, server.ram*2, server.cores);
|
||||
coresRate = formulas.hacknetNodes.hashGainRate(server.level, 0, server.ram, server.cores+1);
|
||||
@@ -4,4 +4,4 @@ maxNumNodes() Netscript Function
|
||||
.. js:function:: maxNumNodes()
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:returns: Maximum number of Hacknet Nodes you can own.
|
||||
:returns: Maximum number of Hacknet Nodes you can own, unless you have not unlocked HackNet servers. Then, it returns Infinity.
|
||||
|
||||
@@ -54,7 +54,8 @@ This includes information such as function signatures, what they do, and their r
|
||||
getServerMinSecurityLevel() <basicfunctions/getServerMinSecurityLevel>
|
||||
getServerRequiredHackingLevel() <basicfunctions/getServerRequiredHackingLevel>
|
||||
getServerNumPortsRequired() <basicfunctions/getServerNumPortsRequired>
|
||||
getServerRam() <basicfunctions/getServerRam>
|
||||
getServerMaxRam() <basicfunctions/getServerMaxRam>
|
||||
getServerUsedRam() <basicfunctions/getServerUsedRam>
|
||||
serverExists() <basicfunctions/serverExists>
|
||||
fileExists() <basicfunctions/fileExists>
|
||||
isRunning() <basicfunctions/isRunning>
|
||||
@@ -90,3 +91,8 @@ This includes information such as function signatures, what they do, and their r
|
||||
wget() <basicfunctions/wget>
|
||||
getFavorToDonate() <basicfunctions/getFavorToDonate>
|
||||
flags() <basicfunctions/flags>
|
||||
|
||||
.. toctree::
|
||||
:caption: Deprecated:
|
||||
|
||||
getServerRam() <basicfunctions/getServerRam>
|
||||
@@ -86,7 +86,7 @@ The following is an example of one way a script can be used to automate the
|
||||
purchasing and upgrading of Hacknet Nodes.
|
||||
|
||||
This script attempts to purchase Hacknet Nodes until the player has a total of 8. Then
|
||||
it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 cores
|
||||
it gradually upgrades those Node's to a minimum of level 80, 16 GB RAM, and 8 cores
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
@@ -129,3 +129,16 @@ it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 c
|
||||
};
|
||||
|
||||
print("All nodes upgraded to 16GB RAM");
|
||||
|
||||
for (var i = 0; i < cnt; i++) {
|
||||
while (hacknet.getNodeStats(i).cores < 8) {
|
||||
var cost = hacknet.getCoreUpgradeCost(i, 1);
|
||||
while (myMoney() < cost) {
|
||||
print("Need $" + cost + " . Have $" + myMoney());
|
||||
sleep(3000);
|
||||
}
|
||||
res = hacknet.upgradeCore(i, 1);
|
||||
};
|
||||
};
|
||||
|
||||
print("All nodes upgraded to 8 cores");
|
||||
|
||||
@@ -27,6 +27,7 @@ level 3, then you will be able to access all of the Singularity Functions.
|
||||
getCurrentServer() <singularityfunctions/getCurrentServer>
|
||||
connect() <singularityfunctions/connect>
|
||||
manualHack() <singularityfunctions/manualHack>
|
||||
installBackdoor() <singularityfunctions/installBackdoor>
|
||||
getPlayer() <singularityfunctions/getPlayer>
|
||||
hospitalize() <singularityfunctions/hospitalize>
|
||||
isBusy() <singularityfunctions/isBusy>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
installBackdoor() Netscript Function
|
||||
====================================
|
||||
|
||||
.. js:function:: installBackdoor()
|
||||
|
||||
:RAM cost: 2 GB
|
||||
|
||||
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
|
||||
|
||||
This function will install a backdoor on the server you are currently connected to.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
connect("foodnstuff");
|
||||
installBackdoor();
|
||||
|
||||
.. warning::
|
||||
For NS2 users:
|
||||
|
||||
This function is async.
|
||||
10
index.html
10
index.html
@@ -327,8 +327,8 @@
|
||||
Would you like to join? <br/> <br/>
|
||||
Warning: Joining this faction may prevent you from joining other factions during this run!
|
||||
</p>
|
||||
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
|
||||
<button id="faction-invitation-box-no" class="popup-box-button"> No </button>
|
||||
<button id="faction-invitation-box-yes" class="popup-box-button"> Join! </button>
|
||||
<button id="faction-invitation-box-no" class="popup-box-button"> Decide later </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -587,14 +587,14 @@
|
||||
Copy Save data to Clipboard
|
||||
</button>
|
||||
<button id="debug-delete-scripts-link" class="a-link-button tooltip">
|
||||
(DEBUG) Delete Active Scripts
|
||||
Delete all active scripts
|
||||
<span class="tooltiptextleft">
|
||||
Debug option used to forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After
|
||||
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After
|
||||
using this, save the game and then reload the page.
|
||||
</span>
|
||||
</button>
|
||||
<button id="debug-soft-reset" class="a-link-button tooltip">
|
||||
(DEBUG) Soft Reset
|
||||
Soft Reset
|
||||
<span class="tooltiptextleft">
|
||||
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
|
||||
</span>
|
||||
|
||||
@@ -124,5 +124,5 @@
|
||||
"watch": "webpack --watch --mode production",
|
||||
"watch:dev": "webpack --watch --mode development"
|
||||
},
|
||||
"version": "0.51.7"
|
||||
"version": "0.51.8"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Factions } from "../Faction/Factions";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
interface IConstructorParams {
|
||||
info: string;
|
||||
info: string | JSX.Element;
|
||||
isSpecial?: boolean;
|
||||
moneyCost: number;
|
||||
name: string;
|
||||
@@ -57,7 +57,7 @@ export class Augmentation {
|
||||
baseRepRequirement = 0;
|
||||
|
||||
// Description of what this Aug is and what it does
|
||||
info = "";
|
||||
info: string | JSX.Element;
|
||||
|
||||
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
|
||||
isSpecial = false;
|
||||
|
||||
@@ -60,7 +60,7 @@ function initAugmentations() {
|
||||
"This augmentation increases the player's dexterity by 10%.",
|
||||
dexterity_mult: 1.1,
|
||||
});
|
||||
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
|
||||
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Ishima",
|
||||
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
|
||||
if (augmentationExists(AugmentationNames.Targeting1)) {
|
||||
delete Augmentations[AugmentationNames.Targeting1];
|
||||
@@ -75,7 +75,7 @@ function initAugmentations() {
|
||||
prereqs:[AugmentationNames.Targeting1],
|
||||
dexterity_mult: 1.2,
|
||||
});
|
||||
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
|
||||
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12",
|
||||
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
|
||||
if (augmentationExists(AugmentationNames.Targeting2)) {
|
||||
delete Augmentations[AugmentationNames.Targeting2];
|
||||
@@ -136,7 +136,7 @@ function initAugmentations() {
|
||||
strength_mult: 1.1,
|
||||
defense_mult: 1.1,
|
||||
});
|
||||
CombatRib1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
|
||||
CombatRib1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Volhaven", "Ishima",
|
||||
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
|
||||
if (augmentationExists(AugmentationNames.CombatRib1)) {
|
||||
delete Augmentations[AugmentationNames.CombatRib1];
|
||||
@@ -152,7 +152,7 @@ function initAugmentations() {
|
||||
strength_mult: 1.14,
|
||||
defense_mult: 1.14,
|
||||
});
|
||||
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
|
||||
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Volhaven",
|
||||
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
|
||||
if (augmentationExists(AugmentationNames.CombatRib2)) {
|
||||
delete Augmentations[AugmentationNames.CombatRib2];
|
||||
@@ -428,7 +428,7 @@ function initAugmentations() {
|
||||
"This augmentation increases the player's hacking speed by 3%.",
|
||||
hacking_speed_mult: 1.03,
|
||||
});
|
||||
SynapticEnhancement.addToFactions(["CyberSec"]);
|
||||
SynapticEnhancement.addToFactions(["CyberSec", "Aevum"]);
|
||||
if (augmentationExists(AugmentationNames.SynapticEnhancement)) {
|
||||
delete Augmentations[AugmentationNames.SynapticEnhancement];
|
||||
}
|
||||
@@ -756,7 +756,7 @@ function initAugmentations() {
|
||||
"when working for a company by 20%.",
|
||||
company_rep_mult: 1.2,
|
||||
});
|
||||
NuoptimalInjectorImplant.addToFactions(["Tian Di Hui", "Volhaven", "New Tokyo", "Chongqing", "Ishima",
|
||||
NuoptimalInjectorImplant.addToFactions(["Tian Di Hui", "Volhaven", "New Tokyo", "Chongqing",
|
||||
"Clarke Incorporated", "Four Sigma", "Bachman & Associates"]);
|
||||
if (augmentationExists(AugmentationNames.NuoptimalInjectorImplant)) {
|
||||
delete Augmentations[AugmentationNames.NuoptimalInjectorImplant];
|
||||
@@ -1064,7 +1064,7 @@ function initAugmentations() {
|
||||
agility_exp_mult: 1.1,
|
||||
charisma_exp_mult: 1.1,
|
||||
});
|
||||
Neurotrainer1.addToFactions(["CyberSec"]);
|
||||
Neurotrainer1.addToFactions(["CyberSec", "Aevum"]);
|
||||
if (augmentationExists(AugmentationNames.Neurotrainer1)) {
|
||||
delete Augmentations[AugmentationNames.Neurotrainer1];
|
||||
}
|
||||
|
||||
@@ -44,6 +44,18 @@ export function PlayerMultipliers(): React.ReactElement {
|
||||
</table>
|
||||
}
|
||||
|
||||
function BladeburnerMults(): React.ReactElement {
|
||||
if(!Player.canAccessBladeburner()) return (<></>);
|
||||
return (<>
|
||||
{MultiplierTable([
|
||||
['Bladeburner Success Chance', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
|
||||
['Bladeburner Max Stamina', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
|
||||
['Bladeburner Stamina Gain', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
|
||||
['Bladeburner Field Analysis', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
|
||||
])}<br />
|
||||
</>);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p><strong><u>Multipliers:</u></strong></p><br />
|
||||
@@ -103,6 +115,8 @@ export function PlayerMultipliers(): React.ReactElement {
|
||||
['Crime success ', Player.crime_success_mult, Player.crime_success_mult*mults.crime_success_mult],
|
||||
['Crime money ', Player.crime_money_mult, Player.crime_money_mult*mults.crime_money_mult],
|
||||
])}<br />
|
||||
|
||||
<BladeburnerMults />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
|
||||
"The growth rate of servers is significantly reduced<br>" +
|
||||
"Weakening a server is twice as effective<br>" +
|
||||
"Company wages are decreased by 50%<br>" +
|
||||
"Corporation valuations are 99% lower and are therefore significantly less profitable<br>" +
|
||||
"Corporation valuations are 90% lower and are therefore significantly less profitable<br>" +
|
||||
"Hacknet Node production is significantly decreased<br>" +
|
||||
"Crime and Infiltration are more lucrative<br>" +
|
||||
"Augmentations are twice as expensive<br><br>" +
|
||||
@@ -236,8 +236,7 @@ BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
||||
"To iterate is human, to recurse divine.<br><br>" +
|
||||
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you Source-File 12, or " +
|
||||
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
|
||||
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
|
||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||
"of Source-File 12 lets you start any BitNodes with NeuroFlux Governor equal to the level of this source file.");
|
||||
// Books: Frontera, Shiner
|
||||
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
|
||||
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
|
||||
|
||||
@@ -736,7 +736,7 @@ Bladeburner.prototype.completeAction = function() {
|
||||
}
|
||||
}
|
||||
var logLossText = "";
|
||||
if (loss > 0) {logLossText += "Lost " + formatNumber(loss, 3) + " rank.";}
|
||||
if (loss > 0) {logLossText += "Lost " + formatNumber(loss, 3) + " rank. ";}
|
||||
if (damage > 0) {logLossText += "Took " + formatNumber(damage, 0) + " damage.";}
|
||||
if (isOperation && this.logging.ops) {
|
||||
this.log(action.name + " failed! " + logLossText);
|
||||
|
||||
@@ -160,7 +160,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
|
||||
"technology in Operation K, we've discovered that a small group of " +
|
||||
"MK-VI Synthoids were able to make off with the schematics and design " +
|
||||
"of the technology before the Operation. It is almost a certainty that " +
|
||||
"these Synthoids are some of the rogue MK-VI ones from the Synthoid Uprising." +
|
||||
"these Synthoids are some of the rogue MK-VI ones from the Synthoid Uprising.<br><br>" +
|
||||
"The goal of Operation Deckard is to hunt down these Synthoids and retire " +
|
||||
"them. I don't need to tell you how critical this mission is.",
|
||||
baseDifficulty:20e3, reqdRank:40e3,
|
||||
@@ -231,7 +231,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
|
||||
"means that the supercomputer may be able to reason abstractly " +
|
||||
"and become self-aware.<br><br>" +
|
||||
"I do not need to remind you why sentient-level AIs pose a serious " +
|
||||
"thread to all of mankind.<br><br>" +
|
||||
"threat to all of mankind.<br><br>" +
|
||||
"The research for this project is being conducted at one of Fulcrum " +
|
||||
"Technologies secret facilities in Aevum, codenamed 'Alpha Ranch'. " +
|
||||
"Infiltrate the compound, delete and destroy the work, and then find and kill the " +
|
||||
@@ -342,4 +342,4 @@ export const BlackOperations: IMap<BlackOperation> = {};
|
||||
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
|
||||
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
|
||||
});
|
||||
})()
|
||||
})()
|
||||
|
||||
@@ -14,8 +14,10 @@ import {
|
||||
} from "../utils/JSONReviver";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { createPopup, removePopup } from "./ui/React/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
import { CodingContractPopup } from "./ui/React/CodingContractPopup";
|
||||
|
||||
|
||||
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
||||
|
||||
@@ -171,57 +173,26 @@ export class CodingContract {
|
||||
* Creates a popup to prompt the player to solve the problem
|
||||
*/
|
||||
async prompt(): Promise<CodingContractResult> {
|
||||
// tslint:disable-next-line
|
||||
return new Promise<CodingContractResult>((resolve) => {
|
||||
const contractType: CodingContractType = CodingContractTypes[this.type];
|
||||
const popupId = `coding-contract-prompt-popup-${this.fn}`;
|
||||
const title: HTMLElement = createElement("h1", {
|
||||
innerHTML: this.type,
|
||||
});
|
||||
const txt: HTMLElement = createElement("p", {
|
||||
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
||||
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
||||
"after which the contract will self-destruct.<br><br>",
|
||||
`${contractType.desc(this.data).replace(/\n/g, "<br>")}`].join(" "),
|
||||
});
|
||||
let solveBtn: HTMLElement;
|
||||
const cancelBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
clickListener: () => {
|
||||
const popupId = `coding-contract-prompt-popup-${this.fn}`;
|
||||
return new Promise<CodingContractResult>((resolve, reject) => {
|
||||
let popup = new CodingContractPopup({
|
||||
c: this,
|
||||
popupId: popupId,
|
||||
onClose: () => {
|
||||
resolve(CodingContractResult.Cancelled);
|
||||
removeElementById(popupId);
|
||||
removePopup(popupId);
|
||||
},
|
||||
innerText: "Cancel",
|
||||
});
|
||||
const answerInput = createElement("input", {
|
||||
onkeydown: (e: any) => {
|
||||
if (e.keyCode === KEY.ENTER && answerInput.value !== "") {
|
||||
e.preventDefault();
|
||||
solveBtn.click();
|
||||
} else if (e.keyCode === KEY.ESC) {
|
||||
e.preventDefault();
|
||||
cancelBtn.click();
|
||||
}
|
||||
},
|
||||
placeholder: "Enter Solution here",
|
||||
width: "50%",
|
||||
}) as HTMLInputElement;
|
||||
solveBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
clickListener: () => {
|
||||
const answer: string = answerInput.value;
|
||||
if (this.isSolution(answer)) {
|
||||
onAttempt: (val: string) => {
|
||||
console.log(`top; ${val}`);
|
||||
if (this.isSolution(val)) {
|
||||
resolve(CodingContractResult.Success);
|
||||
} else {
|
||||
resolve(CodingContractResult.Failure);
|
||||
}
|
||||
removeElementById(popupId);
|
||||
},
|
||||
innerText: "Solve",
|
||||
removePopup(popupId);
|
||||
}
|
||||
});
|
||||
const lineBreak: HTMLElement = createElement("br");
|
||||
createPopup(popupId, [title, lineBreak, txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
||||
answerInput.focus();
|
||||
createPopup(popupId, CodingContractPopup, popup.props);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IMap } from "./types";
|
||||
|
||||
export const CONSTANTS: IMap<any> = {
|
||||
Version: "0.51.7",
|
||||
Version: "0.51.8",
|
||||
|
||||
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
||||
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
||||
@@ -228,61 +228,60 @@ export const CONSTANTS: IMap<any> = {
|
||||
|
||||
LatestUpdate:
|
||||
`
|
||||
v0.51.7 - 2021-04-28 n00dles
|
||||
v0.51.8 - 2021-05-07 It was there all along (hydroflame)
|
||||
-------
|
||||
|
||||
Tutorial servers
|
||||
|
||||
* All the tutorial servers have been reverted to their original value
|
||||
* The new server n00dles has been added as tutorial server.
|
||||
Servers
|
||||
|
||||
Terminal
|
||||
|
||||
* 'tail' now accepts Pid.
|
||||
* 'analyze' now handles Hacknet Servers correctly.
|
||||
* 'ServerProfiler.exe' now handles Hacknet Servers correctly.
|
||||
|
||||
SF12
|
||||
|
||||
* Now makes you start with Neuroflux Governor equal to the level of the SF.
|
||||
* Update n00dles metadata
|
||||
|
||||
Netscript
|
||||
|
||||
* Deprecated 'getServerRam'.
|
||||
* 'getServerMaxRam' added to replace 'getServerRam'
|
||||
* 'getServerUsedRam' added to replace 'getServerRam'
|
||||
* 'getBitnodeMultipliers' is available inside BN5
|
||||
* Time logged by hack/grow/weaken now displays in human time.
|
||||
* thread count logged by hack/grow/weaken now displays with commas every
|
||||
thousands place.
|
||||
* 'hashGainRate' use the correct 'usedRam' and 'maxRam'
|
||||
* Fix 'setActionAutolevel' logging.
|
||||
* Fix 'setActionLevel' not working at all.
|
||||
* Add 'installBackdoor' singularity function.
|
||||
|
||||
Donation
|
||||
Hacknet
|
||||
|
||||
* Always visible but locked until favor requirements are reached.
|
||||
* Fix Hacknet Servers total production always displaying 0
|
||||
|
||||
Augmentations
|
||||
Documentation
|
||||
|
||||
* City factions has been rebalanced to give a reason to visit them all.
|
||||
|
||||
Sleeves
|
||||
|
||||
* Fix sleeves not being able to work at Volhavens gym.
|
||||
|
||||
Lint
|
||||
|
||||
* This shouldn't change anything but was like 10h of work.
|
||||
* Updated guide to no longer recommend BN12.
|
||||
* Fix documentation for maxNumNodes (@ModdedGamers)
|
||||
* Fix typo in 'sourcefiles.rst'
|
||||
* Fix typo in 'recommendedbitnodeorder.rst'
|
||||
* Fix 'getServer' documentation missing 'server' argument.
|
||||
* Fix missing ram cost in 'getData.rst'
|
||||
* Fix basic formulas examples.
|
||||
* Fix typo in BN11 description.
|
||||
* Fix formatting issue in Bladeburner (@Pimgd)
|
||||
|
||||
Misc.
|
||||
|
||||
* Plethora of typo fixed (@Pimgd)
|
||||
* ps documentation fix (@Dawe)
|
||||
* The dev menu now has a quick bitflume option.
|
||||
* Fix SF -1 not being as powerful as intended.
|
||||
* Fix cashroot starter kit not displaying correctly.
|
||||
* Fix DOM element 'character-overview-text' being nested twice.
|
||||
* Hacknet documentation example fix.
|
||||
* Money amount under 1000 dont display 3 decimal anymore.
|
||||
* Fix nextSourceFile flag miscalculation on the bitverse (for Bn12)
|
||||
* Faction invite text says "Decide later"/"Join!" instead of "No"/"Yes"
|
||||
* Fix negative money being displayed in full.
|
||||
* Fix Hacking Missions not working.
|
||||
* Fix Corporation tree not rendering.
|
||||
* Fix script being needlessly recompiled. This should save real ram (not game ram)
|
||||
* w0r1d_d43m0n can be backdoored
|
||||
* Coding Contracts title is click-to-copy (@Rodeth)
|
||||
* Covenant memory upgrade works better.
|
||||
* Fix Neuroflux not being correctly calculated when entering BN with SF12.
|
||||
* Delete Active Script now delete all active scripts, not just home.
|
||||
* Now you can 'cd' in directories that only contain '.txt' files.
|
||||
* Fix 'analyze' always saying players had root access
|
||||
* Passive faction rep no longer builds for special factions.
|
||||
* Donation option no longer appears for special factions.
|
||||
* Rephrased some milestones.
|
||||
* donation textbox now accepts money in the format '1b' and the like (@Dawe)
|
||||
* Fix being able to join hated factions simultaneously. (@Dawe)
|
||||
* 'ls' now displays files in multiple column. (Helps players with many files)
|
||||
* Bladeburner multiplers now appear under Character>Stats and
|
||||
Character>Augmentation when they are relevant.
|
||||
* Fix missing functions syntax highlight in codemirror.
|
||||
* Fix infiltration number formatting.
|
||||
* script income transfers to parent on death. This helps keep track of
|
||||
income for scripts that spawn short lived scripts.
|
||||
`,
|
||||
}
|
||||
@@ -1365,6 +1365,11 @@ Industry.prototype.createResearchBox = function() {
|
||||
},
|
||||
}
|
||||
|
||||
// Construct the tree with Treant
|
||||
// This is required for side effect.
|
||||
// eslint-disable-next-line no-new
|
||||
new Treant(markup);
|
||||
|
||||
// Add Event Listeners for all Nodes
|
||||
const allResearch = researchTree.getAllNodes();
|
||||
for (let i = 0; i < allResearch.length; ++i) {
|
||||
|
||||
@@ -60,7 +60,7 @@ export class Overview extends BaseReactComponent {
|
||||
|
||||
let txt = "Total Funds: " + numeralWrapper.format(this.corp().funds.toNumber(), '$0.000a') + "<br>" +
|
||||
"Total Revenue: " + numeralWrapper.format(this.corp().revenue.toNumber(), "$0.000a") + " / s<br>" +
|
||||
"Total Expenses: " + numeralWrapper.format(this.corp().expenses.toNumber(), "$0.000a") + "/ s<br>" +
|
||||
"Total Expenses: " + numeralWrapper.format(this.corp().expenses.toNumber(), "$0.000a") + " / s<br>" +
|
||||
"Total Profits: " + profitStr + " / s<br>" +
|
||||
dividendStr +
|
||||
"Publicly Traded: " + (this.corp().public ? "Yes" : "No") + "<br>" +
|
||||
|
||||
@@ -135,6 +135,10 @@ class DevMenuComponent extends Component {
|
||||
Player.getHomeComputer().maxRam *= 2;
|
||||
}
|
||||
|
||||
quickB1tFlum3() {
|
||||
hackWorldDaemon(Player.bitNodeN, true, true);
|
||||
}
|
||||
|
||||
b1tflum3() {
|
||||
hackWorldDaemon(Player.bitNodeN, true);
|
||||
}
|
||||
@@ -705,7 +709,8 @@ class DevMenuComponent extends Component {
|
||||
<button className="std-button" onClick={this.upgradeRam}>Upgrade Home Computer's RAM</button>
|
||||
</div>
|
||||
<div className="row">
|
||||
<button className="std-button" onClick={this.b1tflum3}>Run bit_flum3.exe</button>
|
||||
<button className="std-button" onClick={this.quickB1tFlum3}>Quick b1t_flum3.exe</button>
|
||||
<button className="std-button" onClick={this.b1tflum3}>Run b1t_flum3.exe</button>
|
||||
<button className="std-button" onClick={this.hackW0r1dD43m0n}>Hack w0rld_d34m0n</button>
|
||||
</div>
|
||||
<div className="row">
|
||||
|
||||
@@ -4,8 +4,8 @@ export function applyExploit(): void {
|
||||
if (Player.exploits && Player.exploits.length === 0) {
|
||||
return;
|
||||
}
|
||||
const inc = Math.pow(1.0001, Player.exploits.length);
|
||||
const dec = Math.pow(0.9999, Player.exploits.length);
|
||||
const inc = Math.pow(1.001, Player.exploits.length);
|
||||
const dec = Math.pow(0.999, Player.exploits.length);
|
||||
|
||||
Player.hacking_chance_mult *= inc;
|
||||
Player.hacking_speed_mult *= inc;
|
||||
|
||||
@@ -56,6 +56,12 @@ export function joinFaction(faction) {
|
||||
Factions[enemy].isBanned = true;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < Player.factionInvitations.length; ++i) {
|
||||
if (Player.factionInvitations[i] == faction.name || Factions[Player.factionInvitations[i]].isBanned) {
|
||||
Player.factionInvitations.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function startHackingMission(faction) {
|
||||
@@ -238,6 +244,11 @@ export function processPassiveFactionRepGain(numCycles) {
|
||||
if (!Factions.hasOwnProperty(name)) continue;
|
||||
const faction = Factions[name];
|
||||
if (!faction.isMember) continue;
|
||||
// No passive rep for special factions
|
||||
const info = faction.getInfo();
|
||||
if(!info.offersWork()) continue;
|
||||
// No passive rep for gangs.
|
||||
if(Player.getGangName() === name) continue;
|
||||
// 0 favor = 1%/s
|
||||
// 50 favor = 6%/s
|
||||
// 100 favor = 11%/s
|
||||
|
||||
@@ -57,6 +57,13 @@ export class FactionInfo {
|
||||
this.augmentationPriceMult = 1;
|
||||
this.augmentationRepRequirementMult = 1;
|
||||
}
|
||||
|
||||
offersWork(): boolean {
|
||||
return this.offerFieldWork ||
|
||||
this.offerHackingMission ||
|
||||
this.offerHackingWork ||
|
||||
this.offerSecurityWork;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,10 +12,14 @@ import { Reputation } from "../../ui/React/Reputation";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
disabled: boolean;
|
||||
favorToDonate: number;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
@@ -36,9 +40,10 @@ export class DonateOption extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
|
||||
this.state = {
|
||||
donateAmt: 0,
|
||||
status: <></>,
|
||||
status: props.disabled ? <>Unlocked at {props.favorToDonate} favor with {props.faction.name}</> : <></>,
|
||||
}
|
||||
|
||||
this.calculateRepGain = this.calculateRepGain.bind(this);
|
||||
@@ -70,7 +75,7 @@ export class DonateOption extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
handleChange(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const amt = parseFloat(e.target.value);
|
||||
const amt = numeralWrapper.parseMoney(e.target.value);
|
||||
|
||||
if (isNaN(amt)) {
|
||||
this.setState({
|
||||
@@ -90,10 +95,17 @@ export class DonateOption extends React.Component<IProps, IState> {
|
||||
return (
|
||||
<div className={"faction-work-div"}>
|
||||
<div className={"faction-work-div-wrapper"}>
|
||||
<input className="text-input" onChange={this.handleChange} placeholder={"Donation amount"} style={inputStyleMarkup} />
|
||||
<input
|
||||
className="text-input"
|
||||
onChange={this.handleChange}
|
||||
placeholder={"Donation amount"}
|
||||
style={inputStyleMarkup}
|
||||
disabled={this.props.disabled}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.donate}
|
||||
text={"Donate Money"}
|
||||
disabled={this.props.disabled}
|
||||
/>
|
||||
<p style={this.blockStyle}>{this.state.status}</p>
|
||||
</div>
|
||||
|
||||
@@ -264,11 +264,13 @@ export class FactionRoot extends React.Component<IProps, IState> {
|
||||
/>
|
||||
}
|
||||
{
|
||||
(!isPlayersGang && canDonate) &&
|
||||
!isPlayersGang && factionInfo.offersWork() &&
|
||||
<DonateOption
|
||||
faction={this.props.faction}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
favorToDonate={favorToDonate}
|
||||
disabled={!canDonate}
|
||||
/>
|
||||
}
|
||||
<Option
|
||||
|
||||
@@ -421,7 +421,9 @@ function processAllHacknetServerEarnings(numCycles) {
|
||||
// Also, update the hash rate before processing
|
||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
||||
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
||||
hashes += hserver.process(numCycles);
|
||||
const h = hserver.process(numCycles);
|
||||
hserver.totalHashesGenerated += h;
|
||||
hashes += h;
|
||||
}
|
||||
|
||||
Player.hashManager.storeHashes(hashes);
|
||||
|
||||
@@ -30,7 +30,7 @@ export const Milestones: Milestone[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Join the faction hinted at in j1.msg",
|
||||
title: "Join the faction hinted at in csec-test.msg",
|
||||
fulfilled: (p: IPlayer): boolean => {
|
||||
return p.factions.includes("CyberSec");
|
||||
},
|
||||
@@ -42,7 +42,7 @@ export const Milestones: Milestone[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Join the faction hinted at in j2.msg",
|
||||
title: "Join the faction hinted at in nitesec-test.msg",
|
||||
fulfilled: (p: IPlayer): boolean => {
|
||||
return p.factions.includes("NiteSec");
|
||||
},
|
||||
@@ -66,7 +66,7 @@ export const Milestones: Milestone[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Join the faction hinted at in j4.msg",
|
||||
title: "Join the faction hinted at in 19dfj3l1nd.msg",
|
||||
fulfilled: (p: IPlayer): boolean => {
|
||||
return p.factions.includes("BitRunners");
|
||||
},
|
||||
@@ -78,8 +78,9 @@ export const Milestones: Milestone[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Join the final faction",
|
||||
title: "Complete fl1ght.exe",
|
||||
fulfilled: (p: IPlayer): boolean => {
|
||||
// technically wrong but whatever
|
||||
return p.factions.includes("Daedalus");
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,6 +13,11 @@ import { isString } from "../utils/helpers/isString";
|
||||
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
|
||||
// For some reason `jsplumb` needs to be imported exactly like this,
|
||||
// lowercase p, and later in the code used as `jsPlumb` uppercase P. wtf.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import jsplumb from "jsplumb";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
@@ -822,7 +827,7 @@ HackingMission.prototype.updateNodeDomElement = function(nodeObj) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Node DOM element's corresponding Node object using its
|
||||
* Gets a Node DOM elements corresponding Node object using its
|
||||
* element id. Function accepts either the DOM element object or the ID as
|
||||
* an argument
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,8 @@ export const RamCostConstants: IMap<number> = {
|
||||
ScriptGetHackingLevelRamCost: 0.05,
|
||||
ScriptGetMultipliersRamCost: 4.0,
|
||||
ScriptGetServerRamCost: 0.1,
|
||||
ScriptGetServerMaxRam: 0.05,
|
||||
ScriptGetServerUsedRam: 0.05,
|
||||
ScriptFileExistsRamCost: 0.1,
|
||||
ScriptIsRunningRamCost: 0.1,
|
||||
ScriptHacknetNodesRamCost: 4.0,
|
||||
@@ -122,6 +124,8 @@ export const RamCosts: IMap<any> = {
|
||||
getServerGrowth: () => RamCostConstants.ScriptGetServerRamCost,
|
||||
getServerNumPortsRequired: () => RamCostConstants.ScriptGetServerRamCost,
|
||||
getServerRam: () => RamCostConstants.ScriptGetServerRamCost,
|
||||
getServerMaxRam: () => RamCostConstants.ScriptGetServerMaxRam,
|
||||
getServerUsedRam: () => RamCostConstants.ScriptGetServerUsedRam,
|
||||
serverExists: () => RamCostConstants.ScriptGetServerRamCost,
|
||||
fileExists: () => RamCostConstants.ScriptFileExistsRamCost,
|
||||
isRunning: () => RamCostConstants.ScriptIsRunningRamCost,
|
||||
@@ -182,6 +186,7 @@ export const RamCosts: IMap<any> = {
|
||||
getCurrentServer: () => RamCostConstants.ScriptSingularityFn1RamCost,
|
||||
connect: () => RamCostConstants.ScriptSingularityFn1RamCost,
|
||||
manualHack: () => RamCostConstants.ScriptSingularityFn1RamCost,
|
||||
installBackdoor: () => RamCostConstants.ScriptSingularityFn1RamCost,
|
||||
getStats: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||
getCharacterInformation: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||
getPlayer: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||
|
||||
@@ -670,7 +670,7 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeErrorMsg('hack', canHack.msg);
|
||||
}
|
||||
|
||||
workerScript.log("hack", `Executing ${ip} in ${hackingTime.toFixed(3)} seconds (t=${threads})`);
|
||||
workerScript.log("hack", `Executing ${ip} in ${convertTimeMsToTimeElapsedString(hackingTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)})`);
|
||||
|
||||
return netscriptDelay(hackingTime * 1000, workerScript).then(function() {
|
||||
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
|
||||
@@ -706,7 +706,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
|
||||
Player.gainHackingExp(expGainedOnSuccess);
|
||||
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
|
||||
workerScript.log("hack", `Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney(moneyGained)} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${threads})`);
|
||||
workerScript.log("hack", `Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney(moneyGained)} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${numeralWrapper.formatThreads(threads)})`);
|
||||
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
|
||||
if (stock) {
|
||||
influenceStockThroughServerHack(server, moneyGained);
|
||||
@@ -719,7 +719,7 @@ function NetscriptFunctions(workerScript) {
|
||||
// Player only gains 25% exp for failure?
|
||||
Player.gainHackingExp(expGainedOnFailure);
|
||||
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
|
||||
workerScript.log("hack", `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} exp (t=${threads})`);
|
||||
workerScript.log("hack", `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} exp (t=${numeralWrapper.formatThreads(threads)})`);
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
});
|
||||
@@ -937,7 +937,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
|
||||
var growTime = calculateGrowTime(server, Player);
|
||||
workerScript.log("grow", `Executing on '${server.hostname}' in ${formatNumber(growTime, 3)} seconds (t=${threads}).`);
|
||||
workerScript.log("grow", `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(growTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)}).`);
|
||||
return netscriptDelay(growTime * 1000, workerScript).then(function() {
|
||||
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
|
||||
const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable;
|
||||
@@ -950,7 +950,7 @@ function NetscriptFunctions(workerScript) {
|
||||
expGain = 0;
|
||||
}
|
||||
const logGrowPercent = (moneyAfter/moneyBefore)*100 - 100;
|
||||
workerScript.log("grow", `Available money on '${server.hostname}' grown by ${formatNumber(logGrowPercent, 6)}%. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${threads}).`);
|
||||
workerScript.log("grow", `Available money on '${server.hostname}' grown by ${formatNumber(logGrowPercent, 6)}%. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)}).`);
|
||||
workerScript.scriptRef.onlineExpGained += expGain;
|
||||
Player.gainHackingExp(expGain);
|
||||
if (stock) {
|
||||
@@ -988,13 +988,13 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
|
||||
var weakenTime = calculateWeakenTime(server, Player);
|
||||
workerScript.log("weaken", `Executing on '${server.hostname}' in ${formatNumber(weakenTime, 3)} seconds (t=${threads})`);
|
||||
workerScript.log("weaken", `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(weakenTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)})`);
|
||||
return netscriptDelay(weakenTime * 1000, workerScript).then(function() {
|
||||
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
|
||||
server.weaken(CONSTANTS.ServerWeakenAmount * threads);
|
||||
workerScript.scriptRef.recordWeaken(server.ip, threads);
|
||||
var expGain = calculateHackingExpGain(server, Player) * threads;
|
||||
workerScript.log("weaken", `'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${threads})`);
|
||||
workerScript.log("weaken", `'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`);
|
||||
workerScript.scriptRef.onlineExpGained += expGain;
|
||||
Player.gainHackingExp(expGain);
|
||||
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
|
||||
@@ -1453,6 +1453,11 @@ function NetscriptFunctions(workerScript) {
|
||||
if (scriptname == destServer.scripts[i].filename) {
|
||||
workerScript.log("scp", `WARNING: File '${scriptname}' overwritten on '${destServer.hostname}'`);
|
||||
const oldScript = destServer.scripts[i];
|
||||
// If it's the exact same file don't actually perform the
|
||||
// copy to avoid recompiling uselessly. Players tend to scp
|
||||
// liberally.
|
||||
if(oldScript.code === sourceScript.code)
|
||||
return true;
|
||||
oldScript.code = sourceScript.code;
|
||||
oldScript.ramUsage = sourceScript.ramUsage;
|
||||
oldScript.markUpdated();
|
||||
@@ -1619,7 +1624,7 @@ function NetscriptFunctions(workerScript) {
|
||||
},
|
||||
getBitNodeMultipliers: function() {
|
||||
updateDynamicRam("getBitNodeMultipliers", getRamCost("getBitNodeMultipliers"));
|
||||
if (SourceFileFlags[5] <= 0) {
|
||||
if (SourceFileFlags[5] <= 0 && Player.bitNodeN !== 5) {
|
||||
throw makeRuntimeErrorMsg("getBitNodeMultipliers", "Requires Source-File 5 to run.");
|
||||
}
|
||||
let copy = Object.assign({}, BitNodeMultipliers);
|
||||
@@ -1709,6 +1714,18 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.log("getServerRam", `returned [${formatNumber(server.maxRam, 2)}GB, ${formatNumber(server.ramUsed, 2)}GB]`);
|
||||
return [server.maxRam, server.ramUsed];
|
||||
},
|
||||
getServerMaxRam: function(ip) {
|
||||
updateDynamicRam("getServerMaxRam", getRamCost("getServerMaxRam"));
|
||||
const server = safeGetServer(ip, "getServerMaxRam");
|
||||
workerScript.log("getServerMaxRam", `returned ${formatNumber(server.maxRam, 2)}GB`);
|
||||
return server.maxRam;
|
||||
},
|
||||
getServerUsedRam: function(ip) {
|
||||
updateDynamicRam("getServerUsedRam", getRamCost("getServerUsedRam"));
|
||||
const server = safeGetServer(ip, "getServerUsedRam");
|
||||
workerScript.log("getServerUsedRam", `returned ${formatNumber(server.ramUsed, 2)}GB`);
|
||||
return server.ramUsed;
|
||||
},
|
||||
serverExists: function(ip) {
|
||||
updateDynamicRam("serverExists", getRamCost("serverExists"));
|
||||
return (getServer(ip) !== null);
|
||||
@@ -2920,6 +2937,28 @@ function NetscriptFunctions(workerScript) {
|
||||
const server = Player.getCurrentServer();
|
||||
return hack(server.hostname, true);
|
||||
},
|
||||
installBackdoor: function() {
|
||||
updateDynamicRam("installBackdoor", getRamCost("installBackdoor"));
|
||||
checkSingularityAccess("installBackdoor", 1);
|
||||
const server = Player.getCurrentServer();
|
||||
const installTime = calculateHackingTime(server, Player) / 4 * 1000;
|
||||
|
||||
// No root access or skill level too low
|
||||
const canHack = netscriptCanHack(server, Player);
|
||||
if (!canHack.res) {
|
||||
throw makeRuntimeErrorMsg('installBackdoor', canHack.msg);
|
||||
}
|
||||
|
||||
workerScript.log("installBackdoor", `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`);
|
||||
|
||||
return netscriptDelay(installTime, workerScript).then(function() {
|
||||
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
|
||||
workerScript.log("installBackdoor", `Successfully installed backdoor on '${server.hostname}'`);
|
||||
|
||||
server.backdoorInstalled = true;
|
||||
return Promise.resolve();
|
||||
});
|
||||
},
|
||||
getStats: function() {
|
||||
updateDynamicRam("getStats", getRamCost("getStats"));
|
||||
checkSingularityAccess("getStats", 1);
|
||||
@@ -3942,7 +3981,7 @@ function NetscriptFunctions(workerScript) {
|
||||
setActionAutolevel: function(type="", name="", autoLevel=true) {
|
||||
updateDynamicRam("setActionAutolevel", getRamCost("bladeburner", "setActionAutolevel"));
|
||||
checkBladeburnerAccess("setActionAutolevel");
|
||||
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
|
||||
const action = getBladeburnerActionObject("setActionAutolevel", type, name);
|
||||
action.autoLevel = autoLevel;
|
||||
},
|
||||
setActionLevel: function(type="", name="", level=1) {
|
||||
@@ -3952,7 +3991,7 @@ function NetscriptFunctions(workerScript) {
|
||||
if(level < 1 || level > action.maxLevel) {
|
||||
throw makeRuntimeErrorMsg("bladeburner.setActionLevel", `Level must be between 1 and ${action.maxLevel}, is ${level}`)
|
||||
}
|
||||
actionObj.level = level;
|
||||
action.level = level;
|
||||
},
|
||||
getRank: function() {
|
||||
updateDynamicRam("getRank", getRamCost("bladeburner", "getRank"));
|
||||
@@ -4430,9 +4469,9 @@ function NetscriptFunctions(workerScript) {
|
||||
},
|
||||
},
|
||||
hacknetServers: {
|
||||
hashGainRate: function(level, ram, cores, mult=1) {
|
||||
hashGainRate: function(level, ramUsed, maxRam, cores, mult=1) {
|
||||
checkFormulasAccess("hacknetServers.hashGainRate", 9);
|
||||
return HScalculateHashGainRate(level, ram, cores, mult);
|
||||
return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult=1);
|
||||
},
|
||||
levelUpgradeCost: function(startingLevel, extraLevels=1, costMult=1) {
|
||||
checkFormulasAccess("hacknetServers.levelUpgradeCost", 9);
|
||||
|
||||
@@ -27,6 +27,7 @@ export async function executeJSScript(scripts = [], workerScript) {
|
||||
// but not really behaves like import. Particularly, it cannot
|
||||
// load fully dynamic content. So we hide the import from webpack
|
||||
// by placing it inside an eval call.
|
||||
script.markUpdated();
|
||||
urls = _getScriptUrls(script, scripts, []);
|
||||
script.url = urls[urls.length - 1].url;
|
||||
script.module = new Promise(resolve => resolve(eval('import(urls[urls.length - 1].url)')));
|
||||
@@ -59,13 +60,13 @@ export async function executeJSScript(scripts = [], workerScript) {
|
||||
function shouldCompile(script, scripts) {
|
||||
if (script.module === "") return true;
|
||||
return script.dependencies.some(dep => {
|
||||
const depScript = scripts.find(s => s.filename == dep.url);
|
||||
const depScript = scripts.find(s => s.filename == dep.filename);
|
||||
|
||||
// If the script is not present on the server, we should recompile, if only to get any necessary
|
||||
// compilation errors.
|
||||
if (!depScript) return true;
|
||||
|
||||
const depIsMoreRecent = depScript.moduleSequenceNumber > script.moduleSequenceNumber
|
||||
const depIsMoreRecent = depScript.moduleSequenceNumber > script.moduleSequenceNumber;
|
||||
return depIsMoreRecent;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -417,8 +417,8 @@ function processNetscript1Imports(code, workerScript) {
|
||||
* @param {Server} server - Server on which the script is to be run
|
||||
* @returns {number} pid of started script
|
||||
*/
|
||||
export function startWorkerScript(runningScript, server) {
|
||||
if (createAndAddWorkerScript(runningScript, server)) {
|
||||
export function startWorkerScript(runningScript, server, parent) {
|
||||
if (createAndAddWorkerScript(runningScript, server, parent)) {
|
||||
// Push onto runningScripts.
|
||||
// This has to come after createAndAddWorkerScript() because that fn updates RAM usage
|
||||
server.runScript(runningScript, Player.hacknet_node_money_mult);
|
||||
@@ -438,7 +438,7 @@ export function startWorkerScript(runningScript, server) {
|
||||
* @param {Server} server - Server on which the script is to be run
|
||||
* returns {boolean} indicating whether or not the workerScript was successfully added
|
||||
*/
|
||||
export function createAndAddWorkerScript(runningScriptObj, server) {
|
||||
export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
// Update server's ram usage
|
||||
let threads = 1;
|
||||
if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
|
||||
@@ -489,6 +489,12 @@ export function createAndAddWorkerScript(runningScriptObj, server) {
|
||||
// Once the code finishes (either resolved or rejected, doesnt matter), set its
|
||||
// running status to false
|
||||
p.then(function(w) {
|
||||
// On natural death, the earnings are transfered to the parent if it still exists.
|
||||
if(parent && parent.running) {
|
||||
parent.scriptRef.onlineExpGained += runningScriptObj.onlineExpGained;
|
||||
parent.scriptRef.onlineMoneyMade += runningScriptObj.onlineMoneyMade;
|
||||
}
|
||||
|
||||
// If the WorkerScript is no longer "running", then this means its execution was
|
||||
// already stopped somewhere else (maybe by something like exit()). This prevents
|
||||
// the script from being cleaned up twice
|
||||
@@ -643,7 +649,7 @@ export function runScriptFromScript(caller, server, scriptname, args, workerScri
|
||||
let runningScriptObj = new RunningScript(script, args);
|
||||
runningScriptObj.threads = threads;
|
||||
|
||||
return startWorkerScript(runningScriptObj, server);
|
||||
return startWorkerScript(runningScriptObj, server, workerScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,5 +368,10 @@ function updateAugDescription(elems: IResleeveUIElems): void {
|
||||
return;
|
||||
}
|
||||
|
||||
elems.augDescription.innerHTML = aug.info;
|
||||
let innerHTML = aug.info;
|
||||
if(typeof innerHTML !== 'string') {
|
||||
innerHTML = renderToStaticMarkup(innerHTML);
|
||||
}
|
||||
|
||||
elems.augDescription.innerHTML = innerHTML;
|
||||
}
|
||||
|
||||
@@ -907,7 +907,7 @@ export class Sleeve extends Person {
|
||||
this.currentTaskLocation = LocationName.Sector12PowerhouseGym;
|
||||
costMult = 20;
|
||||
break;
|
||||
case LocationName.VolhavenMilleniumFitnessGym:
|
||||
case LocationName.VolhavenMilleniumFitnessGym.toLowerCase():
|
||||
if (this.city != CityName.Volhaven) { return false; }
|
||||
this.currentTaskLocation = LocationName.VolhavenMilleniumFitnessGym;
|
||||
costMult = 7;
|
||||
|
||||
@@ -55,10 +55,15 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer): void
|
||||
continue;
|
||||
}
|
||||
|
||||
let tooltip = aug.info;
|
||||
if(typeof tooltip !== 'string') {
|
||||
tooltip = renderToStaticMarkup(tooltip);
|
||||
}
|
||||
|
||||
ownedAugsDiv.appendChild(createElement("div", {
|
||||
class: "gang-owned-upgrade", // Reusing a class from the Gang UI
|
||||
innerText: ownedAug,
|
||||
tooltip: aug.info,
|
||||
tooltip: tooltip,
|
||||
}))
|
||||
}
|
||||
popupElems.push(ownedAugsDiv);
|
||||
@@ -83,13 +88,18 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer): void
|
||||
class: "cmpy-mgmt-upgrade-div", // We'll reuse this CSS class
|
||||
});
|
||||
|
||||
let info = aug.info;
|
||||
if(typeof info !== 'string') {
|
||||
info = renderToStaticMarkup(info);
|
||||
}
|
||||
|
||||
div.appendChild(createElement("p", {
|
||||
fontSize: "12px",
|
||||
innerHTML:
|
||||
[
|
||||
`<h2>${aug.name}</h2><br>`,
|
||||
`Cost: ${renderToStaticMarkup(Money(aug.startingCost))}<br><br>`,
|
||||
`${aug.info}`,
|
||||
`${info}`,
|
||||
].join(" "),
|
||||
padding: "2px",
|
||||
clickListener: () => {
|
||||
|
||||
@@ -35,7 +35,11 @@ export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState>
|
||||
}
|
||||
|
||||
changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const n: number = parseInt(e.target.value);
|
||||
let n: number = parseInt(e.target.value);
|
||||
|
||||
if(isNaN(n)) n = 1;
|
||||
const maxMemory = 100 - this.props.sleeve.memory;
|
||||
if (n > maxMemory) n = maxMemory;
|
||||
|
||||
this.setState({
|
||||
amt: n,
|
||||
@@ -89,7 +93,7 @@ export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState>
|
||||
<label htmlFor={inputId}>
|
||||
Amount of memory to purchase (must be an integer):
|
||||
</label>
|
||||
<input id={inputId} onChange={this.changePurchaseAmount} type={"number"} value={isNaN(this.state.amt) ? this.state.amt.toString() : this.state.amt} />
|
||||
<input className="text-input" id={inputId} onChange={this.changePurchaseAmount} type={"number"} value={this.state.amt} />
|
||||
<br />
|
||||
<StdButton disabled={purchaseBtnDisabled} onClick={this.purchaseMemory} text={purchaseBtnContent} />
|
||||
</div>
|
||||
|
||||
@@ -234,6 +234,11 @@ function prestigeSourceFile() {
|
||||
}
|
||||
}
|
||||
|
||||
// Give levels of NeuroFluxGoverner for Source-File 12. Must be done here before Augmentations are recalculated
|
||||
if (SourceFileFlags[12] > 0) {
|
||||
Player.augmentations.push({name: AugmentationNames.NeuroFluxGovernor, level: SourceFileFlags[12]})
|
||||
}
|
||||
|
||||
// Re-initialize things - This will update any changes
|
||||
initFactions(); // Factions must be initialized before augmentations
|
||||
initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Program } from "./Program";
|
||||
import { programsMetadata } from "./data/programsMetadata";
|
||||
import { programsMetadata } from "./data/ProgramsMetadata";
|
||||
import { IMap } from "../types";
|
||||
|
||||
export const Programs: IMap<Program> = {};
|
||||
|
||||
@@ -58,13 +58,17 @@ function writeRedPillLetter(pElem, line, i=0) {
|
||||
}
|
||||
|
||||
let redPillFlag = false;
|
||||
function hackWorldDaemon(currentNodeNumber, flume=false) {
|
||||
function hackWorldDaemon(currentNodeNumber, flume=false, quick=false) {
|
||||
// Clear Red Pill screen first
|
||||
var container = document.getElementById("red-pill-content");
|
||||
removeChildrenFromElement(container);
|
||||
|
||||
redPillFlag = true;
|
||||
Engine.loadRedPillContent();
|
||||
|
||||
if(quick) {
|
||||
return loadBitVerse(currentNodeNumber, flume, quick);
|
||||
}
|
||||
return writeRedPillLine("[ERROR] SEMPOOL INVALID").then(function() {
|
||||
return writeRedPillLine("[ERROR] Segmentation Fault");
|
||||
}).then(function() {
|
||||
@@ -143,7 +147,7 @@ function giveSourceFile(bitNodeNumber) {
|
||||
// is destroyed. Updated every time loadBitVerse() is called
|
||||
let nextSourceFileFlags = [];
|
||||
|
||||
function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
||||
function loadBitVerse(destroyedBitNodeNum, flume=false, quick=false) {
|
||||
// Clear the screen
|
||||
const container = document.getElementById("red-pill-content");
|
||||
removeChildrenFromElement(container);
|
||||
@@ -151,7 +155,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
||||
// Update NextSourceFileFlags
|
||||
nextSourceFileFlags = SourceFileFlags.slice();
|
||||
if (!flume) {
|
||||
if (nextSourceFileFlags[destroyedBitNodeNum] < 3 && destroyedBitNodeNum !== 12)
|
||||
if (nextSourceFileFlags[destroyedBitNodeNum] < 3)
|
||||
++nextSourceFileFlags[destroyedBitNodeNum];
|
||||
}
|
||||
|
||||
@@ -221,6 +225,10 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
||||
}(i)); // Immediate invocation closure
|
||||
}
|
||||
|
||||
if(quick) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
// Create lore text
|
||||
return writeRedPillLine("Many decades ago, a humanoid extraterrestial species which we call the Enders descended on the Earth...violently").then(function() {
|
||||
return writeRedPillLine("Our species fought back, but it was futile. The Enders had technology far beyond our own...");
|
||||
@@ -316,8 +324,6 @@ function createBitNodeYesNoEventListener(newBitNode, destroyedBitNode, flume=fal
|
||||
document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
|
||||
$('input[class=terminal-input]').prop('disabled', false);
|
||||
|
||||
Terminal.hackFlag = false;
|
||||
|
||||
prestigeSourceFile();
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
@@ -178,7 +178,7 @@ class CodeMirrorEditorWrapper extends ScriptEditor {
|
||||
netscriptFns.push(name);
|
||||
|
||||
//Get functions from namespaces
|
||||
const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang", "sleeve"];
|
||||
const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang", "sleeve", "heart", "formulas"];
|
||||
if (namespaces.includes(name)) {
|
||||
let namespace = fnsObj[name];
|
||||
if (typeof namespace !== "object") {continue;}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
import CodeMirror from "codemirror/lib/codemirror.js";
|
||||
import { NetscriptFunctions } from "../NetscriptFunctions";
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
@@ -26,7 +28,7 @@ CodeMirror.defineMode("netscript", function(config, parserConfig) {
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
return {
|
||||
const ret = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
|
||||
"debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
@@ -40,234 +42,16 @@ CodeMirror.defineMode("netscript", function(config, parserConfig) {
|
||||
|
||||
// Netscript Basic Functions
|
||||
"hack": atom,
|
||||
"hackAnalyzeThreads": atom,
|
||||
"hackAnalyzePercent": atom,
|
||||
"hackChance": atom,
|
||||
"sleep": atom,
|
||||
"grow": atom,
|
||||
"weaken": atom,
|
||||
"growthAnalyze": atom,
|
||||
"print": atom,
|
||||
"tprint": atom,
|
||||
"scan": atom,
|
||||
"nuke": atom,
|
||||
"brutessh": atom,
|
||||
"ftpcrack": atom,
|
||||
"clearLog": atom,
|
||||
"disableLog": atom,
|
||||
"enableLog": atom,
|
||||
"isLogEnabled": atom,
|
||||
"getScriptLogs": atom,
|
||||
"tail": atom,
|
||||
"relaysmtp": atom,
|
||||
"httpworm": atom,
|
||||
"sqlinject": atom,
|
||||
"run": atom,
|
||||
"exec": atom,
|
||||
"spawn": atom,
|
||||
"kill": atom,
|
||||
"killall": atom,
|
||||
"exit": atom,
|
||||
"scp": atom,
|
||||
"ls": atom,
|
||||
"ps": atom,
|
||||
"hasRootAccess": atom,
|
||||
"getIp": atom,
|
||||
"getHackingMultipliers": atom,
|
||||
"getBitNodeMultipliers": atom,
|
||||
"getStats": atom,
|
||||
"isBusy": atom,
|
||||
"getHacknetMultipliers": atom,
|
||||
"getHostname": atom,
|
||||
"getHackingLevel": atom,
|
||||
"getServerMoneyAvailable": atom,
|
||||
"getServerMaxMoney": atom,
|
||||
"getServerGrowth": atom,
|
||||
"getServerSecurityLevel": atom,
|
||||
"getServerBaseSecurityLevel": atom,
|
||||
"getServerMinSecurityLevel": atom,
|
||||
"getServerRequiredHackingLevel": atom,
|
||||
"getServerNumPortsRequired": atom,
|
||||
"getServerRam": atom,
|
||||
"serverExists": atom,
|
||||
"fileExists": atom,
|
||||
"isRunning": atom,
|
||||
"deleteServer": atom,
|
||||
"getPurchasedServers": atom,
|
||||
"getPurchasedServerLimit": atom,
|
||||
"getPurchasedServerMaxRam": atom,
|
||||
"getPurchasedServerCost": atom,
|
||||
"purchaseServer": atom,
|
||||
"round": atom,
|
||||
"write": atom,
|
||||
"tryWrite": atom,
|
||||
"read": atom,
|
||||
"peek": atom,
|
||||
"clear": atom,
|
||||
"rm": atom,
|
||||
"getPortHandle": atom,
|
||||
"scriptRunning": atom,
|
||||
"scriptKill": atom,
|
||||
"getScriptName": atom,
|
||||
"getScriptRam": atom,
|
||||
"getHackTime": atom,
|
||||
"getGrowTime": atom,
|
||||
"getWeakenTime": atom,
|
||||
"getScriptIncome": atom,
|
||||
"getScriptExpGain": atom,
|
||||
"getTimeSinceLastAug": atom,
|
||||
"prompt": atom,
|
||||
|
||||
// Netscript Singularity Functions
|
||||
"universityCourse": atom,
|
||||
"getCharacterInformation": atom,
|
||||
"gymWorkout": atom,
|
||||
"travelToCity": atom,
|
||||
"purchaseTor": atom,
|
||||
"purchaseProgram": atom,
|
||||
"upgradeHomeRam": atom,
|
||||
"getUpgradeHomeRamCost": atom,
|
||||
"workForCompany": atom,
|
||||
"applyToCompany": atom,
|
||||
"getCompanyRep": atom,
|
||||
"getCompanyFavor": atom,
|
||||
"stopAction": atom,
|
||||
"getFactionFavor": atom,
|
||||
"getFavorToDonate": atom,
|
||||
"getFactionFavorGain": atom,
|
||||
"getCompanyFavorGain": atom,
|
||||
"checkFactionInvitations": atom,
|
||||
"joinFaction": atom,
|
||||
"workForFaction": atom,
|
||||
"getFactionRep": atom,
|
||||
"donateToFaction": atom,
|
||||
"createProgram": atom,
|
||||
"commitCrime": atom,
|
||||
"getCrimeChance": atom,
|
||||
"getOwnedAugmentations": atom,
|
||||
"getOwnedSourceFiles": atom,
|
||||
"getAugmentationsFromFaction": atom,
|
||||
"getAugmentationPrereq": atom,
|
||||
"getAugmentationCost": atom,
|
||||
"purchaseAugmentation": atom,
|
||||
"installAugmentations": atom,
|
||||
|
||||
// Netscript TIX API
|
||||
"getStockPrice": atom,
|
||||
"getStockAskPrice": atom,
|
||||
"getStockBidPrice": atom,
|
||||
"getStockPosition": atom,
|
||||
"getStockSymbols": atom,
|
||||
"getStockMaxShares": atom,
|
||||
"getStockPurchaseCost": atom,
|
||||
"getStockSaleGain": atom,
|
||||
"buyStock": atom,
|
||||
"sellStock": atom,
|
||||
"shortStock": atom,
|
||||
"sellShort": atom,
|
||||
"placeOrder": atom,
|
||||
"cancelOrder": atom,
|
||||
"getOrders": atom,
|
||||
"getStockVolatility": atom,
|
||||
"getStockForecast": atom,
|
||||
"purchase4SMarketData": atom,
|
||||
"purchase4SMarketDataTixApi": atom,
|
||||
|
||||
// Netscript Hacknet Node API
|
||||
"hacknet": atom,
|
||||
"numNodes": atom,
|
||||
"purchaseNode": atom,
|
||||
"getPurchaseNodeCost": atom,
|
||||
"getNodeStats": atom,
|
||||
"upgradeLevel": atom,
|
||||
"upgradeRam": atom,
|
||||
"upgradeCore": atom,
|
||||
"upgradeCache": atom,
|
||||
"getLevelUpgradeCost": atom,
|
||||
"getRamUpgradeCost": atom,
|
||||
"getCoreUpgradeCost": atom,
|
||||
"getCacheUpgradeCost": atom,
|
||||
|
||||
// Netscript Gang API
|
||||
"gang": atom,
|
||||
"getMemberNames": atom,
|
||||
"getGangInformation": atom,
|
||||
"getMemberInformation": atom,
|
||||
"canRecruitMember": atom,
|
||||
"recruitMember": atom,
|
||||
"getTaskNames": atom,
|
||||
"setMemberTask": atom,
|
||||
"getEquipmentNames": atom,
|
||||
"getEquipmentCost": atom,
|
||||
"getEquipmentType": atom,
|
||||
"purchaseEquipment": atom,
|
||||
"ascendMember": atom,
|
||||
"setTerritoryWarfare": atom,
|
||||
"getChanceToWinClash": atom,
|
||||
"getBonusTime": atom,
|
||||
|
||||
// Netscript Bladeburner API
|
||||
"bladeburner": atom,
|
||||
"getContractNames": atom,
|
||||
"getOperationNames": atom,
|
||||
"getBlackOpNames": atom,
|
||||
"getGeneralActionNames": atom,
|
||||
"getSkillNames": atom,
|
||||
"startAction": atom,
|
||||
"stopBladeburnerAction": atom,
|
||||
"getCurrentAction": atom,
|
||||
"getActionTime": atom,
|
||||
"getActionEstimatedSuccessChance": atom,
|
||||
"getActionCountRemaining": atom,
|
||||
"getActionMaxLevel": atom,
|
||||
"getActionCurrentLevel": atom,
|
||||
"getActionAutolevel": atom,
|
||||
"getActionRepGain": atom,
|
||||
"setActionAutolevel": atom,
|
||||
"setActionLevel": atom,
|
||||
"getRank": atom,
|
||||
"getBlackOpRank": atom,
|
||||
"getSkillPoints": atom,
|
||||
"getSkillLevel": atom,
|
||||
"getSkillUpgradeCost": atom,
|
||||
"upgradeSkill": atom,
|
||||
"getTeamSize": atom,
|
||||
"getCity": atom,
|
||||
"setTeamSize": atom,
|
||||
"getCityEstimatedPopulation": atom,
|
||||
"getCityEstimatedCommunities": atom,
|
||||
"getCityChaos": atom,
|
||||
"switchCity": atom,
|
||||
"getStamina": atom,
|
||||
"joinBladeburnerFaction": atom,
|
||||
// Repeat of above "getBonusTime": atom,
|
||||
|
||||
// Netscript Coding Contract API
|
||||
"codingcontract": atom,
|
||||
"attempt": atom,
|
||||
"getContractType": atom,
|
||||
"getData": atom,
|
||||
"getDescription": atom,
|
||||
"getNumTriesRemaining": atom,
|
||||
|
||||
// Sleeve API
|
||||
"sleeve": atom,
|
||||
"getNumSleeves": atom,
|
||||
"setToShockRecovery": atom,
|
||||
"setToSynchronize": atom,
|
||||
"setToCommitCrime": atom,
|
||||
"setToUniversityCourse": atom,
|
||||
"travel": atom,
|
||||
"setToCompanyWork": atom,
|
||||
"setToFactionWork": atom,
|
||||
"setToGymWorkout": atom,
|
||||
"getSleeveStats": atom,
|
||||
"getTask": atom,
|
||||
"getInformation": atom,
|
||||
"getSleeveAugmentations": atom,
|
||||
"getSleevePurchasableAugs": atom,
|
||||
"purchaseSleeveAug": atom,
|
||||
};
|
||||
|
||||
function push(obj) {
|
||||
for(const key of Object.keys(obj)) {
|
||||
if(typeof obj[key] === 'function') ret[key] = atom;
|
||||
if(typeof obj[key] === 'object') push(obj[key]);
|
||||
}
|
||||
}
|
||||
push(NetscriptFunctions(null));
|
||||
return ret;
|
||||
}());
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
|
||||
|
||||
@@ -1203,38 +1203,51 @@ export const serverMetadata: IServerMetadata[] = [
|
||||
},
|
||||
{
|
||||
hackDifficulty: 1,
|
||||
hostname: "n00dles",
|
||||
literature: [],
|
||||
maxRamExponent: 2,
|
||||
moneyAvailable: 70000,
|
||||
networkLayer: 1,
|
||||
numOpenPortsRequired: 0,
|
||||
organizationName: LocationName.NewTokyoNoodleBar,
|
||||
requiredHackingSkill: 1,
|
||||
serverGrowth: 3000,
|
||||
specialName: LocationName.NewTokyoNoodleBar,
|
||||
},
|
||||
{
|
||||
hackDifficulty: 10,
|
||||
hostname: "foodnstuff",
|
||||
literature: [LiteratureNames.Sector12Crime],
|
||||
maxRamExponent: 4,
|
||||
moneyAvailable: 40000,
|
||||
moneyAvailable: 2000000,
|
||||
networkLayer: 1,
|
||||
numOpenPortsRequired: 0,
|
||||
organizationName: LocationName.Sector12FoodNStuff,
|
||||
requiredHackingSkill: 1,
|
||||
serverGrowth: 3000,
|
||||
serverGrowth: 5,
|
||||
specialName: LocationName.Sector12FoodNStuff,
|
||||
},
|
||||
{
|
||||
hackDifficulty: 3,
|
||||
hackDifficulty: 10,
|
||||
hostname: "sigma-cosmetics",
|
||||
maxRamExponent: 4,
|
||||
moneyAvailable: 70000,
|
||||
moneyAvailable: 2300000,
|
||||
networkLayer: 1,
|
||||
numOpenPortsRequired: 0,
|
||||
organizationName: "Sigma Cosmetics",
|
||||
requiredHackingSkill: 5,
|
||||
serverGrowth: 3000,
|
||||
serverGrowth: 10,
|
||||
},
|
||||
{
|
||||
hackDifficulty: 9,
|
||||
hackDifficulty: 15,
|
||||
hostname: "joesguns",
|
||||
maxRamExponent: 4,
|
||||
moneyAvailable: 600000,
|
||||
moneyAvailable: 2500000,
|
||||
networkLayer: 1,
|
||||
numOpenPortsRequired: 0,
|
||||
organizationName: LocationName.Sector12JoesGuns,
|
||||
requiredHackingSkill: 10,
|
||||
serverGrowth: 500,
|
||||
serverGrowth: 20,
|
||||
specialName: LocationName.Sector12JoesGuns,
|
||||
},
|
||||
{
|
||||
@@ -1569,4 +1582,4 @@ export const serverMetadata: IServerMetadata[] = [
|
||||
serverGrowth: 0,
|
||||
specialName: "w0r1d_d43m0n",
|
||||
},
|
||||
];
|
||||
];
|
||||
@@ -60,5 +60,4 @@ SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so t
|
||||
"Level 1: 32%<br>" +
|
||||
"Level 2: 48%<br>" +
|
||||
"Level 3: 56%<br>");
|
||||
SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File increases all your multipliers by 1% per level. This effect is multiplicative with itself. " +
|
||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||
SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.");
|
||||
|
||||
@@ -141,44 +141,9 @@ export function applySourceFile(srcFile: PlayerOwnedSourceFile): void {
|
||||
Player.company_rep_mult *= incMult;
|
||||
break;
|
||||
}
|
||||
case 12: { // The Recursion
|
||||
const inc = Math.pow(1.01, srcFile.lvl);
|
||||
const dec = Math.pow(0.99, srcFile.lvl);
|
||||
|
||||
Player.hacking_chance_mult *= inc;
|
||||
Player.hacking_speed_mult *= inc;
|
||||
Player.hacking_money_mult *= inc;
|
||||
Player.hacking_grow_mult *= inc;
|
||||
Player.hacking_mult *= inc;
|
||||
|
||||
Player.strength_mult *= inc;
|
||||
Player.defense_mult *= inc;
|
||||
Player.dexterity_mult *= inc;
|
||||
Player.agility_mult *= inc;
|
||||
Player.charisma_mult *= inc;
|
||||
|
||||
Player.hacking_exp_mult *= inc;
|
||||
Player.strength_exp_mult *= inc;
|
||||
Player.defense_exp_mult *= inc;
|
||||
Player.dexterity_exp_mult *= inc;
|
||||
Player.agility_exp_mult *= inc;
|
||||
Player.charisma_exp_mult *= inc;
|
||||
|
||||
Player.company_rep_mult *= inc;
|
||||
Player.faction_rep_mult *= inc;
|
||||
|
||||
Player.crime_money_mult *= inc;
|
||||
Player.crime_success_mult *= inc;
|
||||
|
||||
Player.hacknet_node_money_mult *= inc;
|
||||
Player.hacknet_node_purchase_cost_mult *= dec;
|
||||
Player.hacknet_node_ram_cost_mult *= dec;
|
||||
Player.hacknet_node_core_cost_mult *= dec;
|
||||
Player.hacknet_node_level_cost_mult *= dec;
|
||||
|
||||
Player.work_money_mult *= inc;
|
||||
case 12: // The Recursion
|
||||
// No effects, grants neuroflux.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error(`Invalid source file number: ${srcFile.n}`);
|
||||
break;
|
||||
|
||||
166
src/Terminal.jsx
166
src/Terminal.jsx
@@ -53,7 +53,11 @@ import { Player } from "./Player";
|
||||
import { hackWorldDaemon } from "./RedPill";
|
||||
import { RunningScript } from "./Script/RunningScript";
|
||||
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
||||
import { getCurrentEditor, findRunningScript } from "./Script/ScriptHelpers";
|
||||
import {
|
||||
getCurrentEditor,
|
||||
findRunningScript,
|
||||
findRunningScriptByPid,
|
||||
} from "./Script/ScriptHelpers";
|
||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import {
|
||||
@@ -531,6 +535,7 @@ let Terminal = {
|
||||
Player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(Player.bitNodeN);
|
||||
Terminal.hackFlag = false;
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
@@ -559,7 +564,16 @@ let Terminal = {
|
||||
|
||||
finishBackdoor: function(cancelled = false) {
|
||||
if(!cancelled){
|
||||
let server = Player.getCurrentServer();
|
||||
const server = Player.getCurrentServer();
|
||||
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
||||
if (Player.bitNodeN == null) {
|
||||
Player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(Player.bitNodeN);
|
||||
Terminal.backdoorFlag = false;
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
postElement(<>Backdoor successful!</>);
|
||||
}
|
||||
@@ -571,47 +585,27 @@ let Terminal = {
|
||||
let currServ = Player.getCurrentServer();
|
||||
const isHacknet = currServ instanceof HacknetServer;
|
||||
post(currServ.hostname + ": ");
|
||||
post("Organization name: " + currServ.organizationName);
|
||||
var rootAccess = "";
|
||||
if (currServ.hasAdminRights) {rootAccess = "YES";}
|
||||
else {rootAccess = "NO";}
|
||||
post("Root Access: " + rootAccess);
|
||||
if (!isHacknet) { post("Required hacking skill: " + currServ.requiredHackingSkill); }
|
||||
post("Server security level: " + numeralWrapper.formatServerSecurity(currServ.hackDifficulty));
|
||||
post("Chance to hack: " + numeralWrapper.formatPercentage(calculateHackingChance(currServ, Player)));
|
||||
post("Time to hack: " + convertTimeMsToTimeElapsedString(calculateHackingTime(currServ, Player)*1000));
|
||||
postElement(<>Total money available on server: {Money(currServ.moneyAvailable)}</>);
|
||||
if (!isHacknet) { post("Required number of open ports for NUKE: " + currServ.numOpenPortsRequired); }
|
||||
|
||||
if (currServ.sshPortOpen) {
|
||||
post("SSH port: Open")
|
||||
} else {
|
||||
post("SSH port: Closed")
|
||||
}
|
||||
|
||||
if (currServ.ftpPortOpen) {
|
||||
post("FTP port: Open")
|
||||
} else {
|
||||
post("FTP port: Closed")
|
||||
}
|
||||
|
||||
if (currServ.smtpPortOpen) {
|
||||
post("SMTP port: Open")
|
||||
} else {
|
||||
post("SMTP port: Closed")
|
||||
}
|
||||
|
||||
if (currServ.httpPortOpen) {
|
||||
post("HTTP port: Open")
|
||||
} else {
|
||||
post("HTTP port: Closed")
|
||||
}
|
||||
|
||||
if (currServ.sqlPortOpen) {
|
||||
post("SQL port: Open")
|
||||
} else {
|
||||
post("SQL port: Closed")
|
||||
}
|
||||
const org = currServ.organizationName
|
||||
post("Organization name: " + (!isHacknet ? org : "Player"));
|
||||
const admin = currServ.hasAdminRights;
|
||||
let hasAdminRights = !isHacknet && currServ.hasAdminRights || isHacknet;
|
||||
post("Root Access: " + (hasAdminRights ? "YES" : "NO"));
|
||||
const hackingSkill = currServ.requiredHackingSkill
|
||||
post("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A"));
|
||||
const security = currServ.hackDifficulty;
|
||||
post("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A"));
|
||||
const hackingChance = calculateHackingChance(currServ, Player)
|
||||
post("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A"));
|
||||
const hackingTime = calculateHackingTime(currServ, Player)*1000;
|
||||
post("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A"));
|
||||
postElement(<>Total money available on server: {!isHacknet ? Money(currServ.moneyAvailable) : "N/A"}</>);
|
||||
const numPort = currServ.numOpenPortsRequired;
|
||||
post("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A"));
|
||||
post("SSH port: "+ (currServ.sshPortOpen ? "Open" : "Closed"))
|
||||
post("FTP port: "+ (currServ.ftpPortOpen ? "Open" : "Closed"))
|
||||
post("SMTP port: "+ (currServ.smtpPortOpen ? "Open" : "Closed"))
|
||||
post("HTTP port: "+ (currServ.httpPortOpen ? "Open" : "Closed"))
|
||||
post("SQL port: "+ (currServ.sqlPortOpen ? "Open" : "Closed"))
|
||||
}
|
||||
Terminal.analyzeFlag = false;
|
||||
},
|
||||
@@ -974,7 +968,8 @@ let Terminal = {
|
||||
}
|
||||
|
||||
const server = Player.getCurrentServer();
|
||||
if(!server.scripts.some(script => script.filename.startsWith(evaledDir))) {
|
||||
if(!server.scripts.some(script => script.filename.startsWith(evaledDir)) &&
|
||||
!server.textFiles.some(file => file.fn.startsWith(evaledDir))) {
|
||||
postError("Invalid path. Failed to change directories");
|
||||
return;
|
||||
}
|
||||
@@ -1405,10 +1400,10 @@ let Terminal = {
|
||||
try {
|
||||
if (commandArray.length < 2) {
|
||||
postError("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
|
||||
} else {
|
||||
} else if(typeof commandArray[1] === 'string') {
|
||||
const scriptName = Terminal.getFilepath(commandArray[1]);
|
||||
if (!isScriptFilename(scriptName)) {
|
||||
postError("tail can only be called on .script files (filename must end with .script)");
|
||||
postError("tail can only be called on .script, .ns, .js files, or by pid");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1425,6 +1420,13 @@ let Terminal = {
|
||||
return;
|
||||
}
|
||||
logBoxCreate(runningScript);
|
||||
} else {
|
||||
const runningScript = findRunningScriptByPid(commandArray[1], Player.getCurrentServer());
|
||||
if (runningScript == null) {
|
||||
postError("No such script exists");
|
||||
return;
|
||||
}
|
||||
logBoxCreate(runningScript);
|
||||
}
|
||||
} catch(e) {
|
||||
Terminal.postThrownError(e);
|
||||
@@ -1700,10 +1702,14 @@ let Terminal = {
|
||||
}
|
||||
|
||||
// Display all programs and scripts
|
||||
let allFiles = [];
|
||||
let folders = [];
|
||||
const allPrograms = [];
|
||||
const allScripts = [];
|
||||
const allTextFiles = [];
|
||||
const allContracts = [];
|
||||
const allMessages = [];
|
||||
const folders = [];
|
||||
|
||||
function handleFn(fn) {
|
||||
function handleFn(fn, dest) {
|
||||
let parsedFn = fn;
|
||||
if (prefix) {
|
||||
if (!fn.startsWith(prefix)) {
|
||||
@@ -1732,29 +1738,53 @@ let Terminal = {
|
||||
return;
|
||||
}
|
||||
|
||||
allFiles.push(parsedFn);
|
||||
dest.push(parsedFn);
|
||||
}
|
||||
|
||||
// Get all of the programs and scripts on the machine into one temporary array
|
||||
const s = Player.getCurrentServer();
|
||||
for (const program of s.programs) handleFn(program);
|
||||
for (const script of s.scripts) handleFn(script.filename);
|
||||
for (const txt of s.textFiles) handleFn(txt.fn);
|
||||
for (const contract of s.contracts) handleFn(contract.fn);
|
||||
for (const msgOrLit of s.messages) (msgOrLit instanceof Message) ? handleFn(msgOrLit.filename) : handleFn(msgOrLit);
|
||||
for (const program of s.programs) handleFn(program, allPrograms);
|
||||
for (const script of s.scripts) handleFn(script.filename, allScripts);
|
||||
for (const txt of s.textFiles) handleFn(txt.fn, allTextFiles);
|
||||
for (const contract of s.contracts) handleFn(contract.fn, allContracts);
|
||||
for (const msgOrLit of s.messages) (msgOrLit instanceof Message) ? handleFn(msgOrLit.filename, allMessages) : handleFn(msgOrLit, allMessages);
|
||||
|
||||
// Sort the files/folders alphabetically then print each
|
||||
allFiles.sort();
|
||||
allPrograms.sort();
|
||||
allScripts.sort();
|
||||
allTextFiles.sort();
|
||||
allContracts.sort();
|
||||
allMessages.sort();
|
||||
folders.sort();
|
||||
|
||||
const config = { color: "#0000FF" };
|
||||
for (const dir of folders) {
|
||||
postContent(dir, config);
|
||||
function postSegments(segments, config) {
|
||||
const maxLength = Math.max(...segments.map(s => s.length))+1;
|
||||
const filesPerRow = Math.floor(80 / maxLength);
|
||||
for(let i = 0; i < segments.length; i++) {
|
||||
let row = '';
|
||||
for(let col = 0; col < filesPerRow; col++) {
|
||||
if(!(i < segments.length)) break;
|
||||
row += segments[i];
|
||||
row += " ".repeat((maxLength * (col+1)) - row.length);
|
||||
i++
|
||||
}
|
||||
postContent(row, config);
|
||||
}
|
||||
}
|
||||
|
||||
for (const file of allFiles) {
|
||||
postContent(file);
|
||||
}
|
||||
|
||||
const config = { color: "#0000FF" };
|
||||
postSegments(folders, config);
|
||||
postElement(<br />);
|
||||
postSegments(allMessages);
|
||||
postElement(<br />);
|
||||
postSegments(allTextFiles);
|
||||
postElement(<br />);
|
||||
postSegments(allPrograms);
|
||||
postElement(<br />);
|
||||
postSegments(allContracts);
|
||||
postElement(<br />);
|
||||
postSegments(allScripts);
|
||||
},
|
||||
|
||||
executeMemCommand: function(commandArray) {
|
||||
@@ -2136,13 +2166,19 @@ let Terminal = {
|
||||
post("Invalid server IP/hostname");
|
||||
return;
|
||||
}
|
||||
|
||||
if(targetServer instanceof HacknetServer) {
|
||||
post(`${Programs.ServerProfiler.name} cannot be run on a Hacknet Server.`);
|
||||
return
|
||||
}
|
||||
|
||||
post(targetServer.hostname + ":");
|
||||
post("Server base security level: " + targetServer.baseDifficulty);
|
||||
post("Server current security level: " + targetServer.hackDifficulty);
|
||||
post("Server growth rate: " + targetServer.serverGrowth);
|
||||
post(`Netscript hack() execution time: ${convertTimeMsToTimeElapsedString(calculateHackingTime(targetServer, Player)*1000)}`);
|
||||
post(`Netscript grow() execution time: ${convertTimeMsToTimeElapsedString(calculateGrowTime(targetServer, Player)*1000)}`);
|
||||
post(`Netscript weaken() execution time: ${convertTimeMsToTimeElapsedString(calculateWeakenTime(targetServer, Player)*1000)}`);
|
||||
post(`Netscript hack() execution time: ${convertTimeMsToTimeElapsedString(calculateHackingTime(targetServer, Player)*1000, true)}`);
|
||||
post(`Netscript grow() execution time: ${convertTimeMsToTimeElapsedString(calculateGrowTime(targetServer, Player)*1000, true)}`);
|
||||
post(`Netscript weaken() execution time: ${convertTimeMsToTimeElapsedString(calculateWeakenTime(targetServer, Player)*1000, true)}`);
|
||||
};
|
||||
programHandlers[Programs.AutoLink.name] = () => {
|
||||
post("This executable cannot be run.");
|
||||
|
||||
@@ -107,10 +107,10 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
{
|
||||
desc: (n: number): string => {
|
||||
return ["It is possible write four as a sum in exactly four different ways:\n\n",
|
||||
" 3 + 1\n",
|
||||
" 2 + 2\n",
|
||||
" 2 + 1 + 1\n",
|
||||
" 1 + 1 + 1 + 1\n\n",
|
||||
" 3 + 1\n",
|
||||
" 2 + 2\n",
|
||||
" 2 + 1 + 1\n",
|
||||
" 1 + 1 + 1 + 1\n\n",
|
||||
`How many different ways can the number ${n} be written as a sum of at least`,
|
||||
"two positive integers?"].join(" ");
|
||||
},
|
||||
@@ -142,17 +142,17 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
}
|
||||
d += ["\nHere is an example of what spiral order should be:",
|
||||
"\nExample:",
|
||||
" [\n",
|
||||
" [1, 2, 3],\n",
|
||||
" [4, 5, 6],\n",
|
||||
" [7, 8, 9]\n",
|
||||
" ] should result in [1, 2, 3, 6, 9, 8 ,7, 4, 5]\n\n",
|
||||
" [\n",
|
||||
" [1, 2, 3],\n",
|
||||
" [4, 5, 6],\n",
|
||||
" [7, 8, 9]\n",
|
||||
" ] should result in [1, 2, 3, 6, 9, 8 ,7, 4, 5]\n\n",
|
||||
"Note that the matrix will not always be square:\n",
|
||||
" [\n",
|
||||
" [1, 2, 3, 4]\n",
|
||||
" [5, 6, 7, 8]\n",
|
||||
" [9, 10, 11, 12]\n",
|
||||
" ] should result in [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7"].join(" ");
|
||||
" [\n",
|
||||
" [1, 2, 3, 4]\n",
|
||||
" [5, 6, 7, 8]\n",
|
||||
" [9, 10, 11, 12]\n",
|
||||
" ] should result in [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7"].join(" ");
|
||||
|
||||
return d;
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ import {
|
||||
scriptEditorInit,
|
||||
updateScriptEditorContent,
|
||||
} from "./Script/ScriptHelpers";
|
||||
import { initForeignServers } from "./Server/AllServers";
|
||||
import { initForeignServers, AllServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { initSpecialServerIps } from "./Server/SpecialServerIps";
|
||||
@@ -643,12 +643,6 @@ const Engine = {
|
||||
clickListener: (e) => {
|
||||
if (!e.isTrusted) { return false; }
|
||||
joinFaction(Factions[factionName]);
|
||||
for (var i = 0; i < Player.factionInvitations.length; ++i) {
|
||||
if (Player.factionInvitations[i] == factionName || Factions[Player.factionInvitations[i]].isBanned) {
|
||||
Player.factionInvitations.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
Engine.displayFactionsInfo();
|
||||
return false;
|
||||
},
|
||||
@@ -1542,8 +1536,10 @@ const Engine = {
|
||||
|
||||
// DEBUG Delete active Scripts on home
|
||||
document.getElementById("debug-delete-scripts-link").addEventListener("click", function() {
|
||||
Player.getHomeComputer().runningScripts = [];
|
||||
dialogBoxCreate("Forcefully deleted all running scripts on home computer. Please save and refresh page");
|
||||
for(const hostname of Object.keys(AllServers)) {
|
||||
AllServers[hostname].runningScripts = [];
|
||||
}
|
||||
dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page.");
|
||||
gameOptionsBoxClose();
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -340,8 +340,8 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
Would you like to join? <br /> <br />
|
||||
Warning: Joining this faction may prevent you from joining other factions during this run!
|
||||
</p>
|
||||
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
|
||||
<button id="faction-invitation-box-no" class="popup-box-button"> No </button>
|
||||
<button id="faction-invitation-box-yes" class="popup-box-button"> Join! </button>
|
||||
<button id="faction-invitation-box-no" class="popup-box-button"> Decide later </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -600,14 +600,14 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
Copy Save data to Clipboard
|
||||
</button>
|
||||
<button id="debug-delete-scripts-link" class="a-link-button tooltip">
|
||||
(DEBUG) Delete Active Scripts
|
||||
Delete all active scripts
|
||||
<span class="tooltiptextleft">
|
||||
Debug option used to forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After
|
||||
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After
|
||||
using this, save the game and then reload the page.
|
||||
</span>
|
||||
</button>
|
||||
<button id="debug-soft-reset" class="a-link-button tooltip">
|
||||
(DEBUG) Soft Reset
|
||||
Soft Reset
|
||||
<span class="tooltiptextleft">
|
||||
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
|
||||
</span>
|
||||
|
||||
@@ -49,7 +49,7 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
|
||||
panelClass="active-scripts-script-panel"
|
||||
panelContent={
|
||||
<>
|
||||
<pre>Threads: {props.workerScript.scriptRef.threads}</pre>
|
||||
<pre>Threads: {numeralWrapper.formatThreads(props.workerScript.scriptRef.threads)}</pre>
|
||||
<pre>Args: {arrayToString(props.workerScript.args)}</pre>
|
||||
<pre>Online Time: {convertTimeMsToTimeElapsedString(scriptRef.onlineRunningTime * 1e3)}</pre>
|
||||
<pre>Offline Time: {convertTimeMsToTimeElapsedString(scriptRef.offlineRunningTime * 1e3)}</pre>
|
||||
|
||||
@@ -108,6 +108,18 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
||||
</>
|
||||
}
|
||||
|
||||
function BladeburnerMults(): React.ReactElement {
|
||||
if(!p.canAccessBladeburner()) return (<></>);
|
||||
return (<>
|
||||
<MultiplierTable rows={[
|
||||
['Bladeburner Success Chance', p.bladeburner_max_stamina_mult],
|
||||
['Bladeburner Max Stamina', p.bladeburner_stamina_gain_mult],
|
||||
['Bladeburner Stamina Gain', p.bladeburner_analysis_mult],
|
||||
['Bladeburner Field Analysis', p.bladeburner_success_chance_mult],
|
||||
]} /><br />
|
||||
</>);
|
||||
}
|
||||
|
||||
function CurrentBitNode(): React.ReactElement {
|
||||
if(p.sourceFiles.length > 0) {
|
||||
|
||||
@@ -233,7 +245,9 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
||||
<MultiplierTable rows={[
|
||||
['Crime success', p.crime_success_mult],
|
||||
['Crime money', p.crime_money_mult, p.crime_money_mult*BitNodeMultipliers.CrimeMoney],
|
||||
]} /><br /><br />
|
||||
]} /><br />
|
||||
|
||||
<BladeburnerMults /><br />
|
||||
|
||||
<b>Misc.</b><br /><br />
|
||||
<span>{`Servers owned: ${p.purchasedServers.length} / ${getPurchaseServerLimit()}`}</span><br />
|
||||
|
||||
@@ -24,10 +24,19 @@ export function AugmentationAccordion(props: IProps): React.ReactElement {
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof props.aug.info === 'string') {
|
||||
return (
|
||||
<Accordion
|
||||
headerContent={<>{displayName}</>}
|
||||
panelContent={<p dangerouslySetInnerHTML={{__html: props.aug.info}}></p>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
headerContent={<>{displayName}</>}
|
||||
panelContent={<p dangerouslySetInnerHTML={{__html: props.aug.info}}></p>}
|
||||
panelContent={<p>{props.aug.info}</p>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ export class CharacterOverviewComponent extends Component {
|
||||
);
|
||||
|
||||
return (
|
||||
<div id="character-overview-text">
|
||||
<table>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr id="character-hp-wrapper">
|
||||
<td className="character-hp-cell">Hp:</td><td id="character-hp-text" className="character-hp-cell character-stat-cell">{numeralWrapper.formatHp(Player.hp) + " / " + numeralWrapper.formatHp(Player.max_hp)}</td>
|
||||
@@ -47,8 +46,7 @@ export class CharacterOverviewComponent extends Component {
|
||||
intelligence
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
}
|
||||
61
src/ui/React/CodingContractPopup.tsx
Normal file
61
src/ui/React/CodingContractPopup.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as React from "react";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
import { CodingContract, CodingContractType, CodingContractTypes } from "../../CodingContracts";
|
||||
import { ClickableTag, CopyableText } from "./CopyableText";
|
||||
import { PopupCloseButton } from "./PopupCloseButton";
|
||||
|
||||
type IProps = {
|
||||
c: CodingContract;
|
||||
popupId: string;
|
||||
onClose: () => void;
|
||||
onAttempt: (answer: string) => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
answer: string;
|
||||
}
|
||||
|
||||
export class CodingContractPopup extends React.Component<IProps, IState>{
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = { answer: ''};
|
||||
this.setAnswer = this.setAnswer.bind(this);
|
||||
this.onInputKeydown = this.onInputKeydown.bind(this);
|
||||
}
|
||||
|
||||
setAnswer(event: any) {
|
||||
this.setState({ answer: event.target.value });
|
||||
}
|
||||
|
||||
onInputKeydown(e:any){
|
||||
if (e.keyCode === KEY.ENTER && e.target.value !== "") {
|
||||
e.preventDefault();
|
||||
this.props.onAttempt(this.state.answer);
|
||||
} else if (e.keyCode === KEY.ESC) {
|
||||
e.preventDefault();
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const contractType: CodingContractType = CodingContractTypes[this.props.c.type];
|
||||
let description = [];
|
||||
for (const [i, value] of contractType.desc(this.props.c.data).split('\n').entries())
|
||||
description.push(<span key={i} dangerouslySetInnerHTML={{__html: value+'<br />'}}></span>);
|
||||
return (
|
||||
<div>
|
||||
<CopyableText value={this.props.c.type} tag={ClickableTag.Tag_h1} />
|
||||
<br/><br/>
|
||||
<p>You are attempting to solve a Coding Contract. You have {this.props.c.getMaxNumTries() - this.props.c.tries} tries remaining, after which the contract will self-destruct.</p>
|
||||
<br/>
|
||||
<p>{description}</p>
|
||||
<br/>
|
||||
<input className="text-input" style={{ width:"50%",marginTop:"8px" }} autoFocus={true} placeholder="Enter Solution here" value={this.state.answer}
|
||||
onChange={this.setAnswer} onKeyDown={this.onInputKeydown} />
|
||||
<PopupCloseButton popup={this.props.popupId} onClose={() => this.props.onAttempt(this.state.answer)} text={"Solve"} />
|
||||
<PopupCloseButton popup={this.props.popupId} onClose={this.props.onClose} text={"Close"} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
import * as React from "react";
|
||||
|
||||
export enum ClickableTag{
|
||||
Tag_span,
|
||||
Tag_h1
|
||||
}
|
||||
|
||||
type IProps = {
|
||||
value: string;
|
||||
tag: ClickableTag;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
@@ -9,6 +15,11 @@ type IState = {
|
||||
}
|
||||
|
||||
export class CopyableText extends React.Component<IProps, IState> {
|
||||
public static defaultProps = {
|
||||
//Default span to prevent destroying current clickables
|
||||
tag: ClickableTag.Tag_span
|
||||
};
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
@@ -53,9 +64,19 @@ export class CopyableText extends React.Component<IProps, IState> {
|
||||
|
||||
|
||||
render(): React.ReactNode {
|
||||
return (<span className={this.textClasses()} onClick={this.copy}>
|
||||
<b>{this.props.value}</b>
|
||||
<span className={this.tooltipClasses()}>Copied!</span>
|
||||
</span>);
|
||||
switch (this.props.tag) {
|
||||
case ClickableTag.Tag_h1:
|
||||
return (
|
||||
<h1 className={this.textClasses()} onClick={this.copy}>
|
||||
{this.props.value}
|
||||
<span className={this.tooltipClasses()}>Copied!</span>
|
||||
</h1>)
|
||||
case ClickableTag.Tag_span:
|
||||
return (
|
||||
<span className={this.textClasses()} onClick={this.copy}>
|
||||
<b>{this.props.value}</b>
|
||||
<span className={this.tooltipClasses()}>Copied!</span>
|
||||
</span>)
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/ui/React/PopupButton.tsx
Normal file
72
src/ui/React/PopupButton.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Basic button for popup dialog boxes
|
||||
* It creates an event handler such that pressing Esc will perform the click handler.
|
||||
*
|
||||
* Should only be used in other React components, otherwise it may not be properly
|
||||
* unmounted
|
||||
*/
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||
|
||||
export interface IPopupButtonProps {
|
||||
class?: string;
|
||||
popup: HTMLElement | string;
|
||||
style?: object;
|
||||
text: string;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export class PopupButton extends React.Component<IPopupButtonProps, any> {
|
||||
constructor(props: IPopupButtonProps) {
|
||||
super(props);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.keyListener = this.keyListener.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener("keydown", this.keyListener);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener("keydown", this.keyListener);
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
if(this.props.onClose)
|
||||
this.props.onClose();
|
||||
//We might be able to remove this?
|
||||
//Clickhandler from the props will override this anyhow.
|
||||
let popup: HTMLElement | null;
|
||||
if (typeof this.props.popup === "string") {
|
||||
popup = document.getElementById(this.props.popup);
|
||||
} else {
|
||||
popup = this.props.popup;
|
||||
}
|
||||
// TODO Check if this is okay? This is essentially calling to unmount a parent component
|
||||
if (popup instanceof HTMLElement) {
|
||||
ReactDOM.unmountComponentAtNode(popup); // Removes everything inside the wrapper container
|
||||
removeElement(popup); // Removes the wrapper container
|
||||
}
|
||||
}
|
||||
|
||||
keyListener(e: KeyboardEvent) {
|
||||
//This doesn't really make sense, a button doesnt have to listen to escape IMO
|
||||
//Too affraid to remove it since im not sure what it will break.. But yuck..
|
||||
if (e.keyCode === KEY.ESC) {
|
||||
this.handleClick();
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const className = this.props.class ? this.props.class : "std-button";
|
||||
|
||||
return (
|
||||
<button className={className} onClick={this.handleClick} style={this.props.style}>
|
||||
{this.props.text}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -8,33 +8,27 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||
import { IPopupButtonProps, PopupButton } from "./PopupButton";
|
||||
|
||||
export interface IPopupCloseButtonProps {
|
||||
export interface IPopupCloseButtonProps extends IPopupButtonProps {
|
||||
class?: string;
|
||||
popup: HTMLElement | string;
|
||||
style?: any;
|
||||
text: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export class PopupCloseButton extends React.Component<IPopupCloseButtonProps, any> {
|
||||
export class PopupCloseButton extends PopupButton {
|
||||
constructor(props: IPopupCloseButtonProps) {
|
||||
super(props);
|
||||
|
||||
this.closePopup = this.closePopup.bind(this);
|
||||
this.keyListener = this.keyListener.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
document.addEventListener("keydown", this.keyListener);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
document.removeEventListener("keydown", this.keyListener);
|
||||
}
|
||||
|
||||
closePopup(): void {
|
||||
if(this.props.onClose)
|
||||
this.props.onClose();
|
||||
let popup: HTMLElement | null;
|
||||
if (typeof this.props.popup === "string") {
|
||||
popup = document.getElementById(this.props.popup);
|
||||
@@ -42,24 +36,23 @@ export class PopupCloseButton extends React.Component<IPopupCloseButtonProps, an
|
||||
popup = this.props.popup;
|
||||
}
|
||||
|
||||
// TODO Check if this is okay? This is essentially calling to unmount a parent component
|
||||
// TODO Check if this is okay? This is essentially calling to unmount a
|
||||
// parent component
|
||||
if (popup instanceof HTMLElement) {
|
||||
ReactDOM.unmountComponentAtNode(popup); // Removes everything inside the wrapper container
|
||||
// Removes everything inside the wrapper container
|
||||
ReactDOM.unmountComponentAtNode(popup);
|
||||
removeElement(popup); // Removes the wrapper container
|
||||
}
|
||||
}
|
||||
|
||||
keyListener(e: KeyboardEvent): void {
|
||||
if (e.keyCode === KEY.ESC) {
|
||||
this.closePopup();
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const className = this.props.class ? this.props.class : "std-button";
|
||||
|
||||
return (
|
||||
<button className={className} onClick={this.closePopup} style={this.props.style}>
|
||||
<button
|
||||
className={className}
|
||||
onClick={this.closePopup}
|
||||
style={this.props.style}>
|
||||
{this.props.text}
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -53,6 +53,9 @@ class NumeralFormatter {
|
||||
}
|
||||
|
||||
formatMoney(n: number): string {
|
||||
if(Math.abs(n) < 1000) {
|
||||
return this.format(n, "$0.00");
|
||||
}
|
||||
return this.format(n, "$0.000a");
|
||||
}
|
||||
|
||||
@@ -131,6 +134,26 @@ class NumeralFormatter {
|
||||
formatInfiltrationSecurity(n: number): string {
|
||||
return this.format(n, "0.000a");
|
||||
}
|
||||
|
||||
formatThreads(n: number): string {
|
||||
return this.format(n, "0,0");
|
||||
}
|
||||
|
||||
parseMoney(s: string): number {
|
||||
// numeral library does not handle formats like 1e10 well (returns 110),
|
||||
// so if both return a valid number, return the biggest one
|
||||
const numeralValue = numeral(s).value();
|
||||
const parsed = parseFloat(s);
|
||||
if (isNaN(parsed) && numeralValue === null) {
|
||||
return NaN;
|
||||
} else if (isNaN(parsed)) {
|
||||
return numeralValue;
|
||||
} else if (numeralValue === null) {
|
||||
return parsed;
|
||||
} else {
|
||||
return Math.max(numeralValue, parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const numeralWrapper = new NumeralFormatter();
|
||||
|
||||
@@ -394,6 +394,16 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function() {
|
||||
await testNonzeroDynamicRamCost(f);
|
||||
});
|
||||
|
||||
it("getServerMaxRam()", async function() {
|
||||
const f = ["getServerMaxRam"];
|
||||
await testNonzeroDynamicRamCost(f);
|
||||
});
|
||||
|
||||
it("getServerUsedRam()", async function() {
|
||||
const f = ["getServerUsedRam"];
|
||||
await testNonzeroDynamicRamCost(f);
|
||||
});
|
||||
|
||||
it("serverExists()", async function() {
|
||||
const f = ["serverExists"];
|
||||
await testNonzeroDynamicRamCost(f);
|
||||
|
||||
@@ -284,6 +284,16 @@ describe("Netscript Static RAM Calculation/Generation Tests", function() {
|
||||
await expectNonZeroRamCost(f);
|
||||
});
|
||||
|
||||
it("getServerMaxRam()", async function() {
|
||||
const f = ["getServerMaxRam"];
|
||||
await expectNonZeroRamCost(f);
|
||||
});
|
||||
|
||||
it("getServerUsedRam()", async function() {
|
||||
const f = ["getServerUsedRam"];
|
||||
await expectNonZeroRamCost(f);
|
||||
});
|
||||
|
||||
it("serverExists()", async function() {
|
||||
const f = ["serverExists"];
|
||||
await expectNonZeroRamCost(f);
|
||||
|
||||
11
test/StringHelperFunctionsTests.ts
Normal file
11
test/StringHelperFunctionsTests.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { expect } from "chai";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
|
||||
describe("StringHelperFunctions Tests", function() {
|
||||
expect(convertTimeMsToTimeElapsedString(1000)).to.equal("1 seconds");
|
||||
expect(convertTimeMsToTimeElapsedString(5*60*1000+34*1000)).to.equal("5 minutes 34 seconds");
|
||||
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000)).to.equal("2 days 5 minutes 34 seconds");
|
||||
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000, true)).to.equal("2 days 5 minutes 34.000 seconds");
|
||||
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000+123, true)).to.equal("2 days 5 minutes 34.123 seconds");
|
||||
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000+123.888, true)).to.equal("2 days 5 minutes 34.123 seconds");
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./Netscript/DynamicRamCalculationTests";
|
||||
export * from "./Netscript/StaticRamCalculationTests";
|
||||
export * from "./StockMarketTests";
|
||||
export * from "./StringHelperFunctionsTests";
|
||||
export * from "./Terminal/DirectoryTests";
|
||||
|
||||
@@ -36,8 +36,6 @@ function factionInvitationBoxCreate(faction) {
|
||||
var i = Player.factionInvitations.findIndex((facName)=>{return facName === faction.name});
|
||||
if (i === -1) {
|
||||
console.error("Could not find faction in Player.factionInvitations");
|
||||
} else {
|
||||
Player.factionInvitations.splice(i, 1);
|
||||
}
|
||||
joinFaction(faction);
|
||||
factionInvitationBoxClose();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { dialogBoxCreate } from "./DialogBox";
|
||||
import { clearEventListeners } from "./uiHelpers/clearEventListeners";
|
||||
import { formatNumber } from "./StringHelperFunctions";
|
||||
import { numeralWrapper } from "../src/ui/numeralFormat";
|
||||
|
||||
import { BitNodeMultipliers } from "../src/BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../src/Constants";
|
||||
@@ -38,12 +38,12 @@ function infiltrationBoxCreate(inst) {
|
||||
Player.gainIntelligenceExp(inst.calcGainedIntelligenceExp());
|
||||
|
||||
const expGainText = ["You gained:",
|
||||
`${formatNumber(inst.calcGainedHackingExp(), 3)} hacking exp`,
|
||||
`${formatNumber(inst.calcGainedStrengthExp(), 3)} str exp`,
|
||||
`${formatNumber(inst.calcGainedDefenseExp(), 3)} def exp`,
|
||||
`${formatNumber(inst.calcGainedDexterityExp(), 3)} dex exp`,
|
||||
`${formatNumber(inst.calcGainedAgilityExp(), 3)} agi exp`,
|
||||
`${formatNumber(inst.calcGainedCharismaExp(), 3)} cha exp`].join("\n");
|
||||
`${numeralWrapper.formatExp(inst.calcGainedHackingExp(), 3)} hacking exp`,
|
||||
`${numeralWrapper.formatExp(inst.calcGainedStrengthExp(), 3)} str exp`,
|
||||
`${numeralWrapper.formatExp(inst.calcGainedDefenseExp(), 3)} def exp`,
|
||||
`${numeralWrapper.formatExp(inst.calcGainedDexterityExp(), 3)} dex exp`,
|
||||
`${numeralWrapper.formatExp(inst.calcGainedAgilityExp(), 3)} agi exp`,
|
||||
`${numeralWrapper.formatExp(inst.calcGainedCharismaExp(), 3)} cha exp`].join("\n");
|
||||
|
||||
var totalValue = 0;
|
||||
for (var i = 0; i < inst.secretsStolen.length; ++i) {
|
||||
@@ -58,9 +58,9 @@ function infiltrationBoxCreate(inst) {
|
||||
CONSTANTS.InfiltrationRepValue * BitNodeMultipliers.InfiltrationRep;
|
||||
var moneyValue = totalValue * CONSTANTS.InfiltrationMoneyValue * BitNodeMultipliers.InfiltrationMoney;
|
||||
infiltrationSetText("You can sell the classified documents and secrets " +
|
||||
"you stole from " + inst.companyName + " for <span class='money-gold'>$" +
|
||||
formatNumber(moneyValue, 2) + "</span> on the black market or you can give it " +
|
||||
"to a faction to gain <span class='light-yellow'>" + formatNumber(facValue, 3) + " reputation</span> with " +
|
||||
"you stole from " + inst.companyName + " for <span class='money-gold'>" +
|
||||
numeralWrapper.formatMoney(moneyValue) + "</span> on the black market or you can give it " +
|
||||
"to a faction to gain <span class='light-yellow'>" + numeralWrapper.formatReputation(facValue) + " reputation</span> with " +
|
||||
"that faction.");
|
||||
var selector = document.getElementById("infiltration-faction-select");
|
||||
selector.innerHTML = "";
|
||||
@@ -88,7 +88,7 @@ function infiltrationBoxCreate(inst) {
|
||||
Player.gainMoney(moneyValue);
|
||||
Player.recordMoneySource(moneyValue, "infiltration");
|
||||
dialogBoxCreate("You sold the classified information you stole from " + inst.companyName +
|
||||
" for <span class='money-gold'>$" + formatNumber(moneyValue, 2) + "</span> on the black market!<br><br>" +
|
||||
" for <span class='money-gold'>" + numeralWrapper.formatMoney(moneyValue) + "</span> on the black market!<br><br>" +
|
||||
expGainText);
|
||||
infiltrationBoxClose();
|
||||
return false;
|
||||
@@ -108,7 +108,7 @@ function infiltrationBoxCreate(inst) {
|
||||
}
|
||||
faction.playerReputation += facValue;
|
||||
dialogBoxCreate("You gave the classified information you stole from " + inst.companyName +
|
||||
" to " + facName + " and gained <span class='light-yellow'>" + formatNumber(facValue, 3) + " reputation</span> with the faction. <br><br>" +
|
||||
" to " + facName + " and gained <span class='light-yellow'>" + numeralWrapper.formatReputation(facValue) + " reputation</span> with the faction. <br><br>" +
|
||||
expGainText);
|
||||
infiltrationBoxClose();
|
||||
return false;
|
||||
|
||||
@@ -13,7 +13,8 @@ Converts a date representing time in milliseconds to a string with the format H
|
||||
e.g. 10000 -> "10 seconds"
|
||||
120000 -> "2 minutes and 0 seconds"
|
||||
*/
|
||||
function convertTimeMsToTimeElapsedString(time: number): string {
|
||||
function convertTimeMsToTimeElapsedString(time: number, showMilli=false): string {
|
||||
time = Math.floor(time);
|
||||
const millisecondsPerSecond = 1000;
|
||||
const secondPerMinute = 60;
|
||||
const minutesPerHours = 60;
|
||||
@@ -33,7 +34,13 @@ function convertTimeMsToTimeElapsedString(time: number): string {
|
||||
const minutes: number = Math.floor(secTruncHours / secondPerMinute);
|
||||
const secTruncMinutes: number = secTruncHours % secondPerMinute;
|
||||
|
||||
const seconds: number = secTruncMinutes;
|
||||
const milliTruncSec: string = (() => {
|
||||
let str = `${time % millisecondsPerSecond}`;
|
||||
while(str.length < 3) str = "0"+str;
|
||||
return str;
|
||||
})()
|
||||
|
||||
const seconds: string = showMilli ? `${secTruncMinutes}.${milliTruncSec}` : `${secTruncMinutes}`;
|
||||
|
||||
let res = "";
|
||||
if (days > 0) {res += `${days} days `; }
|
||||
|
||||
Reference in New Issue
Block a user