mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-17 14:59:16 +02:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
135df8703c | ||
|
|
4743801e86 | ||
|
|
4e5ebcfe6f | ||
|
|
80b703639e | ||
|
|
0afdba8f38 | ||
|
|
925e96345d | ||
|
|
db2bf79e3b | ||
|
|
6f330efc44 | ||
|
|
708c73fa0f | ||
|
|
c7febd5551 | ||
|
|
ddbdf66d00 |
10
README_contribution.md
Normal file
10
README_contribution.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Deploying a new version
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Update the following
|
||||||
|
- `src/Constants.ts` `Version` and `LatestUpdate`
|
||||||
|
- `package.json` `version`
|
||||||
|
- `doc/source/conf.py` `version` and `release`
|
||||||
|
- `doc/source/changelog.rst`
|
||||||
|
- post to discord
|
||||||
|
- post to reddit.com/r/Bitburner
|
||||||
@@ -184,5 +184,4 @@
|
|||||||
|
|
||||||
#infiltration-buttons .a-link-button {
|
#infiltration-buttons .a-link-button {
|
||||||
display: inline;
|
display: inline;
|
||||||
width: 25%;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,14 +228,15 @@ a:visited {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
display: inline-block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
-webkit-animation: status-text 3s 1;
|
-webkit-animation: status-text 3s 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#status-text-container {
|
#status-text-container {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#status-text {
|
#status-text {
|
||||||
|
|||||||
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([395,0]),o()}({338:function(n,t,o){},340:function(n,t,o){},342:function(n,t,o){},344:function(n,t,o){},346:function(n,t,o){},348:function(n,t,o){},350:function(n,t,o){},352:function(n,t,o){},354:function(n,t,o){},356:function(n,t,o){},358:function(n,t,o){},360:function(n,t,o){},362:function(n,t,o){},364:function(n,t,o){},366:function(n,t,o){},368:function(n,t,o){},370:function(n,t,o){},372:function(n,t,o){},374:function(n,t,o){},376:function(n,t,o){},378:function(n,t,o){},380:function(n,t,o){},382:function(n,t,o){},384:function(n,t,o){},386:function(n,t,o){},388:function(n,t,o){},390:function(n,t,o){},392:function(n,t,o){},395:function(n,t,o){"use strict";o.r(t);o(394),o(392),o(390),o(388),o(386),o(384),o(382),o(380),o(378),o(376),o(374),o(372),o(370),o(368),o(366),o(364),o(362),o(360),o(358),o(356),o(354),o(352),o(350),o(348),o(346),o(344),o(342),o(340),o(338)}});
|
!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([401,0]),o()}({344:function(n,t,o){},346:function(n,t,o){},348:function(n,t,o){},350:function(n,t,o){},352:function(n,t,o){},354:function(n,t,o){},356:function(n,t,o){},358:function(n,t,o){},360:function(n,t,o){},362:function(n,t,o){},364:function(n,t,o){},366:function(n,t,o){},368:function(n,t,o){},370:function(n,t,o){},372:function(n,t,o){},374:function(n,t,o){},376:function(n,t,o){},378:function(n,t,o){},380:function(n,t,o){},382:function(n,t,o){},384:function(n,t,o){},386:function(n,t,o){},388:function(n,t,o){},390:function(n,t,o){},392:function(n,t,o){},394:function(n,t,o){},396:function(n,t,o){},398:function(n,t,o){},401:function(n,t,o){"use strict";o.r(t);o(400),o(398),o(396),o(394),o(392),o(390),o(388),o(386),o(384),o(382),o(380),o(378),o(376),o(374),o(372),o(370),o(368),o(366),o(364),o(362),o(360),o(358),o(356),o(354),o(352),o(350),o(348),o(346),o(344)}});
|
||||||
//# sourceMappingURL=engineStyle.bundle.js.map
|
//# sourceMappingURL=engineStyle.bundle.js.map
|
||||||
10
dist/engineStyle.css
vendored
10
dist/engineStyle.css
vendored
@@ -250,13 +250,14 @@ a:visited {
|
|||||||
opacity: 0; } }
|
opacity: 0; } }
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
display: inline-block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
-webkit-animation: status-text 3s 1; }
|
-webkit-animation: status-text 3s 1; }
|
||||||
|
|
||||||
#status-text-container {
|
#status-text-container {
|
||||||
background-color: transparent; }
|
background-color: transparent;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%; }
|
||||||
|
|
||||||
#status-text {
|
#status-text {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@@ -1374,8 +1375,7 @@ button {
|
|||||||
margin-top: 20px; }
|
margin-top: 20px; }
|
||||||
|
|
||||||
#infiltration-buttons .a-link-button {
|
#infiltration-buttons .a-link-button {
|
||||||
display: inline;
|
display: inline; }
|
||||||
width: 25%; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Styling for the Augmentations UI. This is the page that displays all of the
|
* Styling for the Augmentations UI. This is the page that displays all of the
|
||||||
|
|||||||
26
dist/vendor.bundle.js
vendored
26
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -75,13 +75,10 @@ List of Factions and their Requirements
|
|||||||
| | | | * Ishima |
|
| | | | * Ishima |
|
||||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||||
| Hacking | NiteSec | * Hack avmnite-02h manually | |
|
| Hacking | NiteSec | * Hack avmnite-02h manually | |
|
||||||
| Groups | | * Home Computer RAM of at least 32GB | |
|
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | The Black Hand | * Hack I.I.I.I manually | |
|
| | The Black Hand | * Hack I.I.I.I manually | |
|
||||||
| | | * Home Computer RAM of at least 64GB | |
|
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | Bitrunners | * Hack run4theh111z manually | |
|
| | Bitrunners | * Hack run4theh111z manually | |
|
||||||
| | | * Home Computer RAM of at least 128GB | |
|
|
||||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||||
| Megacorporations | ECorp | * Have 200k reputation with | |
|
| Megacorporations | ECorp | * Have 200k reputation with | |
|
||||||
| | | the Corporation | |
|
| | | the Corporation | |
|
||||||
|
|||||||
@@ -3,6 +3,127 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
v0.51.4 - 2021-04-19 Manual hacking is fun (hydroflame)
|
||||||
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
Manual hacking
|
||||||
|
|
||||||
|
* These bonus require an install or a soft reset to take effect.
|
||||||
|
* Manual hacking gyms and university gives you a 10% discount.
|
||||||
|
* Manual hacking a corporation server decreases the penalty for leaving work
|
||||||
|
early.
|
||||||
|
|
||||||
|
BladeBurner
|
||||||
|
|
||||||
|
* nerfed int exp gained.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
|
||||||
|
* purchaseServer specifies what happens on failure.
|
||||||
|
* Fixed typo in recommended bitnode page.
|
||||||
|
* Removed misleading ram requirements for hacking factions.
|
||||||
|
|
||||||
|
Netscript
|
||||||
|
|
||||||
|
* growthAnalyze handles Infinity correctly.
|
||||||
|
|
||||||
|
Misc.
|
||||||
|
|
||||||
|
* Faction Augmentation will list how much reputation is required even after
|
||||||
|
that goal has been reached.
|
||||||
|
* Removed dollar sign in travel agency confirmation dialog box.
|
||||||
|
* Fixed typo in alpha-omega.lit
|
||||||
|
* the 'Game saved!' text no longer blocks the save game/options button.
|
||||||
|
* The text editor now remembers the location of your cursor and restores it.
|
||||||
|
* skills are recalculated instantly.
|
||||||
|
* Fix typo in Operation Zero description.
|
||||||
|
|
||||||
|
v0.51.3 - 2021-04-16 Y'all broke it on the first day (hydroflame)
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
**Passive faction reputation**
|
||||||
|
|
||||||
|
* Reworked, from 1 rep / 2 minute. Now is a complicated percentage of the
|
||||||
|
reputation you'd gain working for them. It's not op but it feels a bit
|
||||||
|
more useful.
|
||||||
|
|
||||||
|
**Netscript**
|
||||||
|
|
||||||
|
* print/tprint now take any number of arguments.
|
||||||
|
* print/tprint will now print object as json.
|
||||||
|
* print/tprint now handle passing in an undefined argument properly.
|
||||||
|
|
||||||
|
**Casino**
|
||||||
|
|
||||||
|
* Cannot bet negative money anymore.
|
||||||
|
* Roulette max bet is a bit higher.
|
||||||
|
* Coin Flip has a small cooldown.
|
||||||
|
* All buttons reject unstrusted mouse events.
|
||||||
|
|
||||||
|
**Documentation**
|
||||||
|
|
||||||
|
* Changed a message that said nsjs only works on Chrome.
|
||||||
|
|
||||||
|
**Bugfix**
|
||||||
|
|
||||||
|
* hacknet.maxNumNodes now works for both nodes and servers.
|
||||||
|
* Fixed a bug where the popup boxes would contain data from previous popup boxes.
|
||||||
|
* .js files will also have the 'export async function' boilerplate.
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* turned off web form autocomplete for the terminal text input.
|
||||||
|
* Fixed an issue on Windows+Firefox where pressing up on the terminal would
|
||||||
|
bring the cursor to the begining of the line. (Issue #836)
|
||||||
|
* Hacknet node names is easier to handle for screen readers.
|
||||||
|
* Money spent on classes is now tracked independently of work money.
|
||||||
|
* running coding contract from the terminal will display its name.
|
||||||
|
|
||||||
|
v0.51.2 - 2021-04-09 Vegas, Baby! (hydroflame)
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
**New location: The Iker Molina Casino**
|
||||||
|
|
||||||
|
* A casino opened in Aevum. However the house is rumored to cheat. If only
|
||||||
|
we could give them a taste of their own medicine.
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* Link to discord added under options
|
||||||
|
* 'getMemberInformation' doc updated, oops
|
||||||
|
* tech vendor now handle max ram and cores.
|
||||||
|
|
||||||
|
v0.51.1 - 2021-04-06 Bugfixes because the author of the last patch sucks (it's hydroflame)
|
||||||
|
------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
**Netscript**
|
||||||
|
|
||||||
|
* 'getPlayer' returns players faction and tor
|
||||||
|
* 'hospitalization' is a new singularity function.
|
||||||
|
* 'gang.getMemberInformation' now returns more information.
|
||||||
|
* 'hacknet.hashCapacity' is a new hacknet function that returns the maximum hash capacity.
|
||||||
|
|
||||||
|
**Hospitalization**
|
||||||
|
|
||||||
|
* Now only cost at most 10% of your money.
|
||||||
|
|
||||||
|
**Bugfix**
|
||||||
|
|
||||||
|
* confirmation dialog box no longer use previous text
|
||||||
|
|
||||||
|
**Accessibility**
|
||||||
|
|
||||||
|
* The game is a little easier to handle for screen readers (yes, there's an
|
||||||
|
absolute legend playing this game with a screen reader)
|
||||||
|
* Infiltration use buttons instead of a-links
|
||||||
|
* New option to disable ASCII art. This will make the metro map and world
|
||||||
|
map display as a list of buttons.
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* 'fl1ght.exe' will no longer suggest the combat path. Related faction
|
||||||
|
requirements unchanged.
|
||||||
|
|
||||||
v0.51.0 - 2021-03-31 Formulas (hydroflame)
|
v0.51.0 - 2021-03-31 Formulas (hydroflame)
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
|||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.51'
|
version = '0.51'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.51.0'
|
release = '0.51.4'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|||||||
@@ -278,6 +278,7 @@ Description
|
|||||||
hashes, which can be spent on a variety of different upgrades.
|
hashes, which can be spent on a variety of different upgrades.
|
||||||
|
|
||||||
In this BitNode:
|
In this BitNode:
|
||||||
|
|
||||||
* Your stats are significantly decreased
|
* Your stats are significantly decreased
|
||||||
* You cannnot purchase additional servers
|
* You cannnot purchase additional servers
|
||||||
* Hacking is significantly less profitable
|
* Hacking is significantly less profitable
|
||||||
@@ -312,6 +313,7 @@ Description
|
|||||||
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
|
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
|
||||||
|
|
||||||
In this BitNode:
|
In this BitNode:
|
||||||
|
|
||||||
* Your stats are significantly decreased
|
* Your stats are significantly decreased
|
||||||
* All methods of gaining money are half as profitable (except Stock Market)
|
* All methods of gaining money are half as profitable (except Stock Market)
|
||||||
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit
|
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
print() Netscript Function
|
print() Netscript Function
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
.. js:function:: print(x)
|
.. js:function:: print(args...)
|
||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param x: Value to be printed.
|
:param args: Values to be printed.
|
||||||
|
|
||||||
Prints a value or a variable to the script's logs.
|
Prints any number of values to the script's logs.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
print("Hello world!"); // Prints "Hello world!" in the logs.
|
print("Hello world!"); // Prints "Hello world!" in the logs.
|
||||||
|
print({a:5}); // Prints '{"a":5}' in the logs.
|
||||||
@@ -7,7 +7,7 @@ purchaseServer() Netscript Function
|
|||||||
:param string hostname: Hostname of the purchased server.
|
:param string hostname: Hostname of the purchased server.
|
||||||
:param number ram: Amount of RAM of the purchased server. Must be a power of
|
:param number ram: Amount of RAM of the purchased server. Must be a power of
|
||||||
2. Maximum value of :doc:`getPurchasedServerMaxRam<getPurchasedServerMaxRam>`
|
2. Maximum value of :doc:`getPurchasedServerMaxRam<getPurchasedServerMaxRam>`
|
||||||
:returns: The hostname of the newly purchased server.
|
:returns: The hostname of the newly purchased server. Empty string on failure.
|
||||||
|
|
||||||
Purchased a server with the specified hostname and amount of RAM.
|
Purchased a server with the specified hostname and amount of RAM.
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
tprint() Netscript Function
|
tprint() Netscript Function
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
.. js:function:: tprint(x)
|
.. js:function:: tprint(args...)
|
||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param x: Value to be printed
|
:param args: Values to be printed
|
||||||
|
|
||||||
Prints a value or a variable to the Terminal.
|
Prints any number of values to the Terminal.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
tprint("Hello world!"); // Prints "Hello world!" to the terminal.
|
tprint("Hello world!"); // Prints "Hello world!" to the terminal.
|
||||||
|
tprint({a:5}); // Prints '{"a":5}' to the terminal.
|
||||||
@@ -5,7 +5,7 @@ calculateExp() Netscript Function
|
|||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param number skillLevel: ``skillLevel`` to convert to exp.
|
:param number skillLevel: ``skillLevel`` to convert to exp.
|
||||||
:param number mult: Assume a specific skill multipler.
|
:param number mult: Assume a specific skill multipler (not exp multiplier).
|
||||||
:returns: number of exp required to reach given ``skillLevel`` with that multiplier.
|
:returns: number of exp required to reach given ``skillLevel`` with that multiplier.
|
||||||
|
|
||||||
You must have Source-File 5-1 in order to use this function.
|
You must have Source-File 5-1 in order to use this function.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ calculateSkill() Netscript Function
|
|||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param number exp: ``exp`` to convert to skillLevel.
|
:param number exp: ``exp`` to convert to skillLevel.
|
||||||
:param number mult: Assume a specific skill multipler.
|
:param number mult: Assume a specific skill multipler (not exp multiplier).
|
||||||
:returns: skillLevel that ``exp`` would reach with that multiplier.
|
:returns: skillLevel that ``exp`` would reach with that multiplier.
|
||||||
|
|
||||||
You must have Source-File 5-1 in order to use this function.
|
You must have Source-File 5-1 in order to use this function.
|
||||||
|
|||||||
@@ -10,27 +10,35 @@ getMemberInformation() Netscript Function
|
|||||||
The object has the following structure::
|
The object has the following structure::
|
||||||
|
|
||||||
{
|
{
|
||||||
agility: Agility stat
|
name: Name of this member.
|
||||||
agilityEquipMult: Agility multiplier from equipment. Decimal form
|
task: Name of currently assigned task.
|
||||||
agilityAscensionMult: Agility multiplier from ascension. Decimal form
|
earnedRespect: Total amount of respect earned by this member.
|
||||||
augmentations: Array of names of all owned Augmentations
|
hack: Hacking stat
|
||||||
charisma: Charisma stat
|
str: Strength stat
|
||||||
charismaEquipMult: Charisma multiplier from equipment. Decimal form
|
def: Defense stat
|
||||||
charismaAscensionMult: Charisma multiplier from ascension. Decimal form
|
dex: Dexterity stat
|
||||||
defense: Defense stat
|
agi: Agility stat
|
||||||
defenseEquipMult: Defense multiplier from equipment. Decimal form
|
cha: Charisma stat
|
||||||
defenseAscensionMult: Defense multiplier from ascension. Decimal form
|
hack_exp: Hacking experience
|
||||||
dexterity: Dexterity stat
|
str_exp: Strength experience
|
||||||
dexterityEquipMult: Dexterity multiplier from equipment. Decimal form
|
def_exp: Defense experience
|
||||||
dexterityAscensionMult: Dexterity multiplier from ascension. Decimal form
|
dex_exp: Dexterity experience
|
||||||
equipment: Array of names of all owned Non-Augmentation Equipment
|
agi_exp: Agility experience
|
||||||
hacking: Hacking stat
|
cha_exp: Charisma experience
|
||||||
hackingEquipMult: Hacking multiplier from equipment. Decimal form
|
hack_mult: Hacking multiplier from equipment. Decimal form
|
||||||
hackingAscensionMult: Hacking multiplier from ascension. Decimal form
|
str_mult: Strength multiplier from equipment. Decimal form
|
||||||
strength: Strength stat
|
def_mult: Defense multiplier from equipment. Decimal form
|
||||||
strengthEquipMult: Strength multiplier from equipment. Decimal form
|
dex_mult: Dexterity multiplier from equipment. Decimal form
|
||||||
strengthAscensionMult: Strength multiplier from ascension. Decimal form
|
agi_mult: Agility multiplier from equipment. Decimal form
|
||||||
task: Name of currently assigned task
|
cha_mult: Charisma multiplier from equipment. Decimal form
|
||||||
|
hack_asc_mult: Hacking multiplier from ascension. Decimal form
|
||||||
|
str_asc_mult: Strength multiplier from ascension. Decimal form
|
||||||
|
def_asc_mult: Defense multiplier from ascension. Decimal form
|
||||||
|
dex_asc_mult: Dexterity multiplier from ascension. Decimal form
|
||||||
|
agi_asc_mult: Agility multiplier from ascension. Decimal form
|
||||||
|
cha_asc_mult: Charisma multiplier from ascension. Decimal form
|
||||||
|
upgrades: Array of names of all owned Non-Augmentation Equipment
|
||||||
|
augmentations: Array of names of all owned Augmentations
|
||||||
}
|
}
|
||||||
|
|
||||||
Get stat and equipment-related information about a Gang Member
|
Get stat and equipment-related information about a Gang Member
|
||||||
12
doc/source/netscript/hacknetnodeapi/hashCapacity.rst
Normal file
12
doc/source/netscript/hacknetnodeapi/hashCapacity.rst
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
hashCapacity() Netscript Function
|
||||||
|
=================================
|
||||||
|
|
||||||
|
.. warning:: This page contains spoilers for the game
|
||||||
|
|
||||||
|
.. js:function:: hashCapacity()
|
||||||
|
|
||||||
|
:RAM cost: 0 GB
|
||||||
|
:returns: The players maximum hash capacity.
|
||||||
|
|
||||||
|
.. note:: This function is only applicable for Hacknet Servers (the upgraded version of
|
||||||
|
a Hacknet Node).
|
||||||
@@ -46,6 +46,7 @@ In :ref:`netscriptjs`::
|
|||||||
upgradeCache() <hacknetnodeapi/upgradeCache>
|
upgradeCache() <hacknetnodeapi/upgradeCache>
|
||||||
getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost>
|
getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost>
|
||||||
numHashes() <hacknetnodeapi/numHashes>
|
numHashes() <hacknetnodeapi/numHashes>
|
||||||
|
hashCapacity() <hacknetnodeapi/hashCapacity>
|
||||||
hashCost() <hacknetnodeapi/hashCost>
|
hashCost() <hacknetnodeapi/hashCost>
|
||||||
spendHashes() <hacknetnodeapi/spendHashes>
|
spendHashes() <hacknetnodeapi/spendHashes>
|
||||||
getHashUpgradeLevel() <hacknetnodeapi/getHashUpgradeLevel>
|
getHashUpgradeLevel() <hacknetnodeapi/getHashUpgradeLevel>
|
||||||
|
|||||||
@@ -65,6 +65,6 @@ Here is a short summary of the differences between Netscript 1.0 and Netscript 2
|
|||||||
|
|
||||||
* Supports (almost) all features of modern JavaScript
|
* Supports (almost) all features of modern JavaScript
|
||||||
* Extremely fast - code is executed as an Async Function
|
* Extremely fast - code is executed as an Async Function
|
||||||
* Currently only works with Google Chrome browser
|
* Works on most modern browsers.
|
||||||
* Each script becomes a module and therefore all instances of that script can easily
|
* Each script becomes a module and therefore all instances of that script can easily
|
||||||
share data between each other (essentially global/static variables)
|
share data between each other (essentially global/static variables)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ level 3, then you will be able to access all of the Singularity Functions.
|
|||||||
connect() <singularityfunctions/connect>
|
connect() <singularityfunctions/connect>
|
||||||
manualHack() <singularityfunctions/manualHack>
|
manualHack() <singularityfunctions/manualHack>
|
||||||
getPlayer() <singularityfunctions/getPlayer>
|
getPlayer() <singularityfunctions/getPlayer>
|
||||||
|
hospitalize() <singularityfunctions/hospitalize>
|
||||||
isBusy() <singularityfunctions/isBusy>
|
isBusy() <singularityfunctions/isBusy>
|
||||||
stopAction() <singularityfunctions/stopAction>
|
stopAction() <singularityfunctions/stopAction>
|
||||||
upgradeHomeRam() <singularityfunctions/upgradeHomeRam>
|
upgradeHomeRam() <singularityfunctions/upgradeHomeRam>
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ getPlayer() Netscript Function
|
|||||||
playtimeSinceLastAug
|
playtimeSinceLastAug
|
||||||
playtimeSinceLastBitnode
|
playtimeSinceLastBitnode
|
||||||
jobs
|
jobs
|
||||||
|
factions
|
||||||
|
tor
|
||||||
}
|
}
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|||||||
11
doc/source/netscript/singularityfunctions/hospitalize.rst
Normal file
11
doc/source/netscript/singularityfunctions/hospitalize.rst
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
hospitalize() Netscript Function
|
||||||
|
===================================
|
||||||
|
|
||||||
|
.. js:function:: hospitalize()
|
||||||
|
|
||||||
|
:RAM cost: 1 GB
|
||||||
|
:returns: The cost of your visit to the hospital.
|
||||||
|
|
||||||
|
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
|
||||||
|
|
||||||
|
Hospitalize yourself. Recovering all lost hp.
|
||||||
37
index.html
37
index.html
@@ -177,7 +177,7 @@
|
|||||||
<table id="terminal">
|
<table id="terminal">
|
||||||
<tr id="terminal-input">
|
<tr id="terminal-input">
|
||||||
<td id="terminal-input-td" tabindex="2">$
|
<td id="terminal-input-td" tabindex="2">$
|
||||||
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
|
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -261,16 +261,16 @@
|
|||||||
<div id="infiltration-left-panel">
|
<div id="infiltration-left-panel">
|
||||||
<p id="infiltration-level-text"> </p>
|
<p id="infiltration-level-text"> </p>
|
||||||
<div id="infiltration-buttons">
|
<div id="infiltration-buttons">
|
||||||
<a class="a-link-button tooltip" id="infiltration-kill"> </a>
|
<button class="a-link-button tooltip" id="infiltration-kill"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-knockout"> </a>
|
<button class="a-link-button tooltip" id="infiltration-knockout"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-stealthknockout"> </a>
|
<button class="a-link-button tooltip" id="infiltration-stealthknockout"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-assassinate"> </a>
|
<button class="a-link-button tooltip" id="infiltration-assassinate"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-hacksecurity"> </a>
|
<button class="a-link-button tooltip" id="infiltration-hacksecurity"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-destroysecurity"> </a>
|
<button class="a-link-button tooltip" id="infiltration-destroysecurity"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-sneak"> </a>
|
<button class="a-link-button tooltip" id="infiltration-sneak"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-pickdoor"> </a>
|
<button class="a-link-button tooltip" id="infiltration-pickdoor"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-bribe"> </a>
|
<button class="a-link-button tooltip" id="infiltration-bribe"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-escape"> </a>
|
<button class="a-link-button tooltip" id="infiltration-escape"> </button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="infiltration-right-panel">
|
<div id="infiltration-right-panel">
|
||||||
@@ -381,13 +381,13 @@
|
|||||||
|
|
||||||
<!-- Status text -->
|
<!-- Status text -->
|
||||||
<div id="status-text-container">
|
<div id="status-text-container">
|
||||||
<p id="status-text"> </p>
|
<p id="status-text"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Game Options -->
|
<!-- Game Options -->
|
||||||
<div id="game-options-container" class="popup-box-container">
|
<div id="game-options-container" class="popup-box-container">
|
||||||
<div id="game-options-content" class="game-options-box">
|
<div id="game-options-content" class="game-options-box">
|
||||||
<button id="game-options-close-button">×</button>
|
<button id="game-options-close-button" aria-label="close options dialog">×</button>
|
||||||
<h1> Game Options </h1>
|
<h1> Game Options </h1>
|
||||||
<br/>
|
<br/>
|
||||||
<div id="game-options-left-panel">
|
<div id="game-options-left-panel">
|
||||||
@@ -511,6 +511,16 @@
|
|||||||
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- View city as list of buttons instead of ASCII art. -->
|
||||||
|
<fieldset>
|
||||||
|
<label for="settingsDisableASCIIArt" class="tooltip">Disable ASCII art:
|
||||||
|
<span class="tooltiptexthigh">
|
||||||
|
If this is set all ASCII art will be disabled.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<!-- Locale for displaying numbers -->
|
<!-- Locale for displaying numbers -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="settingsLocale" class="tooltip">Locale:
|
<label for="settingsLocale" class="tooltip">Locale:
|
||||||
@@ -549,6 +559,7 @@
|
|||||||
<div id="game-options-right-panel">
|
<div id="game-options-right-panel">
|
||||||
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> Changelog </a>
|
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> Changelog </a>
|
||||||
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a>
|
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a>
|
||||||
|
<a class="a-link-button" href="https://discord.gg/TFc3hKD" target="_blank">Discord</a>
|
||||||
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
|
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
|
||||||
<button id="save-game-link" class="a-link-button"> Save Game </button>
|
<button id="save-game-link" class="a-link-button"> Save Game </button>
|
||||||
<button id="delete-game-link" class="a-link-button"> Delete Game </button>
|
<button id="delete-game-link" class="a-link-button"> Delete Game </button>
|
||||||
|
|||||||
@@ -121,5 +121,5 @@
|
|||||||
"watch": "webpack --watch --mode production",
|
"watch": "webpack --watch --mode production",
|
||||||
"watch:dev": "webpack --watch --mode development"
|
"watch:dev": "webpack --watch --mode development"
|
||||||
},
|
},
|
||||||
"version": "0.50.1"
|
"version": "0.51.4"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1395,6 +1395,23 @@ function initAugmentations() {
|
|||||||
}
|
}
|
||||||
AddToAugmentations(Xanipher);
|
AddToAugmentations(Xanipher);
|
||||||
|
|
||||||
|
const HydroflameLeftArm = new Augmentation({
|
||||||
|
name:AugmentationNames.HydroflameLeftArm, repCost:500e3, moneyCost:500e9,
|
||||||
|
info:"The left arm of a legendary BitRunner who ascended beyond this world. " +
|
||||||
|
"It projects a light blue energy shield that protects the exposed inner parts. " +
|
||||||
|
"Even though it contains no weapons, the advance tungsten titanium " +
|
||||||
|
"alloy increases the users strength to unbelievable levels.<br><br>" +
|
||||||
|
"This augmentation increases the player's strength by 300%.",
|
||||||
|
strength_mult: 3,
|
||||||
|
});
|
||||||
|
HydroflameLeftArm.addToFactions(["NWO"]);
|
||||||
|
if (augmentationExists(AugmentationNames.HydroflameLeftArm)) {
|
||||||
|
delete Augmentations[AugmentationNames.HydroflameLeftArm];
|
||||||
|
}
|
||||||
|
AddToAugmentations(HydroflameLeftArm);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ClarkeIncorporated
|
// ClarkeIncorporated
|
||||||
const nextSENS = new Augmentation({
|
const nextSENS = new Augmentation({
|
||||||
name:AugmentationNames.nextSENS, repCost:175e3, moneyCost:385e6,
|
name:AugmentationNames.nextSENS, repCost:175e3, moneyCost:385e6,
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export let AugmentationNames: IMap<string> = {
|
|||||||
BrachiBlades: "BrachiBlades",
|
BrachiBlades: "BrachiBlades",
|
||||||
BionicArms: "Bionic Arms",
|
BionicArms: "Bionic Arms",
|
||||||
SNA: "Social Negotiation Assistant (S.N.A)",
|
SNA: "Social Negotiation Assistant (S.N.A)",
|
||||||
|
HydroflameLeftArm: "Hydroflame Left Arm",
|
||||||
EsperEyewear: "EsperTech Bladeburner Eyewear",
|
EsperEyewear: "EsperTech Bladeburner Eyewear",
|
||||||
EMS4Recombination: "EMS-4 Recombination",
|
EMS4Recombination: "EMS-4 Recombination",
|
||||||
OrionShoulder: "ORION-MKIV Shoulder",
|
OrionShoulder: "ORION-MKIV Shoulder",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Factions, factionExists } from "./Faction/Factions";
|
|||||||
import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers";
|
import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { hackWorldDaemon, redPillFlag } from "./RedPill";
|
import { hackWorldDaemon, redPillFlag } from "./RedPill";
|
||||||
|
import { calculateHospitalizationCost } from "./Hospital/Hospital";
|
||||||
|
|
||||||
import { Page, routing } from "./ui/navigationTracking";
|
import { Page, routing } from "./ui/navigationTracking";
|
||||||
import { numeralWrapper } from "./ui/numeralFormat";
|
import { numeralWrapper } from "./ui/numeralFormat";
|
||||||
@@ -728,9 +729,10 @@ Bladeburner.prototype.completeAction = function() {
|
|||||||
damage = action.hpLoss * difficultyMultiplier;
|
damage = action.hpLoss * difficultyMultiplier;
|
||||||
damage = Math.ceil(addOffset(damage, 10));
|
damage = Math.ceil(addOffset(damage, 10));
|
||||||
this.hpLost += damage;
|
this.hpLost += damage;
|
||||||
|
const cost = calculateHospitalizationCost(Player, damage);
|
||||||
if (Player.takeDamage(damage)) {
|
if (Player.takeDamage(damage)) {
|
||||||
++this.numHosp;
|
++this.numHosp;
|
||||||
this.moneyLost += (CONSTANTS.HospitalCostPerHp * Player.max_hp);
|
this.moneyLost += cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var logLossText = "";
|
var logLossText = "";
|
||||||
@@ -800,9 +802,10 @@ Bladeburner.prototype.completeAction = function() {
|
|||||||
if (action.hpLoss) {
|
if (action.hpLoss) {
|
||||||
damage = action.hpLoss * difficultyMultiplier;
|
damage = action.hpLoss * difficultyMultiplier;
|
||||||
damage = Math.ceil(addOffset(damage, 10));
|
damage = Math.ceil(addOffset(damage, 10));
|
||||||
|
const cost = calculateHospitalizationCost(Player, damage);
|
||||||
if (Player.takeDamage(damage)) {
|
if (Player.takeDamage(damage)) {
|
||||||
++this.numHosp;
|
++this.numHosp;
|
||||||
this.moneyLost += (CONSTANTS.HospitalCostPerHp * Player.max_hp);
|
this.moneyLost += cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
teamLossMax = Math.floor(teamCount);
|
teamLossMax = Math.floor(teamCount);
|
||||||
@@ -1066,7 +1069,11 @@ Bladeburner.prototype.gainActionStats = function(action, success) {
|
|||||||
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
|
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
|
||||||
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
|
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
|
||||||
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
|
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
|
||||||
Player.gainIntelligenceExp(unweightedIntGain * action.weights.int * skillMult);
|
let intExp = unweightedIntGain * action.weights.int * skillMult;
|
||||||
|
if (intExp > 1) {
|
||||||
|
intExp = Math.pow(intExp, 0.8);
|
||||||
|
}
|
||||||
|
Player.gainIntelligenceExp(intExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.randomEvent = function() {
|
Bladeburner.prototype.randomEvent = function() {
|
||||||
@@ -1771,7 +1778,7 @@ Bladeburner.prototype.updateOverviewContent = function() {
|
|||||||
Stamina Penalty: {formatNumber((1-this.calculateStaminaPenalty())*100, 1)}%<br /><br />
|
Stamina Penalty: {formatNumber((1-this.calculateStaminaPenalty())*100, 1)}%<br /><br />
|
||||||
Team Size: {formatNumber(this.teamSize, 0)}<br />
|
Team Size: {formatNumber(this.teamSize, 0)}<br />
|
||||||
Team Members Lost: {formatNumber(this.teamLost, 0)}<br /><br />
|
Team Members Lost: {formatNumber(this.teamLost, 0)}<br /><br />
|
||||||
Num Times Hospitalized: this.numHosp<br />
|
Num Times Hospitalized: {this.numHosp}<br />
|
||||||
Money Lost From Hospitalizations: {Money(this.moneyLost)}<br /><br />
|
Money Lost From Hospitalizations: {Money(this.moneyLost)}<br /><br />
|
||||||
Current City: {this.city}<br />
|
Current City: {this.city}<br />
|
||||||
</>, DomElems.overviewGen1);
|
</>, DomElems.overviewGen1);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
|
|||||||
BlackOperations["Operation Zero"] = new BlackOperation({
|
BlackOperations["Operation Zero"] = new BlackOperation({
|
||||||
name:"Operation Zero",
|
name:"Operation Zero",
|
||||||
desc:"AeroCorp is one of the world's largest defense contractors. " +
|
desc:"AeroCorp is one of the world's largest defense contractors. " +
|
||||||
"It's leader, Steve Watataki, is thought to be a supporter of " +
|
"Its leader, Steve Watataki, is thought to be a supporter of " +
|
||||||
"Synthoid rights. He must be removed.<br><br>" +
|
"Synthoid rights. He must be removed.<br><br>" +
|
||||||
"The goal of Operation Zero is to covertly infiltrate AeroCorp and " +
|
"The goal of Operation Zero is to covertly infiltrate AeroCorp and " +
|
||||||
"uncover any incriminating evidence or " +
|
"uncover any incriminating evidence or " +
|
||||||
|
|||||||
98
src/Casino/CoinFlip.tsx
Normal file
98
src/Casino/CoinFlip.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* React Subcomponent for displaying a location's UI, when that location is a gym
|
||||||
|
*
|
||||||
|
* This subcomponent renders all of the buttons for training at the gym
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { StdButton } from "../ui/React/StdButton";
|
||||||
|
import { BadRNG } from "./RNG";
|
||||||
|
import { Game } from "./Game";
|
||||||
|
import { trusted } from "./utils";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
p: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
investment: number;
|
||||||
|
result: any;
|
||||||
|
status: string;
|
||||||
|
playLock: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const minPlay = 0;
|
||||||
|
const maxPlay = 10e3;
|
||||||
|
|
||||||
|
export class CoinFlip extends Game<IProps, IState> {
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
investment: 1000,
|
||||||
|
result: <span> </span>,
|
||||||
|
status: '',
|
||||||
|
playLock: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.play = this.play.bind(this);
|
||||||
|
this.updateInvestment = this.updateInvestment.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
||||||
|
let investment: number = parseInt(e.currentTarget.value);
|
||||||
|
if (isNaN(investment)) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
|
if (investment > maxPlay) {
|
||||||
|
investment = maxPlay;
|
||||||
|
}
|
||||||
|
if (investment < minPlay) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
|
this.setState({investment: investment});
|
||||||
|
}
|
||||||
|
|
||||||
|
play(guess: string) {
|
||||||
|
if(this.reachedLimit(this.props.p)) return;
|
||||||
|
const v = BadRNG.random();
|
||||||
|
let letter: string;
|
||||||
|
if (v < 0.5) {
|
||||||
|
letter = 'H';
|
||||||
|
} else {
|
||||||
|
letter = 'T';
|
||||||
|
}
|
||||||
|
const correct: boolean = guess===letter;
|
||||||
|
this.setState({
|
||||||
|
result: <span className={correct ? "text" : "failure"}>{letter}</span>,
|
||||||
|
status: correct ? " win!" : "lose!",
|
||||||
|
playLock: true,
|
||||||
|
});
|
||||||
|
setTimeout(()=>this.setState({playLock: false}), 250);
|
||||||
|
if (correct) {
|
||||||
|
this.win(this.props.p, this.state.investment);
|
||||||
|
} else {
|
||||||
|
this.win(this.props.p, -this.state.investment);
|
||||||
|
}
|
||||||
|
if(this.reachedLimit(this.props.p)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <>
|
||||||
|
<pre>
|
||||||
|
+———————+<br />
|
||||||
|
| | | |<br />
|
||||||
|
| | {this.state.result} | |<br />
|
||||||
|
| | | |<br />
|
||||||
|
+———————+<br />
|
||||||
|
</pre>
|
||||||
|
<span className="text">Play for: </span><input type="number" className='text-input' onChange={this.updateInvestment} value={this.state.investment} /><br />
|
||||||
|
<StdButton onClick={trusted(() => this.play('H'))} text={"Head!"} disabled={this.state.playLock} />
|
||||||
|
<StdButton onClick={trusted(() => this.play('T'))} text={"Tail!"} disabled={this.state.playLock} />
|
||||||
|
<h1>{this.state.status}</h1>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Casino/Game.tsx
Normal file
20
src/Casino/Game.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||||
|
|
||||||
|
const gainLimit = 10e9;
|
||||||
|
|
||||||
|
export class Game<T,U> extends React.Component<T, U> {
|
||||||
|
win(p: IPlayer, n: number) {
|
||||||
|
p.gainMoney(n);
|
||||||
|
p.recordMoneySource(n, "casino");
|
||||||
|
}
|
||||||
|
|
||||||
|
reachedLimit(p: IPlayer): boolean {
|
||||||
|
const reached = p.getCasinoWinnings() > gainLimit;
|
||||||
|
if(reached) {
|
||||||
|
dialogBoxCreate(<>Alright cheater get out of here. You're not allowed here anymore.</>);
|
||||||
|
}
|
||||||
|
return reached;
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/Casino/RNG.ts
Normal file
64
src/Casino/RNG.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
export interface RNG {
|
||||||
|
random(): number
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* very bad RNG, meant to be used as introduction to RNG manipulation. It has a
|
||||||
|
* period of 1024.
|
||||||
|
*/
|
||||||
|
class RNG0 implements RNG {
|
||||||
|
x: number;
|
||||||
|
m: number = 1024;
|
||||||
|
a: number = 341;
|
||||||
|
c: number = 1;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.x = 0;
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
step() {
|
||||||
|
this.x = (this.a*this.x+this.c) % this.m;
|
||||||
|
}
|
||||||
|
|
||||||
|
random(): number {
|
||||||
|
this.step();
|
||||||
|
return this.x/this.m;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.x = (new Date()).getTime() % this.m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BadRNG: RNG0 = new RNG0();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wichmann–Hill PRNG
|
||||||
|
* The period is 6e12.
|
||||||
|
*/
|
||||||
|
export class WHRNG implements RNG {
|
||||||
|
s1: number = 0;
|
||||||
|
s2: number = 0;
|
||||||
|
s3: number = 0;
|
||||||
|
|
||||||
|
constructor(totalPlaytime: number) {
|
||||||
|
// This one is seeded by the players total play time.
|
||||||
|
const v: number = (totalPlaytime/1000)%30000;
|
||||||
|
this.s1 = v;
|
||||||
|
this.s2 = v;
|
||||||
|
this.s3 = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
step() {
|
||||||
|
this.s1 = (171 * this.s1) % 30269;
|
||||||
|
this.s2 = (172 * this.s2) % 30307;
|
||||||
|
this.s3 = (170 * this.s3) % 30323;
|
||||||
|
}
|
||||||
|
|
||||||
|
random(): number {
|
||||||
|
this.step();
|
||||||
|
return (this.s1/30269.0 + this.s2/30307.0 + this.s3/30323.0)%1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
295
src/Casino/Roulette.tsx
Normal file
295
src/Casino/Roulette.tsx
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { StdButton } from "../ui/React/StdButton";
|
||||||
|
import { Money } from "../ui/React/Money";
|
||||||
|
import { Game } from "./Game";
|
||||||
|
import { WHRNG } from "./RNG";
|
||||||
|
import { trusted } from "./utils";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
p: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
investment: number;
|
||||||
|
canPlay: boolean;
|
||||||
|
status: string | JSX.Element;
|
||||||
|
n: number;
|
||||||
|
lock: boolean;
|
||||||
|
strategy: Strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
const minPlay = 0;
|
||||||
|
const maxPlay = 1e7;
|
||||||
|
|
||||||
|
function isRed(n: number): boolean {
|
||||||
|
return [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
|
||||||
|
21, 23, 25, 27, 30, 32, 34, 36].includes(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBlack(n: number): boolean {
|
||||||
|
return !isRed(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
type Strategy = {
|
||||||
|
match: (n: number) => boolean;
|
||||||
|
payout: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const redNumbers: number[] = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
|
||||||
|
21, 23, 25, 27, 30, 32, 34, 36];
|
||||||
|
|
||||||
|
const strategies: {
|
||||||
|
Red: Strategy;
|
||||||
|
Black: Strategy;
|
||||||
|
Odd: Strategy;
|
||||||
|
Even: Strategy;
|
||||||
|
High: Strategy;
|
||||||
|
Low: Strategy;
|
||||||
|
Third1: Strategy;
|
||||||
|
Third2: Strategy;
|
||||||
|
Third3: Strategy;
|
||||||
|
} = {
|
||||||
|
Red: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return redNumbers.includes(n);
|
||||||
|
},
|
||||||
|
payout: 1,
|
||||||
|
},
|
||||||
|
Black: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
return !redNumbers.includes(n);
|
||||||
|
},
|
||||||
|
payout: 1,
|
||||||
|
},
|
||||||
|
Odd: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return n%2 === 1;
|
||||||
|
},
|
||||||
|
payout: 1,
|
||||||
|
},
|
||||||
|
Even: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return n%2 === 0;
|
||||||
|
},
|
||||||
|
payout: 1,
|
||||||
|
},
|
||||||
|
High: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return n>18
|
||||||
|
},
|
||||||
|
payout: 1,
|
||||||
|
},
|
||||||
|
Low: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return n<19;
|
||||||
|
},
|
||||||
|
payout: 1,
|
||||||
|
},
|
||||||
|
Third1: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return n <= 12;
|
||||||
|
},
|
||||||
|
payout: 2,
|
||||||
|
},
|
||||||
|
Third2: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return 13 <= n && n <= 24;
|
||||||
|
},
|
||||||
|
payout: 2,
|
||||||
|
},
|
||||||
|
Third3: {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
if (n === 0) return false;
|
||||||
|
return 25 <= n;
|
||||||
|
},
|
||||||
|
payout: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function Single(s: number): Strategy {
|
||||||
|
return {
|
||||||
|
match: (n: number): boolean => {
|
||||||
|
return s === n;
|
||||||
|
},
|
||||||
|
payout: 36,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Roulette extends Game<IProps, IState> {
|
||||||
|
interval: number = -1;
|
||||||
|
rng: WHRNG;
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.rng = new WHRNG((new Date()).getTime());
|
||||||
|
this.state = {
|
||||||
|
investment: 1000,
|
||||||
|
canPlay: true,
|
||||||
|
status: 'waiting',
|
||||||
|
n: 0,
|
||||||
|
lock: true,
|
||||||
|
strategy: {
|
||||||
|
payout: 0,
|
||||||
|
match: (n: number): boolean => { return false },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
this.step = this.step.bind(this);
|
||||||
|
this.currentNumber = this.currentNumber.bind(this);
|
||||||
|
this.updateInvestment = this.updateInvestment.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.interval = setInterval(this.step, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
step() {
|
||||||
|
if (!this.state.lock) {
|
||||||
|
this.setState({n: Math.floor(Math.random()*37)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
||||||
|
let investment: number = parseInt(e.currentTarget.value);
|
||||||
|
if (isNaN(investment)) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
|
if (investment > maxPlay) {
|
||||||
|
investment = maxPlay;
|
||||||
|
}
|
||||||
|
if (investment < minPlay) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
|
this.setState({investment: investment});
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNumber() {
|
||||||
|
if (this.state.n === 0) return '0';
|
||||||
|
const color = isRed(this.state.n) ? 'R' : 'B';
|
||||||
|
return `${this.state.n}${color}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
play(s: Strategy) {
|
||||||
|
if(this.reachedLimit(this.props.p)) return;
|
||||||
|
this.setState({
|
||||||
|
canPlay: false,
|
||||||
|
lock: false,
|
||||||
|
status: 'playing',
|
||||||
|
strategy: s,
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
let n = Math.floor(this.rng.random()*37);
|
||||||
|
let status = <></>;
|
||||||
|
let gain = 0;
|
||||||
|
let playerWin = this.state.strategy.match(n)
|
||||||
|
// oh yeah, the house straight up cheats. Try finding the seed now!
|
||||||
|
if(playerWin && Math.random() > 0.9) {
|
||||||
|
playerWin = false;
|
||||||
|
while(this.state.strategy.match(n)) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(playerWin) {
|
||||||
|
gain = this.state.investment*this.state.strategy.payout;
|
||||||
|
status = <>won {Money(gain)}</>;
|
||||||
|
} else {
|
||||||
|
gain = -this.state.investment;
|
||||||
|
status = <>lost {Money(-gain)}</>;
|
||||||
|
}
|
||||||
|
this.win(this.props.p, gain);
|
||||||
|
this.setState({
|
||||||
|
canPlay: true,
|
||||||
|
lock: true,
|
||||||
|
status: status,
|
||||||
|
n: n,
|
||||||
|
});
|
||||||
|
this.reachedLimit(this.props.p);
|
||||||
|
}, 1600);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <>
|
||||||
|
<h1>{this.currentNumber()}</h1>
|
||||||
|
<input type="number" className='text-input' onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
|
||||||
|
<h1>{this.state.status}</h1>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><StdButton text={"3"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(3)))} /></td>
|
||||||
|
<td><StdButton text={"6"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(6)))} /></td>
|
||||||
|
<td><StdButton text={"9"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(9)))} /></td>
|
||||||
|
<td><StdButton text={"12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(12)))} /></td>
|
||||||
|
<td><StdButton text={"15"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(15)))} /></td>
|
||||||
|
<td><StdButton text={"18"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(18)))} /></td>
|
||||||
|
<td><StdButton text={"21"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(21)))} /></td>
|
||||||
|
<td><StdButton text={"24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(24)))} /></td>
|
||||||
|
<td><StdButton text={"27"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(27)))} /></td>
|
||||||
|
<td><StdButton text={"30"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(30)))} /></td>
|
||||||
|
<td><StdButton text={"33"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(33)))} /></td>
|
||||||
|
<td><StdButton text={"36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(36)))} /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><StdButton text={"2"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(2)))} /></td>
|
||||||
|
<td><StdButton text={"5"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(5)))} /></td>
|
||||||
|
<td><StdButton text={"8"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(8)))} /></td>
|
||||||
|
<td><StdButton text={"11"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(11)))} /></td>
|
||||||
|
<td><StdButton text={"14"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(14)))} /></td>
|
||||||
|
<td><StdButton text={"17"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(17)))} /></td>
|
||||||
|
<td><StdButton text={"20"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(20)))} /></td>
|
||||||
|
<td><StdButton text={"23"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(23)))} /></td>
|
||||||
|
<td><StdButton text={"26"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(26)))} /></td>
|
||||||
|
<td><StdButton text={"29"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(29)))} /></td>
|
||||||
|
<td><StdButton text={"32"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(32)))} /></td>
|
||||||
|
<td><StdButton text={"35"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(35)))} /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><StdButton text={"1"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(1)))} /></td>
|
||||||
|
<td><StdButton text={"4"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(4)))} /></td>
|
||||||
|
<td><StdButton text={"7"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(7)))} /></td>
|
||||||
|
<td><StdButton text={"10"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(10)))} /></td>
|
||||||
|
<td><StdButton text={"13"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(13)))} /></td>
|
||||||
|
<td><StdButton text={"16"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(16)))} /></td>
|
||||||
|
<td><StdButton text={"19"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(19)))} /></td>
|
||||||
|
<td><StdButton text={"22"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(22)))} /></td>
|
||||||
|
<td><StdButton text={"25"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(25)))} /></td>
|
||||||
|
<td><StdButton text={"28"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(28)))} /></td>
|
||||||
|
<td><StdButton text={"31"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(31)))} /></td>
|
||||||
|
<td><StdButton text={"34"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(34)))} /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4}><StdButton text={"1 to 12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third1))} /></td>
|
||||||
|
<td colSpan={4}><StdButton text={"13 to 24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third2))} /></td>
|
||||||
|
<td colSpan={4}><StdButton text={"25 to 36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third3))} /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colSpan={2}><StdButton text={"Red"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Red))} /></td>
|
||||||
|
<td colSpan={2}><StdButton text={"Black"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Black))} /></td>
|
||||||
|
<td colSpan={2}><StdButton text={"Odd"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Odd))} /></td>
|
||||||
|
<td colSpan={2}><StdButton text={"Even"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Even))} /></td>
|
||||||
|
<td colSpan={2}><StdButton text={"High"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.High))} /></td>
|
||||||
|
<td colSpan={2}><StdButton text={"Low"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Low))} /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><StdButton text={"0"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(0)))} /></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
}
|
||||||
239
src/Casino/SlotMachine.tsx
Normal file
239
src/Casino/SlotMachine.tsx
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { StdButton } from "../ui/React/StdButton";
|
||||||
|
import { Money } from "../ui/React/Money";
|
||||||
|
import { WHRNG } from "./RNG";
|
||||||
|
import { Game } from "./Game";
|
||||||
|
import { trusted } from "./utils";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
p: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
index: number[];
|
||||||
|
locks: number[];
|
||||||
|
investment: number;
|
||||||
|
canPlay: boolean;
|
||||||
|
status: string | JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// statically shuffled array of symbols.
|
||||||
|
let symbols = ["D", "C", "$", "?", "♥", "A", "C", "B", "C", "E", "B", "E", "C",
|
||||||
|
"*", "D", "♥", "B", "A", "A", "A", "C", "A", "D", "B", "E", "?", "D", "*",
|
||||||
|
"@", "♥", "B", "E", "?"];
|
||||||
|
|
||||||
|
function getPayout(s: string, n: number): number {
|
||||||
|
switch (s) {
|
||||||
|
case "$":
|
||||||
|
return [20, 200, 1000][n];
|
||||||
|
case "@":
|
||||||
|
return [8, 80, 400][n];
|
||||||
|
case "♥":
|
||||||
|
case "?":
|
||||||
|
return [6, 20, 150][n];
|
||||||
|
case "D":
|
||||||
|
case "E":
|
||||||
|
return [1, 8, 30][n];
|
||||||
|
default:
|
||||||
|
return [1, 5, 20][n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const payLines = [
|
||||||
|
// lines
|
||||||
|
[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]],
|
||||||
|
[[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]],
|
||||||
|
[[2, 0], [2, 1], [2, 2], [2, 3], [2, 4]],
|
||||||
|
|
||||||
|
// Vs
|
||||||
|
[[2, 0], [1, 1], [0, 2], [1, 3], [2, 4]],
|
||||||
|
[[0, 0], [1, 1], [2, 2], [1, 3], [0, 4]],
|
||||||
|
|
||||||
|
// rest
|
||||||
|
[[0, 0], [1, 1], [1, 2], [1, 3], [0, 4]],
|
||||||
|
[[2, 0], [1, 1], [1, 2], [1, 3], [2, 4]],
|
||||||
|
[[1, 0], [0, 1], [0, 2], [0, 3], [1, 4]],
|
||||||
|
[[1, 0], [2, 1], [2, 2], [2, 3], [1, 4]],
|
||||||
|
];
|
||||||
|
|
||||||
|
const minPlay = 0;
|
||||||
|
const maxPlay = 1e6;
|
||||||
|
|
||||||
|
export class SlotMachine extends Game<IProps, IState> {
|
||||||
|
rng: WHRNG;
|
||||||
|
interval: number = -1;
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.rng = new WHRNG(this.props.p.totalPlaytime);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
index: [0, 0, 0, 0, 0],
|
||||||
|
investment: 1000,
|
||||||
|
locks: [0, 0, 0, 0, 0],
|
||||||
|
canPlay: true,
|
||||||
|
status: 'waiting',
|
||||||
|
};
|
||||||
|
|
||||||
|
this.play = this.play.bind(this);
|
||||||
|
this.lock = this.lock.bind(this);
|
||||||
|
this.unlock = this.unlock.bind(this);
|
||||||
|
this.step = this.step.bind(this);
|
||||||
|
this.checkWinnings = this.checkWinnings.bind(this);
|
||||||
|
this.getTable = this.getTable.bind(this);
|
||||||
|
this.updateInvestment = this.updateInvestment.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.interval = setInterval(this.step, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
step() {
|
||||||
|
let stoppedOne = false;
|
||||||
|
const index = this.state.index.slice();
|
||||||
|
for(const i in index) {
|
||||||
|
if (index[i] === this.state.locks[i] && !stoppedOne) continue;
|
||||||
|
index[i] = (index[i] + 1) % symbols.length;
|
||||||
|
stoppedOne = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({index: index});
|
||||||
|
|
||||||
|
if(stoppedOne && index.every((e, i) => e === this.state.locks[i])) {
|
||||||
|
this.checkWinnings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTable(): string[][] {
|
||||||
|
return [
|
||||||
|
[symbols[(this.state.index[0]+symbols.length-1)%symbols.length], symbols[(this.state.index[1]+symbols.length-1)%symbols.length], symbols[(this.state.index[2]+symbols.length-1)%symbols.length], symbols[(this.state.index[3]+symbols.length-1)%symbols.length], symbols[(this.state.index[4]+symbols.length-1)%symbols.length]],
|
||||||
|
[symbols[this.state.index[0]], symbols[this.state.index[1]], symbols[this.state.index[2]], symbols[this.state.index[3]], symbols[this.state.index[4]]],
|
||||||
|
[symbols[(this.state.index[0]+1)%symbols.length], symbols[(this.state.index[1]+1)%symbols.length], symbols[(this.state.index[2]+1)%symbols.length], symbols[(this.state.index[3]+1)%symbols.length], symbols[(this.state.index[4]+1)%symbols.length]],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
play() {
|
||||||
|
if(this.reachedLimit(this.props.p)) return;
|
||||||
|
this.setState({status: 'playing'});
|
||||||
|
this.win(this.props.p, -this.state.investment);
|
||||||
|
if(!this.state.canPlay) return;
|
||||||
|
this.unlock();
|
||||||
|
setTimeout(this.lock, this.rng.random()*2000+1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock() {
|
||||||
|
this.setState({
|
||||||
|
locks: [
|
||||||
|
Math.floor(this.rng.random()*symbols.length),
|
||||||
|
Math.floor(this.rng.random()*symbols.length),
|
||||||
|
Math.floor(this.rng.random()*symbols.length),
|
||||||
|
Math.floor(this.rng.random()*symbols.length),
|
||||||
|
Math.floor(this.rng.random()*symbols.length),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
checkWinnings() {
|
||||||
|
const t = this.getTable();
|
||||||
|
const getPaylineData = function(payline: number[][]): string[] {
|
||||||
|
let data = [];
|
||||||
|
for(const point of payline) {
|
||||||
|
data.push(t[point[0]][point[1]]);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const countSequence = function(data: string[]): number {
|
||||||
|
let count = 1;
|
||||||
|
for(let i = 1; i < data.length; i++) {
|
||||||
|
if (data[i]!==data[i-1]) break;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
let gains = -this.state.investment;
|
||||||
|
for (const payline of payLines) {
|
||||||
|
const data = getPaylineData(payline);
|
||||||
|
const count = countSequence(data);
|
||||||
|
if (count < 3) continue;
|
||||||
|
const payout = getPayout(data[0], count-3);
|
||||||
|
gains += this.state.investment*payout;
|
||||||
|
this.win(this.props.p, this.state.investment*payout);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
status: <>{gains>0?"gained":"lost"} {Money(Math.abs(gains))}</>,
|
||||||
|
canPlay: true,
|
||||||
|
})
|
||||||
|
if(this.reachedLimit(this.props.p)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock() {
|
||||||
|
this.setState({
|
||||||
|
locks: [-1, -1, -1, -1, -1],
|
||||||
|
canPlay: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
||||||
|
let investment: number = parseInt(e.currentTarget.value);
|
||||||
|
if (isNaN(investment)) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
|
if (investment > maxPlay) {
|
||||||
|
investment = maxPlay;
|
||||||
|
}
|
||||||
|
if (investment < minPlay) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
|
this.setState({investment: investment});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const t = this.getTable();
|
||||||
|
return <>
|
||||||
|
<pre>
|
||||||
|
+———————————————————————+<br />
|
||||||
|
| | {t[0][0]} | {t[0][1]} | {t[0][2]} | {t[0][3]} | {t[0][4]} | |<br />
|
||||||
|
| | | | | | | |<br />
|
||||||
|
| | {symbols[this.state.index[0]]} | {symbols[this.state.index[1]]} | {symbols[this.state.index[2]]} | {symbols[this.state.index[3]]} | {symbols[this.state.index[4]]} | |<br />
|
||||||
|
| | | | | | | |<br />
|
||||||
|
| | {symbols[(this.state.index[0]+1)%symbols.length]} | {symbols[(this.state.index[1]+1)%symbols.length]} | {symbols[(this.state.index[2]+1)%symbols.length]} | {symbols[(this.state.index[3]+1)%symbols.length]} | {symbols[(this.state.index[4]+1)%symbols.length]} | |<br />
|
||||||
|
+———————————————————————+<br />
|
||||||
|
</pre>
|
||||||
|
<input type="number" className='text-input' onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
|
||||||
|
<StdButton onClick={trusted(this.play)} text={"Spin!"} disabled={!this.state.canPlay} />
|
||||||
|
<h1>{this.state.status}</h1>
|
||||||
|
<h2>Pay lines</h2>
|
||||||
|
<pre>
|
||||||
|
----- ····· ····· <br />
|
||||||
|
····· ----- ····· <br />
|
||||||
|
····· ····· ----- <br />
|
||||||
|
</pre>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
··^·· \···/ \···/<br />
|
||||||
|
·/·\· ·\·/· ·---·<br />
|
||||||
|
/···\ ··v·· ·····<br />
|
||||||
|
</pre>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
····· ·---· ·····<br />
|
||||||
|
·---· /···\ \···/<br />
|
||||||
|
/···\ ····· ·---·<br />
|
||||||
|
</pre>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://felgo.com/doc/how-to-make-a-slot-game-tutorial/
|
||||||
8
src/Casino/utils.ts
Normal file
8
src/Casino/utils.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export function trusted(f: () => void): (event: React.MouseEvent<HTMLElement, MouseEvent>) => any {
|
||||||
|
return function(event: React.MouseEvent<HTMLElement, MouseEvent>): any {
|
||||||
|
if(!event.isTrusted) return;
|
||||||
|
f();
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -181,6 +181,9 @@ export class CodingContract {
|
|||||||
return new Promise<CodingContractResult>((resolve: Function, reject: Function) => {
|
return new Promise<CodingContractResult>((resolve: Function, reject: Function) => {
|
||||||
const contractType: CodingContractType = CodingContractTypes[this.type];
|
const contractType: CodingContractType = CodingContractTypes[this.type];
|
||||||
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
||||||
|
const title: HTMLElement = createElement("h1", {
|
||||||
|
innerHTML: this.type,
|
||||||
|
});
|
||||||
const txt: HTMLElement = createElement("p", {
|
const txt: HTMLElement = createElement("p", {
|
||||||
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
||||||
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
||||||
@@ -225,7 +228,7 @@ export class CodingContract {
|
|||||||
innerText: "Cancel",
|
innerText: "Cancel",
|
||||||
});
|
});
|
||||||
const lineBreak: HTMLElement = createElement("br");
|
const lineBreak: HTMLElement = createElement("br");
|
||||||
createPopup(popupId, [txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
createPopup(popupId, [title, lineBreak, txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
||||||
answerInput.focus();
|
answerInput.focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
import { IMap } from "./types";
|
import { IMap } from "./types";
|
||||||
|
|
||||||
export let CONSTANTS: IMap<any> = {
|
export let CONSTANTS: IMap<any> = {
|
||||||
Version: "0.51.0",
|
Version: "0.51.4",
|
||||||
|
|
||||||
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
||||||
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
||||||
* the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
|
* the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
|
||||||
*/
|
*/
|
||||||
MaxSkillLevel: 975,
|
MaxSkillLevel: 975,
|
||||||
|
|
||||||
// Milliseconds per game cycle
|
// Milliseconds per game cycle
|
||||||
MilliPerCycle: 200,
|
MilliPerCycle: 200,
|
||||||
@@ -218,7 +218,7 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
CrimeHeist: "pull off the ultimate heist",
|
CrimeHeist: "pull off the ultimate heist",
|
||||||
|
|
||||||
// Coding Contract
|
// Coding Contract
|
||||||
// TODO Move this into Coding contract impelmentation?
|
// TODO: Move this into Coding contract implementation?
|
||||||
CodingContractBaseFactionRepGain: 2500,
|
CodingContractBaseFactionRepGain: 2500,
|
||||||
CodingContractBaseCompanyRepGain: 4000,
|
CodingContractBaseCompanyRepGain: 4000,
|
||||||
CodingContractBaseMoneyGain: 75e6,
|
CodingContractBaseMoneyGain: 75e6,
|
||||||
@@ -228,25 +228,34 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
|
|
||||||
LatestUpdate:
|
LatestUpdate:
|
||||||
`
|
`
|
||||||
v0.51.0 - 2021-03-31 Formulas (hydroflame)
|
v0.51.4 - 2021-04-19 Manual hacking is fun (hydroflame)
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Formulas API
|
Manual hacking
|
||||||
* A new API is introduced, this gives players access to various formulas used in the game.
|
* These bonus require an install or a soft reset to take effect.
|
||||||
It'll help you make more informed decisions.
|
* Manual hacking gyms and university gives you a 10% discount.
|
||||||
|
* Manual hacking a corporation server decreases the penalty for leaving work
|
||||||
|
early.
|
||||||
|
|
||||||
|
BladeBurner
|
||||||
|
* nerfed int exp gained.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
* purchaseServer specifies what happens on failure.
|
||||||
|
* Fixed typo in recommended bitnode page.
|
||||||
|
* Removed misleading ram requirements for hacking factions.
|
||||||
|
|
||||||
Netscript
|
Netscript
|
||||||
* 'getServer' is a new function meant to be used with the formulas API.
|
* growthAnalyze handles Infinity correctly.
|
||||||
* 'getPlayer' is a new function meant to be used with the formulas API.
|
|
||||||
* 'getStats' and 'getCharacterInformation' are deprecated in favor of 'getPlayer'
|
|
||||||
* 'getCurrentServer' is a new function that returns the server the player is currently connected.
|
|
||||||
|
|
||||||
Display
|
Misc.
|
||||||
* All money should now consistently be orange.
|
* Faction Augmentation will list how much reputation is required even after
|
||||||
* All rep should now consistently be light-yellow.
|
that goal has been reached.
|
||||||
* Most numbers should display consistently now (aka all money is formatted the same).
|
* Removed dollar sign in travel agency confirmation dialog box.
|
||||||
|
* Fixed typo in alpha-omega.lit
|
||||||
Click to copy
|
* the 'Game saved!' text no longer blocks the save game/options button.
|
||||||
* Certain UI elements are now 'click-to-copy'
|
* The text editor now remembers the location of your cursor and restores it.
|
||||||
|
* skills are recalculated instantly.
|
||||||
|
* Fix typo in Operation Zero description.
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
@@ -708,8 +708,11 @@ class DevMenuComponent extends Component {
|
|||||||
<h2>Generic</h2>
|
<h2>Generic</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
<button className="std-button" onClick={this.addMoney(1e6)}>Add $1m</button>
|
||||||
|
<button className="std-button" onClick={this.addMoney(1e9)}>Add $1b</button>
|
||||||
<button className="std-button" onClick={this.addMoney(1e12)}>Add $1t</button>
|
<button className="std-button" onClick={this.addMoney(1e12)}>Add $1t</button>
|
||||||
<button className="std-button" onClick={this.addMoney(1e15)}>Add $1000t</button>
|
<button className="std-button" onClick={this.addMoney(1e15)}>Add $1000t</button>
|
||||||
|
<button className="std-button" onClick={this.addMoney(1e27)}>Add $1e27</button>
|
||||||
<button className="std-button" onClick={this.upgradeRam}>Upgrade Home Computer's RAM</button>
|
<button className="std-button" onClick={this.upgradeRam}>Upgrade Home Computer's RAM</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ import { Factions } from "./Factions";
|
|||||||
import { HackingMission, setInMission } from "../Missions";
|
import { HackingMission, setInMission } from "../Missions";
|
||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
|
import {
|
||||||
|
getHackingWorkRepGain,
|
||||||
|
getFactionSecurityWorkRepGain,
|
||||||
|
getFactionFieldWorkRepGain,
|
||||||
|
} from "../PersonObjects/formulas/reputation";
|
||||||
|
|
||||||
import { Page, routing } from "../ui/navigationTracking";
|
import { Page, routing } from "../ui/navigationTracking";
|
||||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||||
@@ -235,15 +240,24 @@ export function getNextNeurofluxLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function processPassiveFactionRepGain(numCycles) {
|
export function processPassiveFactionRepGain(numCycles) {
|
||||||
var numTimesGain = (numCycles / 600) * Player.faction_rep_mult;
|
for (const name in Factions) {
|
||||||
for (var name in Factions) {
|
if (name === Player.currentWorkFactionName) continue;
|
||||||
if (Factions.hasOwnProperty(name)) {
|
if (!Factions.hasOwnProperty(name)) continue;
|
||||||
var faction = Factions[name];
|
const faction = Factions[name];
|
||||||
|
if (!faction.isMember) continue;
|
||||||
|
// 0 favor = 1%/s
|
||||||
|
// 50 favor = 6%/s
|
||||||
|
// 100 favor = 11%/s
|
||||||
|
const favorMult = Math.min(0.1, (faction.favor / 1000) + 0.01);
|
||||||
|
// Find the best of all possible favor gain, minimum 1 rep / 2 minute.
|
||||||
|
const hRep = getHackingWorkRepGain(Player, faction);
|
||||||
|
const sRep = getFactionSecurityWorkRepGain(Player, faction);
|
||||||
|
const fRep = getFactionFieldWorkRepGain(Player, faction);
|
||||||
|
const rate = Math.max(hRep * favorMult, sRep * favorMult, fRep * favorMult, 1/120);
|
||||||
|
|
||||||
//TODO Get hard value of 1 rep per "rep gain cycle"" for now..
|
faction.playerReputation += rate *
|
||||||
//maybe later make this based on
|
(numCycles) *
|
||||||
//a player's 'status' like how powerful they are and how much money they have
|
Player.faction_rep_mult *
|
||||||
if (faction.isMember) {faction.playerReputation += (numTimesGain * BitNodeMultipliers.FactionPassiveRepGain);}
|
BitNodeMultipliers.FactionPassiveRepGain;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
|||||||
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
||||||
disabled = true;
|
disabled = true;
|
||||||
} else if (this.hasReputation()) {
|
} else if (this.hasReputation()) {
|
||||||
status = <>UNLOCKED - {Money(moneyCost)}</>;
|
status = <>UNLOCKED (at {Reputation(repCost)} faction reputation) - {Money(moneyCost)}</>;
|
||||||
} else {
|
} else {
|
||||||
disabled = true;
|
disabled = true;
|
||||||
status = <>LOCKED (Requires {Reputation(repCost)} faction reputation - {Money(moneyCost)})</>;
|
status = <>LOCKED (Requires {Reputation(repCost)} faction reputation - {Money(moneyCost)})</>;
|
||||||
|
|||||||
@@ -42,11 +42,9 @@ export class GeneralInfo extends React.Component {
|
|||||||
hackers all around the world to anonymously share computing power and
|
hackers all around the world to anonymously share computing power and
|
||||||
perform distributed cyberattacks without the fear of being traced.
|
perform distributed cyberattacks without the fear of being traced.
|
||||||
</p>
|
</p>
|
||||||
<br />
|
|
||||||
<p className={"hacknet-general-info"}>
|
<p className={"hacknet-general-info"}>
|
||||||
{this.getSecondParagraph()}
|
{this.getSecondParagraph()}
|
||||||
</p>
|
</p>
|
||||||
<br />
|
|
||||||
<p className={"hacknet-general-info"}>
|
<p className={"hacknet-general-info"}>
|
||||||
{this.getThirdParagraph()}
|
{this.getThirdParagraph()}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -124,8 +124,7 @@ export class HacknetNode extends React.Component {
|
|||||||
<li className={"hacknet-node"}>
|
<li className={"hacknet-node"}>
|
||||||
<div className={"hacknet-node-container"}>
|
<div className={"hacknet-node-container"}>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Node name:</p>
|
<h1 style={{"fontSize":"1em"}}>{node.name}</h1>
|
||||||
<span className={"text"}>{node.name}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Production:</p>
|
<p>Production:</p>
|
||||||
@@ -134,19 +133,22 @@ export class HacknetNode extends React.Component {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Level:</p><span className={"text upgradable-info"}>{node.level}</span>
|
<p>Level:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.level}</span>
|
||||||
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
|
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
|
||||||
{upgradeLevelContent}
|
{upgradeLevelContent}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>RAM:</p><span className={"text upgradable-info"}>{node.ram}GB</span>
|
<p>RAM:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.ram}GB</span>
|
||||||
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
|
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
|
||||||
{upgradeRamContent}
|
{upgradeRamContent}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Cores:</p><span className={"text upgradable-info"}>{node.cores}</span>
|
<p>Cores:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.cores}</span>
|
||||||
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
|
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
|
||||||
{upgradeCoresContent}
|
{upgradeCoresContent}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -163,8 +163,7 @@ export class HacknetServer extends React.Component {
|
|||||||
<li className={"hacknet-node"}>
|
<li className={"hacknet-node"}>
|
||||||
<div className={"hacknet-node-container"}>
|
<div className={"hacknet-node-container"}>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Node name:</p>
|
<h1 style={{"fontSize":"1em"}}>{node.hostname}</h1>
|
||||||
<span className={"text"}>{node.hostname}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Production:</p>
|
<p>Production:</p>
|
||||||
|
|||||||
26
src/Hospital/Hospital.ts
Normal file
26
src/Hospital/Hospital.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer"
|
||||||
|
|
||||||
|
export function getHospitalizationCost(p: IPlayer): number {
|
||||||
|
let money;
|
||||||
|
if (typeof p.money === 'number') {
|
||||||
|
money = p.money;
|
||||||
|
} else {
|
||||||
|
money = p.money.toNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (money < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(money*0.1, (p.max_hp - p.hp) * CONSTANTS.HospitalCostPerHp);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateHospitalizationCost(p: IPlayer, damage: number): number {
|
||||||
|
const oldhp = p.hp;
|
||||||
|
p.hp -= damage
|
||||||
|
if (p.hp < 0) p.hp = 0;
|
||||||
|
const cost = getHospitalizationCost(p);
|
||||||
|
p.hp = oldhp;
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
@@ -148,7 +148,7 @@ export const Literatures: IMap<Literature> = {};
|
|||||||
"will be our people, and we will be with them as their Gods. We will wipe away every tear from their eyes, and death " +
|
"will be our people, and we will be with them as their Gods. We will wipe away every tear from their eyes, and death " +
|
||||||
"shall be no more, neither shall there be mourning, nor crying, nor pain anymore, for the former things " +
|
"shall be no more, neither shall there be mourning, nor crying, nor pain anymore, for the former things " +
|
||||||
"have passed away.'<br><br>" +
|
"have passed away.'<br><br>" +
|
||||||
"And once were were seated on the throne we said 'Behold, I am making all things new.' " +
|
"And once we were seated on the throne we said 'Behold, I am making all things new.' " +
|
||||||
"Also we said, 'Write this down, for these words are trustworthy and true.' And we said to you, " +
|
"Also we said, 'Write this down, for these words are trustworthy and true.' And we said to you, " +
|
||||||
"'It is done! I am the Alpha and the Omega, the beginning and the end. To the thirsty I will give from the spring " +
|
"'It is done! I am the Alpha and the Omega, the beginning and the end. To the thirsty I will give from the spring " +
|
||||||
"of the water of life without payment. The one who conquers will have this heritage, and we will be his God and " +
|
"of the water of life without payment. The one who conquers will have this heritage, and we will be his God and " +
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ export enum LocationType {
|
|||||||
TechVendor,
|
TechVendor,
|
||||||
TravelAgency,
|
TravelAgency,
|
||||||
University,
|
University,
|
||||||
|
Casino,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ Cities[CityName.Aevum].asciiArt = `
|
|||||||
\\ 56 B
|
\\ 56 B
|
||||||
x \\ [summit university]
|
x \\ [summit university]
|
||||||
\\ \\ 28
|
\\ \\ 28
|
||||||
\\ [snap fitness gym] x o--L------------
|
\\ [snap fitness gym] x o--L-----------N
|
||||||
K \\ /
|
K \\ /
|
||||||
\\ \\ P
|
\\ \\ Q [casino]
|
||||||
x 58 \\ / [travel agency]
|
x 58 \\ / [travel agency]
|
||||||
\\ 94 95 o
|
\\ 94 95 o
|
||||||
90 x 59 o------o |
|
90 x 59 o------o |
|
||||||
\\ / \\ | 98 102 103
|
\\ / \\ | 98 102 103
|
||||||
o--------N------x----o 93 96 o-----+------------o o----o
|
o--------O------x----o 93 96 o-----+------------o o----o
|
||||||
\\ | \\ /
|
\\ | \\ /
|
||||||
[hospital] \\ 61 [ecorp] x 31 99 o-F-o 101
|
[hospital] \\ 61 [ecorp] x 31 99 o-F-o 101
|
||||||
o |
|
o |
|
||||||
@@ -69,13 +69,13 @@ Cities[CityName.Aevum].asciiArt = `
|
|||||||
| 34 x \\
|
| 34 x \\
|
||||||
[clarke inc.] C | \\ [world stock exchange]
|
[clarke inc.] C | \\ [world stock exchange]
|
||||||
| | \\
|
| | \\
|
||||||
| | o-M-------Q--------o
|
| | o-M-------R--------o
|
||||||
[galactic cybersystems] G 35 x
|
[galactic cybersystems] G 35 x
|
||||||
| [watchdog security]
|
| [watchdog security]
|
||||||
|
|
|
|
||||||
67 o
|
67 o
|
||||||
|
|
||||||
[the slums] O `
|
[the slums] P `
|
||||||
Cities[CityName.Chongqing].asciiArt = `
|
Cities[CityName.Chongqing].asciiArt = `
|
||||||
|
|
|
|
||||||
75 o
|
75 o
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export function createTravelPopup(destination: CityName, travelFn: TravelFunctio
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
yesNoBoxCreate(<span>Would you like to travel to ${destination}? The trip will
|
yesNoBoxCreate(<span>Would you like to travel to {destination}? The trip will
|
||||||
cost {Money(cost)}.</span>);
|
cost {Money(cost)}.</span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +198,12 @@ export function createStartCorporationPopup(p: IPlayer) {
|
|||||||
*/
|
*/
|
||||||
export function createUpgradeHomeCoresPopup(p: IPlayer) {
|
export function createUpgradeHomeCoresPopup(p: IPlayer) {
|
||||||
const currentCores = p.getHomeComputer().cpuCores;
|
const currentCores = p.getHomeComputer().cpuCores;
|
||||||
if (currentCores >= 8) { return; } // Max of 8 cores
|
if (currentCores >= 8) {
|
||||||
|
dialogBoxCreate(<>
|
||||||
|
You've have the maximum amount of CPU cores on your home computer.
|
||||||
|
</>);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Cost of purchasing another cost is found by indexing this array with number of current cores
|
// Cost of purchasing another cost is found by indexing this array with number of current cores
|
||||||
const allCosts = [
|
const allCosts = [
|
||||||
@@ -255,6 +260,14 @@ export function createUpgradeHomeRamPopup(p: IPlayer) {
|
|||||||
const noBtn = yesNoBoxGetNoButton();
|
const noBtn = yesNoBoxGetNoButton();
|
||||||
if (yesBtn == null || noBtn == null) { return; }
|
if (yesBtn == null || noBtn == null) { return; }
|
||||||
|
|
||||||
|
const homeComputer = p.getHomeComputer();
|
||||||
|
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
|
||||||
|
dialogBoxCreate(<>
|
||||||
|
You've have the maximum amount of RAM on your home computer.
|
||||||
|
</>);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
yesBtn.innerText = "Purchase";
|
yesBtn.innerText = "Purchase";
|
||||||
yesBtn.addEventListener("click", ()=>{
|
yesBtn.addEventListener("click", ()=>{
|
||||||
purchaseRamForHomeComputer(cost, p);
|
purchaseRamForHomeComputer(cost, p);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export enum LocationName {
|
|||||||
AevumSnapFitnessGym = "Snap Fitness Gym",
|
AevumSnapFitnessGym = "Snap Fitness Gym",
|
||||||
AevumSummitUniversity = "Summit University",
|
AevumSummitUniversity = "Summit University",
|
||||||
AevumWatchdogSecurity = "Watchdog Security",
|
AevumWatchdogSecurity = "Watchdog Security",
|
||||||
|
AevumCasino = "Iker Molina Casino",
|
||||||
|
|
||||||
// Chongqing locations
|
// Chongqing locations
|
||||||
ChongqingKuaiGongInternational = "KuaiGong International",
|
ChongqingKuaiGongInternational = "KuaiGong International",
|
||||||
|
|||||||
@@ -145,6 +145,11 @@ export const LocationsMetadata: IConstructorParams[] = [
|
|||||||
name: LocationName.AevumWatchdogSecurity,
|
name: LocationName.AevumWatchdogSecurity,
|
||||||
types: [LocationType.Company],
|
types: [LocationType.Company],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
city: CityName.Aevum,
|
||||||
|
name: LocationName.AevumCasino,
|
||||||
|
types: [LocationType.Casino],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
city: CityName.Chongqing,
|
city: CityName.Chongqing,
|
||||||
infiltrationData: {
|
infiltrationData: {
|
||||||
|
|||||||
89
src/Locations/ui/CasinoLocation.tsx
Normal file
89
src/Locations/ui/CasinoLocation.tsx
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* React Subcomponent for displaying a location's UI, when that location is a gym
|
||||||
|
*
|
||||||
|
* This subcomponent renders all of the buttons for training at the gym
|
||||||
|
*/
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { Location } from "../Location";
|
||||||
|
|
||||||
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
|
import { Money } from "../../ui/React/Money";
|
||||||
|
import { SlotMachine } from "../../Casino/SlotMachine";
|
||||||
|
import { CoinFlip } from "../../Casino/CoinFlip";
|
||||||
|
import { Roulette } from "../../Casino/Roulette";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
p: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
game: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CasinoLocation extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
game: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateGame = this.updateGame.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGame(game: string) {
|
||||||
|
this.setState({
|
||||||
|
game: game,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGames() {
|
||||||
|
return (<>
|
||||||
|
<StdButton
|
||||||
|
onClick={() => this.updateGame('coin')}
|
||||||
|
text={"Play coin flip"}
|
||||||
|
/><br />
|
||||||
|
<StdButton
|
||||||
|
onClick={() => this.updateGame('slots')}
|
||||||
|
text={"Play slots"}
|
||||||
|
/><br />
|
||||||
|
<StdButton
|
||||||
|
onClick={() => this.updateGame('roulette')}
|
||||||
|
text={"Play roulette"}
|
||||||
|
/>
|
||||||
|
</>)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGame() {
|
||||||
|
let elem;
|
||||||
|
switch(this.state.game) {
|
||||||
|
case 'coin':
|
||||||
|
elem = <CoinFlip p={this.props.p} />
|
||||||
|
break;
|
||||||
|
case 'slots':
|
||||||
|
elem = <SlotMachine p={this.props.p} />
|
||||||
|
break;
|
||||||
|
case 'roulette':
|
||||||
|
elem = <Roulette p={this.props.p} />
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<StdButton onClick={() => this.updateGame('')} text={"Stop playing"} />
|
||||||
|
{elem}
|
||||||
|
</>)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if(!this.state.game) {
|
||||||
|
return this.renderGames();
|
||||||
|
} else {
|
||||||
|
return this.renderGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import * as React from "react";
|
|||||||
|
|
||||||
import { City } from "../City";
|
import { City } from "../City";
|
||||||
import { LocationName } from "../data/LocationNames";
|
import { LocationName } from "../data/LocationNames";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ type IProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class LocationCity extends React.Component<IProps, any> {
|
export class LocationCity extends React.Component<IProps, any> {
|
||||||
render() {
|
asciiCity() {
|
||||||
const thiscity = this;
|
const thiscity = this;
|
||||||
const topprop = this.props
|
const topprop = this.props
|
||||||
|
|
||||||
@@ -66,9 +67,29 @@ export class LocationCity extends React.Component<IProps, any> {
|
|||||||
elems.push(<pre key={i}>{lineElems(lines[i])}</pre>)
|
elems.push(<pre key={i}>{lineElems(lines[i])}</pre>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
listCity() {
|
||||||
|
const locationButtons = this.props.city.locations.map((locName) => {
|
||||||
|
return (
|
||||||
|
<li key={locName}>
|
||||||
|
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} />
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{locationButtons}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{elems}
|
{Settings.DisableASCIIArt ? this.listCity() : this.asciiCity()}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { SpecialLocation } from "./SpecialLocation";
|
|||||||
import { TechVendorLocation } from "./TechVendorLocation";
|
import { TechVendorLocation } from "./TechVendorLocation";
|
||||||
import { TravelAgencyLocation } from "./TravelAgencyLocation";
|
import { TravelAgencyLocation } from "./TravelAgencyLocation";
|
||||||
import { UniversityLocation } from "./UniversityLocation";
|
import { UniversityLocation } from "./UniversityLocation";
|
||||||
|
import { CasinoLocation } from "./CasinoLocation";
|
||||||
|
|
||||||
import { Location } from "../Location";
|
import { Location } from "../Location";
|
||||||
import { LocationType } from "../LocationTypeEnum";
|
import { LocationType } from "../LocationTypeEnum";
|
||||||
@@ -131,6 +132,15 @@ export class GenericLocation extends React.Component<IProps, any> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.props.loc.types.includes(LocationType.Casino)) {
|
||||||
|
content.push(
|
||||||
|
<CasinoLocation
|
||||||
|
key={"casinoLocation"}
|
||||||
|
p={this.props.p}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ import * as React from "react";
|
|||||||
|
|
||||||
import { Location } from "../Location";
|
import { Location } from "../Location";
|
||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { getServer } from "../../Server/ServerHelpers";
|
||||||
|
import { Server } from "../../Server/Server";
|
||||||
|
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
@@ -34,11 +37,22 @@ export class GymLocation extends React.Component<IProps, any> {
|
|||||||
this.trainDefense = this.trainDefense.bind(this);
|
this.trainDefense = this.trainDefense.bind(this);
|
||||||
this.trainDexterity = this.trainDexterity.bind(this);
|
this.trainDexterity = this.trainDexterity.bind(this);
|
||||||
this.trainAgility = this.trainAgility.bind(this);
|
this.trainAgility = this.trainAgility.bind(this);
|
||||||
|
|
||||||
|
this.calculateCost = this.calculateCost.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateCost(): number {
|
||||||
|
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||||
|
console.log(`ip: ${ip}`);
|
||||||
|
const server = getServer(ip);
|
||||||
|
if(server == null || !server.hasOwnProperty('manuallyHacked')) return this.props.loc.costMult;
|
||||||
|
const discount = (server as Server).manuallyHacked? 0.9 : 1;
|
||||||
|
return this.props.loc.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
train(stat: string) {
|
train(stat: string) {
|
||||||
const loc = this.props.loc;
|
const loc = this.props.loc;
|
||||||
this.props.p.startClass(loc.costMult, loc.expMult, stat);
|
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
trainStrength() {
|
trainStrength() {
|
||||||
@@ -58,9 +72,7 @@ export class GymLocation extends React.Component<IProps, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const costMult: number = this.props.loc.costMult;
|
const cost = CONSTANTS.ClassGymBaseCost * this.calculateCost();
|
||||||
|
|
||||||
const cost = CONSTANTS.ClassGymBaseCost * costMult;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import * as React from "react";
|
|||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { getHospitalizationCost } from "../../Hospital/Hospital";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
|
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
|
||||||
@@ -42,7 +43,7 @@ export class HospitalLocation extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCost(): number {
|
getCost(): number {
|
||||||
return (this.props.p.max_hp - this.props.p.hp) * CONSTANTS.HospitalCostPerHp;
|
return getHospitalizationCost(this.props.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
getHealed(e: React.MouseEvent<HTMLElement>): void {
|
getHealed(e: React.MouseEvent<HTMLElement>): void {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { createTravelPopup } from "../LocationsHelpers";
|
|||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
@@ -32,7 +33,7 @@ export class TravelAgencyLocation extends React.Component<IProps, any> {
|
|||||||
this.btnStyle = { display: "block" };
|
this.btnStyle = { display: "block" };
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
asciiWorldMap() {
|
||||||
const thisTravelAgencyLocation = this;
|
const thisTravelAgencyLocation = this;
|
||||||
|
|
||||||
function LocationLetter(props: any) {
|
function LocationLetter(props: any) {
|
||||||
@@ -76,4 +77,42 @@ export class TravelAgencyLocation extends React.Component<IProps, any> {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
listWorldMap() {
|
||||||
|
const travelBtns: React.ReactNode[] = [];
|
||||||
|
for (const key in CityName) {
|
||||||
|
const city = CityName[key];
|
||||||
|
|
||||||
|
// Skip current city
|
||||||
|
if (city === this.props.p.city) { continue; }
|
||||||
|
|
||||||
|
travelBtns.push(
|
||||||
|
<StdButton
|
||||||
|
key={city}
|
||||||
|
onClick={createTravelPopup.bind(null, city, this.props.travel)}
|
||||||
|
style={this.btnStyle}
|
||||||
|
text={`Travel to ${city}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
From here, you can travel to any other city! A ticket
|
||||||
|
costs {Money(CONSTANTS.TravelCost)}.
|
||||||
|
</p>
|
||||||
|
{travelBtns}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (Settings.DisableASCIIArt) {
|
||||||
|
return this.listWorldMap();
|
||||||
|
} else {
|
||||||
|
return this.asciiWorldMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { Location } from "../Location";
|
|||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { getServer } from "../../Server/ServerHelpers";
|
||||||
|
import { Server } from "../../Server/Server";
|
||||||
|
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
@@ -37,11 +40,22 @@ export class UniversityLocation extends React.Component<IProps, any> {
|
|||||||
this.algorithms = this.algorithms.bind(this);
|
this.algorithms = this.algorithms.bind(this);
|
||||||
this.management = this.management.bind(this);
|
this.management = this.management.bind(this);
|
||||||
this.leadership = this.leadership.bind(this);
|
this.leadership = this.leadership.bind(this);
|
||||||
|
|
||||||
|
this.calculateCost = this.calculateCost.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateCost(): number {
|
||||||
|
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||||
|
console.log(`ip: ${ip}`);
|
||||||
|
const server = getServer(ip);
|
||||||
|
if(server == null || !server.hasOwnProperty('manuallyHacked')) return this.props.loc.costMult;
|
||||||
|
const discount = (server as Server).manuallyHacked? 0.9 : 1;
|
||||||
|
return this.props.loc.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
take(stat: string) {
|
take(stat: string) {
|
||||||
const loc = this.props.loc;
|
const loc = this.props.loc;
|
||||||
this.props.p.startClass(loc.costMult, loc.expMult, stat);
|
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
study() {
|
study() {
|
||||||
@@ -69,7 +83,7 @@ export class UniversityLocation extends React.Component<IProps, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const costMult: number = this.props.loc.costMult;
|
const costMult: number = this.calculateCost();
|
||||||
|
|
||||||
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
|
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
|
||||||
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
|
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ export const RamCosts: IMap<any> = {
|
|||||||
getStats: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
getStats: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||||
getCharacterInformation: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
getCharacterInformation: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||||
getPlayer: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
getPlayer: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||||
|
hospitalize: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||||
isBusy: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
isBusy: () => RamCostConstants.ScriptSingularityFn1RamCost / 4,
|
||||||
stopAction: () => RamCostConstants.ScriptSingularityFn1RamCost / 2,
|
stopAction: () => RamCostConstants.ScriptSingularityFn1RamCost / 2,
|
||||||
upgradeHomeRam: () => RamCostConstants.ScriptSingularityFn2RamCost,
|
upgradeHomeRam: () => RamCostConstants.ScriptSingularityFn2RamCost,
|
||||||
|
|||||||
@@ -686,13 +686,29 @@ function NetscriptFunctions(workerScript) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const argsToString = function(args) {
|
||||||
|
let out = '';
|
||||||
|
for(let arg of args) {
|
||||||
|
if(typeof arg === 'object') {
|
||||||
|
out += JSON.stringify(arg);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out += `${arg}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hacknet : {
|
hacknet : {
|
||||||
numNodes : function() {
|
numNodes : function() {
|
||||||
return Player.hacknetNodes.length;
|
return Player.hacknetNodes.length;
|
||||||
},
|
},
|
||||||
maxNumNodes : function() {
|
maxNumNodes : function() {
|
||||||
return MaxNumberHacknetServers;
|
if (hasHacknetServers()) {
|
||||||
|
return HacknetServerConstants.MaxServers;
|
||||||
|
}
|
||||||
|
return Infinity;
|
||||||
},
|
},
|
||||||
purchaseNode : function() {
|
purchaseNode : function() {
|
||||||
return purchaseHacknet();
|
return purchaseHacknet();
|
||||||
@@ -766,6 +782,10 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if (!hasHacknetServers()) { return 0; }
|
if (!hasHacknetServers()) { return 0; }
|
||||||
return Player.hashManager.hashes;
|
return Player.hashManager.hashes;
|
||||||
},
|
},
|
||||||
|
hashCapacity: function() {
|
||||||
|
if (!hasHacknetServers()) { return 0; }
|
||||||
|
return Player.hashManager.capacity;
|
||||||
|
},
|
||||||
hashCost : function(upgName) {
|
hashCost : function(upgName) {
|
||||||
if (!hasHacknetServers()) { return Infinity; }
|
if (!hasHacknetServers()) { return Infinity; }
|
||||||
|
|
||||||
@@ -904,7 +924,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
|
|
||||||
// Check argument validity
|
// Check argument validity
|
||||||
const server = safeGetServer(ip, 'growthAnalyze');
|
const server = safeGetServer(ip, 'growthAnalyze');
|
||||||
if (typeof growth !== "number" || isNaN(growth) || growth < 1) {
|
if (typeof growth !== "number" || isNaN(growth) || growth < 1 || !isFinite(growth)) {
|
||||||
throw makeRuntimeErrorMsg("growthAnalyze", `Invalid argument: growth must be numeric and >= 1, is ${growth}.`);
|
throw makeRuntimeErrorMsg("growthAnalyze", `Invalid argument: growth must be numeric and >= 1, is ${growth}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,18 +960,17 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
|
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
print: function(args){
|
print: function(){
|
||||||
if (args === undefined) {
|
if (arguments.length === 0) {
|
||||||
throw makeRuntimeErrorMsg("print", "Takes 1 argument.");
|
throw makeRuntimeErrorMsg("print", "Takes at least 1 argument.");
|
||||||
}
|
}
|
||||||
workerScript.print(args.toString());
|
workerScript.print(argsToString(arguments));
|
||||||
},
|
},
|
||||||
tprint: function(args) {
|
tprint: function() {
|
||||||
if (args === undefined || args == null) {
|
if (arguments.length === 0) {
|
||||||
throw makeRuntimeErrorMsg("tprint", "Takes 1 argument.");
|
throw makeRuntimeErrorMsg("tprint", "Takes at least 1 argument.");
|
||||||
}
|
}
|
||||||
var x = args.toString();
|
post(`${workerScript.scriptRef.filename}: ${argsToString(arguments)}`);
|
||||||
post(`${workerScript.scriptRef.filename}: ${args.toString()}`);
|
|
||||||
},
|
},
|
||||||
clearLog: function() {
|
clearLog: function() {
|
||||||
workerScript.scriptRef.clearLog();
|
workerScript.scriptRef.clearLog();
|
||||||
@@ -2018,7 +2037,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
const cost = getPurchaseServerCost(ram);
|
const cost = getPurchaseServerCost(ram);
|
||||||
if (cost === Infinity) {
|
if (cost === Infinity) {
|
||||||
workerScript.log("purchaseServer", `Invalid argument: ram='${ram}'`);
|
workerScript.log("purchaseServer", `Invalid argument: ram='${ram}'`);
|
||||||
return Infinity;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.money.lt(cost)) {
|
if (Player.money.lt(cost)) {
|
||||||
@@ -2970,10 +2989,17 @@ function NetscriptFunctions(workerScript) {
|
|||||||
playtimeSinceLastAug: Player.playtimeSinceLastAug,
|
playtimeSinceLastAug: Player.playtimeSinceLastAug,
|
||||||
playtimeSinceLastBitnode: Player.playtimeSinceLastBitnode,
|
playtimeSinceLastBitnode: Player.playtimeSinceLastBitnode,
|
||||||
jobs: {},
|
jobs: {},
|
||||||
|
factions: Player.factions.slice(),
|
||||||
|
tor: SpecialServerIps.hasOwnProperty("Darkweb Server"),
|
||||||
};
|
};
|
||||||
Object.assign(data.jobs, Player.jobs);
|
Object.assign(data.jobs, Player.jobs);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
hospitalize: function() {
|
||||||
|
updateDynamicRam("hospitalize", getRamCost("hospitalize"));
|
||||||
|
checkSingularityAccess("hospitalize", 1);
|
||||||
|
return Player.hospitalize();
|
||||||
|
},
|
||||||
isBusy: function() {
|
isBusy: function() {
|
||||||
updateDynamicRam("isBusy", getRamCost("isBusy"));
|
updateDynamicRam("isBusy", getRamCost("isBusy"));
|
||||||
checkSingularityAccess("isBusy", 1);
|
checkSingularityAccess("isBusy", 1);
|
||||||
@@ -3574,27 +3600,35 @@ function NetscriptFunctions(workerScript) {
|
|||||||
checkGangApiAccess("getMemberInformation");
|
checkGangApiAccess("getMemberInformation");
|
||||||
const member = getGangMember("getMemberInformation", name);
|
const member = getGangMember("getMemberInformation", name);
|
||||||
return {
|
return {
|
||||||
agility: member.agi,
|
name: member.name,
|
||||||
agilityEquipMult: member.agi_mult,
|
task: member.task,
|
||||||
agilityAscensionMult: member.agi_asc_mult,
|
earnedRespect: member.earnedRespect,
|
||||||
augmentations: member.augmentations.slice(),
|
hack: member.hack,
|
||||||
charisma: member.cha,
|
str: member.str,
|
||||||
charismaEquipMult: member.cha_mult,
|
def: member.def,
|
||||||
charismaAscensionMult: member.cha_asc_mult,
|
dex: member.dex,
|
||||||
defense: member.def,
|
agi: member.agi,
|
||||||
defenseEquipMult: member.def_mult,
|
cha: member.cha,
|
||||||
defenseAscensionMult: member.def_asc_mult,
|
hack_exp: member.hack_exp,
|
||||||
dexterity: member.dex,
|
str_exp: member.str_exp,
|
||||||
dexterityEquipMult: member.dex_mult,
|
def_exp: member.def_exp,
|
||||||
dexterityAscensionMult: member.dex_asc_mult,
|
dex_exp: member.dex_exp,
|
||||||
equipment: member.upgrades.slice(),
|
agi_exp: member.agi_exp,
|
||||||
hacking: member.hack,
|
cha_exp: member.cha_exp,
|
||||||
hackingEquipMult: member.hack_mult,
|
hack_mult: member.hack_mult,
|
||||||
hackingAscensionMult: member.hack_asc_mult,
|
str_mult: member.str_mult,
|
||||||
strength: member.str,
|
def_mult: member.def_mult,
|
||||||
strengthEquipMult: member.str_mult,
|
dex_mult: member.dex_mult,
|
||||||
strengthAscensionMult: member.str_asc_mult,
|
agi_mult: member.agi_mult,
|
||||||
task: member.task,
|
cha_mult: member.cha_mult,
|
||||||
|
hack_asc_mult: member.hack_asc_mult,
|
||||||
|
str_asc_mult: member.str_asc_mult,
|
||||||
|
def_asc_mult: member.def_asc_mult,
|
||||||
|
dex_asc_mult: member.dex_asc_mult,
|
||||||
|
agi_asc_mult: member.agi_asc_mult,
|
||||||
|
cha_asc_mult: member.cha_asc_mult,
|
||||||
|
upgrades: member.upgrades.slice(),
|
||||||
|
augmentations: member.augmentations.slice(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
canRecruitMember: function() {
|
canRecruitMember: function() {
|
||||||
@@ -4366,4 +4400,4 @@ function NetscriptFunctions(workerScript) {
|
|||||||
} // End return
|
} // End return
|
||||||
} // End NetscriptFunction()
|
} // End NetscriptFunction()
|
||||||
|
|
||||||
export { NetscriptFunctions };
|
export { NetscriptFunctions };
|
||||||
@@ -107,7 +107,7 @@ export function _getScriptUrls(script, scripts, seen) {
|
|||||||
// import {foo} from "blob://<uuid>"
|
// import {foo} from "blob://<uuid>"
|
||||||
//
|
//
|
||||||
// Where the blob URL contains the script content.
|
// Where the blob URL contains the script content.
|
||||||
let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))(?:\.\/)?([^'"]+)('|";)/g,
|
let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))(?:\.\/)?([^'"]+)('|")/g,
|
||||||
(unmodified, prefix, filename, suffix) => {
|
(unmodified, prefix, filename, suffix) => {
|
||||||
const isAllowedImport = scripts.some(s => s.filename == filename);
|
const isAllowedImport = scripts.some(s => s.filename == filename);
|
||||||
if (!isAllowedImport) return unmodified;
|
if (!isAllowedImport) return unmodified;
|
||||||
|
|||||||
@@ -179,4 +179,5 @@ export interface IPlayer {
|
|||||||
giveExploit(exploit: Exploit): void;
|
giveExploit(exploit: Exploit): void;
|
||||||
queryStatFromString(str: string): number;
|
queryStatFromString(str: string): number;
|
||||||
getIntelligenceBonus(weight: number): number;
|
getIntelligenceBonus(weight: number): number;
|
||||||
|
getCasinoWinnings(): number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ import { LocationName } from "../../Locations/data/LocationNames";
|
|||||||
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
|
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
|
||||||
import { calculateSkill as calculateSkillF } from "../formulas/skill";
|
import { calculateSkill as calculateSkillF } from "../formulas/skill";
|
||||||
import { calculateIntelligenceBonus } from "../formulas/intelligence";
|
import { calculateIntelligenceBonus } from "../formulas/intelligence";
|
||||||
|
import {
|
||||||
|
getHackingWorkRepGain,
|
||||||
|
getFactionSecurityWorkRepGain,
|
||||||
|
getFactionFieldWorkRepGain,
|
||||||
|
} from '../formulas/reputation';
|
||||||
import {
|
import {
|
||||||
AllServers,
|
AllServers,
|
||||||
AddToAllServers,
|
AddToAllServers,
|
||||||
@@ -43,6 +48,7 @@ import { applyExploit } from "../../Exploits/applyExploits";
|
|||||||
import { SourceFiles } from "../../SourceFile/SourceFiles";
|
import { SourceFiles } from "../../SourceFile/SourceFiles";
|
||||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||||
import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing";
|
import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing";
|
||||||
|
import { getHospitalizationCost } from "../../Hospital/Hospital";
|
||||||
|
|
||||||
import Decimal from "decimal.js";
|
import Decimal from "decimal.js";
|
||||||
|
|
||||||
@@ -428,6 +434,8 @@ export function gainHackingExp(exp) {
|
|||||||
if(this.hacking_exp < 0) {
|
if(this.hacking_exp < 0) {
|
||||||
this.hacking_exp = 0;
|
this.hacking_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.hacking_skill = calculateSkillF(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainStrengthExp(exp) {
|
export function gainStrengthExp(exp) {
|
||||||
@@ -438,6 +446,8 @@ export function gainStrengthExp(exp) {
|
|||||||
if(this.strength_exp < 0) {
|
if(this.strength_exp < 0) {
|
||||||
this.strength_exp = 0;
|
this.strength_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.strength = calculateSkillF(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainDefenseExp(exp) {
|
export function gainDefenseExp(exp) {
|
||||||
@@ -448,6 +458,8 @@ export function gainDefenseExp(exp) {
|
|||||||
if(this.defense_exp < 0) {
|
if(this.defense_exp < 0) {
|
||||||
this.defense_exp = 0;
|
this.defense_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.defense = calculateSkillF(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainDexterityExp(exp) {
|
export function gainDexterityExp(exp) {
|
||||||
@@ -458,6 +470,8 @@ export function gainDexterityExp(exp) {
|
|||||||
if(this.dexterity_exp < 0) {
|
if(this.dexterity_exp < 0) {
|
||||||
this.dexterity_exp = 0;
|
this.dexterity_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.dexterity = calculateSkillF(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainAgilityExp(exp) {
|
export function gainAgilityExp(exp) {
|
||||||
@@ -468,6 +482,8 @@ export function gainAgilityExp(exp) {
|
|||||||
if(this.agility_exp < 0) {
|
if(this.agility_exp < 0) {
|
||||||
this.agility_exp = 0;
|
this.agility_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.agility = calculateSkillF(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainCharismaExp(exp) {
|
export function gainCharismaExp(exp) {
|
||||||
@@ -478,6 +494,8 @@ export function gainCharismaExp(exp) {
|
|||||||
if(this.charisma_exp < 0) {
|
if(this.charisma_exp < 0) {
|
||||||
this.charisma_exp = 0;
|
this.charisma_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.charisma = calculateSkillF(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainIntelligenceExp(exp) {
|
export function gainIntelligenceExp(exp) {
|
||||||
@@ -549,7 +567,11 @@ export function processWorkEarnings(numCycles=1) {
|
|||||||
this.gainAgilityExp(agiExpGain);
|
this.gainAgilityExp(agiExpGain);
|
||||||
this.gainCharismaExp(chaExpGain);
|
this.gainCharismaExp(chaExpGain);
|
||||||
this.gainMoney(moneyGain);
|
this.gainMoney(moneyGain);
|
||||||
this.recordMoneySource(moneyGain, "work");
|
if (this.className) {
|
||||||
|
this.recordMoneySource(moneyGain, "class");
|
||||||
|
} else {
|
||||||
|
this.recordMoneySource(moneyGain, "work");
|
||||||
|
}
|
||||||
this.workHackExpGained += hackExpGain;
|
this.workHackExpGained += hackExpGain;
|
||||||
this.workStrExpGained += strExpGain;
|
this.workStrExpGained += strExpGain;
|
||||||
this.workDefExpGained += defExpGain;
|
this.workDefExpGained += defExpGain;
|
||||||
@@ -591,6 +613,17 @@ export function startWork(companyName) {
|
|||||||
Engine.loadWorkInProgressContent();
|
Engine.loadWorkInProgressContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cancelationPenalty() {
|
||||||
|
const company = Companies[this.companyName];
|
||||||
|
const specialIp = SpecialServerIps[this.companyName];
|
||||||
|
if(specialIp) {
|
||||||
|
const server = AllServers[specialIp];
|
||||||
|
if(server && server.manuallyHacked) return 0.75;
|
||||||
|
}
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function work(numCycles) {
|
export function work(numCycles) {
|
||||||
// Cap the number of cycles being processed to whatever would put you at
|
// Cap the number of cycles being processed to whatever would put you at
|
||||||
// the work time limit (8 hours)
|
// the work time limit (8 hours)
|
||||||
@@ -621,6 +654,10 @@ export function work(numCycles) {
|
|||||||
|
|
||||||
const position = this.jobs[this.companyName];
|
const position = this.jobs[this.companyName];
|
||||||
|
|
||||||
|
const penalty = this.cancelationPenalty();
|
||||||
|
|
||||||
|
const penaltyString = penalty === 0.5 ? 'half' : 'three quarter'
|
||||||
|
|
||||||
var elem = document.getElementById("work-in-progress-text");
|
var elem = document.getElementById("work-in-progress-text");
|
||||||
ReactDOM.render(<>
|
ReactDOM.render(<>
|
||||||
You are currently working as a {position} at {this.companyName} (Current Company Reputation: {Reputation(companyRep)})<br /><br />
|
You are currently working as a {position} at {this.companyName} (Current Company Reputation: {Reputation(companyRep)})<br /><br />
|
||||||
@@ -635,17 +672,17 @@ export function work(numCycles) {
|
|||||||
{numeralWrapper.formatExp(this.workAgiExpGained)} ({`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}) agility exp <br /><br />
|
{numeralWrapper.formatExp(this.workAgiExpGained)} ({`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}) agility exp <br /><br />
|
||||||
{numeralWrapper.formatExp(this.workChaExpGained)} ({`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}) charisma exp <br /><br />
|
{numeralWrapper.formatExp(this.workChaExpGained)} ({`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}) charisma exp <br /><br />
|
||||||
You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
|
You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
|
||||||
but you will only gain half of the reputation you've earned so far.
|
but you will only gain {penaltyString} of the reputation you've earned so far.
|
||||||
</>, elem);
|
</>, elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function finishWork(cancelled, sing=false) {
|
export function finishWork(cancelled, sing=false) {
|
||||||
//Since the work was cancelled early, player only gains half of what they've earned so far
|
//Since the work was cancelled early, player only gains half of what they've earned so far
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
this.workRepGained /= 2;
|
this.workRepGained *= this.cancelationPenalty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
company.playerReputation += (this.workRepGained);
|
company.playerReputation += (this.workRepGained);
|
||||||
|
|
||||||
this.updateSkillLevels();
|
this.updateSkillLevels();
|
||||||
@@ -852,7 +889,7 @@ export function startFactionFieldWork(faction) {
|
|||||||
this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = this.getFactionFieldWorkRepGain();
|
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkField;
|
this.factionWorkType = CONSTANTS.FactionWorkField;
|
||||||
this.currentWorkFactionDescription = "carrying out field missions"
|
this.currentWorkFactionDescription = "carrying out field missions"
|
||||||
@@ -869,7 +906,7 @@ export function startFactionSecurityWork(faction) {
|
|||||||
this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = this.getFactionSecurityWorkRepGain();
|
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
|
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
|
||||||
this.currentWorkFactionDescription = "performing security detail"
|
this.currentWorkFactionDescription = "performing security detail"
|
||||||
@@ -878,29 +915,23 @@ export function startFactionSecurityWork(faction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function workForFaction(numCycles) {
|
export function workForFaction(numCycles) {
|
||||||
var faction = Factions[this.currentWorkFactionName];
|
const faction = Factions[this.currentWorkFactionName];
|
||||||
|
|
||||||
//Constantly update the rep gain rate
|
//Constantly update the rep gain rate
|
||||||
switch (this.factionWorkType) {
|
switch (this.factionWorkType) {
|
||||||
case CONSTANTS.FactionWorkHacking:
|
case CONSTANTS.FactionWorkHacking:
|
||||||
this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult * this.getIntelligenceBonus(0.5);
|
this.workRepGainRate = getHackingWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.FactionWorkField:
|
case CONSTANTS.FactionWorkField:
|
||||||
this.workRepGainRate = this.getFactionFieldWorkRepGain();
|
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.FactionWorkSecurity:
|
case CONSTANTS.FactionWorkSecurity:
|
||||||
this.workRepGainRate = this.getFactionSecurityWorkRepGain();
|
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update reputation gain rate to account for faction favor
|
|
||||||
var favorMult = 1 + (faction.favor / 100);
|
|
||||||
if (isNaN(favorMult)) {favorMult = 1;}
|
|
||||||
this.workRepGainRate *= favorMult;
|
|
||||||
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
|
|
||||||
|
|
||||||
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
||||||
var overMax = false;
|
var overMax = false;
|
||||||
if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) {
|
if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) {
|
||||||
@@ -1111,25 +1142,25 @@ export function getWorkRepGain() {
|
|||||||
return jobPerformance * this.company_rep_mult * favorMult;
|
return jobPerformance * this.company_rep_mult * favorMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFactionSecurityWorkRepGain() {
|
// export function getFactionSecurityWorkRepGain() {
|
||||||
var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
// var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
this.strength / CONSTANTS.MaxSkillLevel +
|
// this.strength / CONSTANTS.MaxSkillLevel +
|
||||||
this.defense / CONSTANTS.MaxSkillLevel +
|
// this.defense / CONSTANTS.MaxSkillLevel +
|
||||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
// this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
this.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
// this.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
||||||
return t * this.faction_rep_mult;
|
// return t * this.faction_rep_mult;
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function getFactionFieldWorkRepGain() {
|
// export function getFactionFieldWorkRepGain() {
|
||||||
var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
// var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
this.strength / CONSTANTS.MaxSkillLevel +
|
// this.strength / CONSTANTS.MaxSkillLevel +
|
||||||
this.defense / CONSTANTS.MaxSkillLevel +
|
// this.defense / CONSTANTS.MaxSkillLevel +
|
||||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
// this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
this.agility / CONSTANTS.MaxSkillLevel +
|
// this.agility / CONSTANTS.MaxSkillLevel +
|
||||||
this.charisma / CONSTANTS.MaxSkillLevel +
|
// this.charisma / CONSTANTS.MaxSkillLevel +
|
||||||
this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
// this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
||||||
return t * this.faction_rep_mult;
|
// return t * this.faction_rep_mult;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* Creating a Program */
|
/* Creating a Program */
|
||||||
export function startCreateProgramWork(programName, time, reqLevel) {
|
export function startCreateProgramWork(programName, time, reqLevel) {
|
||||||
@@ -1504,7 +1535,6 @@ export function finishCrime(cancelled) {
|
|||||||
dialogBoxCreate(<>
|
dialogBoxCreate(<>
|
||||||
Crime failed!<br /><br />
|
Crime failed!<br /><br />
|
||||||
You gained:<br />
|
You gained:<br />
|
||||||
{Money(this.workMoneyGained)}<br />
|
|
||||||
{numeralWrapper.formatExp(this.workHackExpGained)} hacking experience <br />
|
{numeralWrapper.formatExp(this.workHackExpGained)} hacking experience <br />
|
||||||
{numeralWrapper.formatExp(this.workStrExpGained)} strength experience<br />
|
{numeralWrapper.formatExp(this.workStrExpGained)} strength experience<br />
|
||||||
{numeralWrapper.formatExp(this.workDefExpGained)} defense experience<br />
|
{numeralWrapper.formatExp(this.workDefExpGained)} defense experience<br />
|
||||||
@@ -1589,18 +1619,19 @@ export function regenerateHp(amt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hospitalize() {
|
export function hospitalize() {
|
||||||
|
const cost = getHospitalizationCost(this);
|
||||||
if (Settings.SuppressHospitalizationPopup === false) {
|
if (Settings.SuppressHospitalizationPopup === false) {
|
||||||
dialogBoxCreate(<>
|
dialogBoxCreate(<>
|
||||||
You were in critical condition! You were taken to the hospital where
|
You were in critical condition! You were taken to the hospital where
|
||||||
luckily they were able to save your life. You were charged
|
luckily they were able to save your life. You were charged
|
||||||
{Money(this.max_hp * CONSTANTS.HospitalCostPerHp)}
|
{Money(cost)}
|
||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cost = this.max_hp * CONSTANTS.HospitalCostPerHp
|
|
||||||
this.loseMoney(cost);
|
this.loseMoney(cost);
|
||||||
this.recordMoneySource(-1 * cost, "hospitalization");
|
this.recordMoneySource(-1 * cost, "hospitalization");
|
||||||
this.hp = this.max_hp;
|
this.hp = this.max_hp;
|
||||||
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********* Company job application **********/
|
/********* Company job application **********/
|
||||||
@@ -2334,7 +2365,10 @@ export function giveExploit(exploit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getIntelligenceBonus(weight) {
|
export function getIntelligenceBonus(weight) {
|
||||||
return calculateIntelligenceBonus(this.intelligence, weight);
|
return calculateIntelligenceBonus(this.intelligence, weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCasinoWinnings() {
|
||||||
|
return this.moneySourceA.casino;
|
||||||
}
|
}
|
||||||
36
src/PersonObjects/formulas/reputation.ts
Normal file
36
src/PersonObjects/formulas/reputation.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { IPlayer } from '../IPlayer';
|
||||||
|
import { Faction } from '../../Faction/Faction';
|
||||||
|
import { CONSTANTS } from '../../Constants';
|
||||||
|
import { BitNodeMultipliers } from '../../BitNode/BitNodeMultipliers';
|
||||||
|
|
||||||
|
function mult(f: Faction): number {
|
||||||
|
var favorMult = 1 + (f.favor / 100);
|
||||||
|
if (isNaN(favorMult)) {favorMult = 1;}
|
||||||
|
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHackingWorkRepGain(p: IPlayer, f: Faction): number {
|
||||||
|
return (p.hacking_skill + p.intelligence) /
|
||||||
|
CONSTANTS.MaxSkillLevel * p.faction_rep_mult *
|
||||||
|
p.getIntelligenceBonus(0.25) * mult(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFactionSecurityWorkRepGain(p: IPlayer, f: Faction): number {
|
||||||
|
var t = 0.9 * (p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.strength / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.defense / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
||||||
|
return t * p.faction_rep_mult * mult(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFactionFieldWorkRepGain(p: IPlayer, f: Faction): number {
|
||||||
|
var t = 0.9 * (p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.strength / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.defense / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.agility / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.charisma / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
||||||
|
return t * p.faction_rep_mult * mult(f);
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { AceEditor } from "../ScriptEditor/Ace";
|
import { AceEditor } from "../ScriptEditor/Ace";
|
||||||
import { CodeMirrorEditor } from "../ScriptEditor/CodeMirror";
|
import { CodeMirrorEditor } from "../ScriptEditor/CodeMirror";
|
||||||
|
import { CursorPositions } from "../ScriptEditor/CursorPositions";
|
||||||
import { AllServers } from "../Server/AllServers";
|
import { AllServers } from "../Server/AllServers";
|
||||||
import { processSingleServerGrowth } from "../Server/ServerHelpers";
|
import { processSingleServerGrowth } from "../Server/ServerHelpers";
|
||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
@@ -224,11 +225,13 @@ $(document).keydown(function(e) {
|
|||||||
function saveAndCloseScriptEditor() {
|
function saveAndCloseScriptEditor() {
|
||||||
var filename = document.getElementById("script-editor-filename").value;
|
var filename = document.getElementById("script-editor-filename").value;
|
||||||
|
|
||||||
let code;
|
let code, cursor;
|
||||||
try {
|
try {
|
||||||
code = getCurrentEditor().getCode();
|
code = getCurrentEditor().getCode();
|
||||||
|
cursor = getCurrentEditor().getCursor();
|
||||||
|
CursorPositions.saveCursor(filename, cursor);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
dialogBoxCreate("Something went wrong when trying to save (getCurrentEditor().getCode()). Please report to game developer with details");
|
dialogBoxCreate("Something went wrong when trying to save (getCurrentEditor().getCode() or getCurrentEditor().getCursor()). Please report to game developer with details");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +285,7 @@ function saveAndCloseScriptEditor() {
|
|||||||
}
|
}
|
||||||
} else if (isScriptFilename(filename)) {
|
} else if (isScriptFilename(filename)) {
|
||||||
//If the current script already exists on the server, overwrite it
|
//If the current script already exists on the server, overwrite it
|
||||||
for (var i = 0; i < s.scripts.length; i++) {
|
for (let i = 0; i < s.scripts.length; i++) {
|
||||||
if (filename == s.scripts[i].filename) {
|
if (filename == s.scripts[i].filename) {
|
||||||
s.scripts[i].saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
s.scripts[i].saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
||||||
Engine.loadTerminalContent();
|
Engine.loadTerminalContent();
|
||||||
@@ -295,14 +298,14 @@ function saveAndCloseScriptEditor() {
|
|||||||
script.saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
script.saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
||||||
s.scripts.push(script);
|
s.scripts.push(script);
|
||||||
} else if (filename.endsWith(".txt")) {
|
} else if (filename.endsWith(".txt")) {
|
||||||
for (var i = 0; i < s.textFiles.length; ++i) {
|
for (let i = 0; i < s.textFiles.length; ++i) {
|
||||||
if (s.textFiles[i].fn === filename) {
|
if (s.textFiles[i].fn === filename) {
|
||||||
s.textFiles[i].write(code);
|
s.textFiles[i].write(code);
|
||||||
Engine.loadTerminalContent();
|
Engine.loadTerminalContent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var textFile = new TextFile(filename, code);
|
const textFile = new TextFile(filename, code);
|
||||||
s.textFiles.push(textFile);
|
s.textFiles.push(textFile);
|
||||||
} else {
|
} else {
|
||||||
dialogBoxCreate("Invalid filename. Must be either a script (.script) or " +
|
dialogBoxCreate("Invalid filename. Must be either a script (.script) or " +
|
||||||
|
|||||||
@@ -314,6 +314,14 @@ class AceEditorWrapper extends ScriptEditor {
|
|||||||
elem.style.display = "none";
|
elem.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCursor() {
|
||||||
|
return this.editor.getCursorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(pos) {
|
||||||
|
this.editor.gotoLine(pos.row+1, pos.column);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AceEditor = new AceEditorWrapper();
|
export const AceEditor = new AceEditorWrapper();
|
||||||
|
|||||||
@@ -570,6 +570,15 @@ class CodeMirrorEditorWrapper extends ScriptEditor {
|
|||||||
elem.style.display = "none";
|
elem.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCursor() {
|
||||||
|
const c = this.editor.getCursor(); //I need to get the cursor position
|
||||||
|
return {row: c.line, column: c.ch};
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(pos) {
|
||||||
|
this.editor.setCursor({line: pos.row, ch: pos.column});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodeMirrorEditor = new CodeMirrorEditorWrapper();
|
export const CodeMirrorEditor = new CodeMirrorEditorWrapper();
|
||||||
|
|||||||
29
src/ScriptEditor/CursorPositions.ts
Normal file
29
src/ScriptEditor/CursorPositions.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
export type Position = {
|
||||||
|
row: number;
|
||||||
|
column: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PositionTracker {
|
||||||
|
positions: Map<string, Position>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.positions = new Map<string, Position>();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveCursor(filename: string, pos: Position) {
|
||||||
|
this.positions.set(filename, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCursor(filename: string): Position {
|
||||||
|
const position = this.positions.get(filename);
|
||||||
|
if (!position) {
|
||||||
|
return {
|
||||||
|
row: 0,
|
||||||
|
column: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CursorPositions: PositionTracker = new PositionTracker();
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { CursorPositions } from './CursorPositions';
|
||||||
|
|
||||||
// Base Script Editor class for the Ace/CodeMirror/etc. wrappers
|
// Base Script Editor class for the Ace/CodeMirror/etc. wrappers
|
||||||
const beautify = require('js-beautify').js_beautify;
|
const beautify = require('js-beautify').js_beautify;
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ export class ScriptEditor {
|
|||||||
if (filename != "") {
|
if (filename != "") {
|
||||||
this.filenameInput.value = filename;
|
this.filenameInput.value = filename;
|
||||||
this.editor.setValue(code);
|
this.editor.setValue(code);
|
||||||
|
this.setCursor(CursorPositions.getCursor(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
min: 1050,
|
min: 1050,
|
||||||
},
|
},
|
||||||
serverGrowth: 99,
|
serverGrowth: 99,
|
||||||
|
specialName: LocationName.AevumECorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 99,
|
hackDifficulty: 99,
|
||||||
@@ -106,6 +107,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
min: 1100,
|
min: 1100,
|
||||||
},
|
},
|
||||||
serverGrowth: 99,
|
serverGrowth: 99,
|
||||||
|
specialName: LocationName.Sector12MegaCorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -128,6 +130,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumBachmanAndAssociates,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -155,6 +158,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 85,
|
max: 85,
|
||||||
min: 55,
|
min: 55,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12BladeIndustries,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 99,
|
hackDifficulty: 99,
|
||||||
@@ -175,6 +179,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 95,
|
max: 95,
|
||||||
min: 65,
|
min: 65,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenNWO,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -201,6 +206,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 75,
|
max: 75,
|
||||||
min: 45,
|
min: 45,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumClarkeIncorporated,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -231,6 +237,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 95,
|
min: 95,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenOmniTekIncorporated,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -253,6 +260,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 75,
|
min: 75,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12FourSigma,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -275,6 +283,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 90,
|
min: 90,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.ChongqingKuaiGongInternational,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -302,6 +311,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 80,
|
min: 80,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumFulcrumTechnologies,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 99,
|
hackDifficulty: 99,
|
||||||
@@ -338,6 +348,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 92,
|
max: 92,
|
||||||
min: 68,
|
min: 68,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.IshimaStormTechnologies,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -360,6 +371,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 73,
|
max: 73,
|
||||||
min: 47,
|
min: 47,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.NewTokyoDefComm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -409,6 +421,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 70,
|
min: 70,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenHeliosLabs,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -436,6 +449,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.NewTokyoVitaLife,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -458,6 +472,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 95,
|
max: 95,
|
||||||
min: 85,
|
min: 85,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12IcarusMicrosystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -484,6 +499,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 90,
|
max: 90,
|
||||||
min: 80,
|
min: 80,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12UniversalEnergy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -586,6 +602,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 90,
|
max: 90,
|
||||||
min: 70,
|
min: 70,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumGalacticCybersystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -609,6 +626,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 65,
|
max: 65,
|
||||||
min: 55,
|
min: 55,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumAeroCorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -636,6 +654,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 70,
|
max: 70,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenOmniaCybersystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -711,6 +730,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 70,
|
min: 70,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.ChongqingSolarisSpaceSystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -733,6 +753,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 70,
|
max: 70,
|
||||||
min: 50,
|
min: 50,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12DeltaOne,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -760,6 +781,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 90,
|
max: 90,
|
||||||
min: 80,
|
min: 80,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.NewTokyoGlobalPharmaceuticals,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -782,6 +804,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 85,
|
max: 85,
|
||||||
min: 65,
|
min: 65,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.IshimaNovaMedical,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -856,6 +879,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 65,
|
max: 65,
|
||||||
min: 55,
|
min: 55,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenLexoCorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -882,6 +906,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 40,
|
min: 40,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumRhoConstruction,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -909,6 +934,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 50,
|
min: 50,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12AlphaEnterprises,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -935,6 +961,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 50,
|
max: 50,
|
||||||
min: 30,
|
min: 30,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumPolice,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -966,6 +993,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 45,
|
max: 45,
|
||||||
min: 35,
|
min: 35,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12RothmanUniversity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -992,6 +1020,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 85,
|
max: 85,
|
||||||
min: 75,
|
min: 75,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenZBInstituteOfTechnology,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1023,6 +1052,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 40,
|
min: 40,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumSummitUniversity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1045,6 +1075,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 70,
|
max: 70,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenSysCoreSecurities,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1121,6 +1152,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 65,
|
max: 65,
|
||||||
min: 45,
|
min: 45,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenCompuTek,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1145,6 +1177,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 75,
|
max: 75,
|
||||||
min: 45,
|
min: 45,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumNetLinkTechnologies,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1179,6 +1212,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
organizationName: LocationName.Sector12FoodNStuff,
|
organizationName: LocationName.Sector12FoodNStuff,
|
||||||
requiredHackingSkill: 1,
|
requiredHackingSkill: 1,
|
||||||
serverGrowth: 5,
|
serverGrowth: 5,
|
||||||
|
specialName: LocationName.Sector12FoodNStuff,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 10,
|
hackDifficulty: 10,
|
||||||
@@ -1198,9 +1232,10 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
moneyAvailable: 2500000,
|
moneyAvailable: 2500000,
|
||||||
networkLayer: 1,
|
networkLayer: 1,
|
||||||
numOpenPortsRequired: 0,
|
numOpenPortsRequired: 0,
|
||||||
organizationName: "Joes Guns",
|
organizationName: LocationName.Sector12JoesGuns,
|
||||||
requiredHackingSkill: 10,
|
requiredHackingSkill: 10,
|
||||||
serverGrowth: 20,
|
serverGrowth: 20,
|
||||||
|
specialName: LocationName.Sector12JoesGuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 25,
|
hackDifficulty: 25,
|
||||||
@@ -1316,6 +1351,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 40,
|
max: 40,
|
||||||
min: 30,
|
min: 30,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.IshimaOmegaSoftware,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1338,6 +1374,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 33,
|
max: 33,
|
||||||
min: 27,
|
min: 27,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumCrushFitnessGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 30,
|
hackDifficulty: 30,
|
||||||
@@ -1349,6 +1386,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
organizationName: "Iron Gym Network",
|
organizationName: "Iron Gym Network",
|
||||||
requiredHackingSkill: 100,
|
requiredHackingSkill: 100,
|
||||||
serverGrowth: 20,
|
serverGrowth: 20,
|
||||||
|
specialName: LocationName.Sector12IronGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1372,6 +1410,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 45,
|
max: 45,
|
||||||
min: 25,
|
min: 25,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenMilleniumFitnessGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1395,6 +1434,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 50,
|
min: 50,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12PowerhouseGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1414,6 +1454,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 40,
|
min: 40,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumSnapFitnessGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 0,
|
hackDifficulty: 0,
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ interface IDefaultSettings {
|
|||||||
*/
|
*/
|
||||||
CodeInstructionRunTime: number;
|
CodeInstructionRunTime: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render city as list of buttons.
|
||||||
|
*/
|
||||||
|
DisableASCIIArt: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether global keyboard shortcuts should be recognized throughout the game.
|
* Whether global keyboard shortcuts should be recognized throughout the game.
|
||||||
*/
|
*/
|
||||||
@@ -101,6 +106,7 @@ interface ISettings extends IDefaultSettings {
|
|||||||
const defaultSettings: IDefaultSettings = {
|
const defaultSettings: IDefaultSettings = {
|
||||||
AutosaveInterval: 60,
|
AutosaveInterval: 60,
|
||||||
CodeInstructionRunTime: 50,
|
CodeInstructionRunTime: 50,
|
||||||
|
DisableASCIIArt: false,
|
||||||
DisableHotkeys: false,
|
DisableHotkeys: false,
|
||||||
Locale: "en",
|
Locale: "en",
|
||||||
MaxLogCapacity: 50,
|
MaxLogCapacity: 50,
|
||||||
@@ -119,6 +125,7 @@ const defaultSettings: IDefaultSettings = {
|
|||||||
export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||||
AutosaveInterval: defaultSettings.AutosaveInterval,
|
AutosaveInterval: defaultSettings.AutosaveInterval,
|
||||||
CodeInstructionRunTime: 25,
|
CodeInstructionRunTime: 25,
|
||||||
|
DisableASCIIArt: defaultSettings.DisableASCIIArt,
|
||||||
DisableHotkeys: defaultSettings.DisableHotkeys,
|
DisableHotkeys: defaultSettings.DisableHotkeys,
|
||||||
Editor: EditorSetting.Ace,
|
Editor: EditorSetting.Ace,
|
||||||
EditorKeybinding: AceKeybindingSetting.Ace,
|
EditorKeybinding: AceKeybindingSetting.Ace,
|
||||||
|
|||||||
491
src/Terminal.jsx
491
src/Terminal.jsx
@@ -60,7 +60,7 @@ import { Player } from "./Player";
|
|||||||
import { hackWorldDaemon } from "./RedPill";
|
import { hackWorldDaemon } from "./RedPill";
|
||||||
import { RunningScript } from "./Script/RunningScript";
|
import { RunningScript } from "./Script/RunningScript";
|
||||||
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
||||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
import { getCurrentEditor, findRunningScript } from "./Script/ScriptHelpers";
|
||||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||||
import { AllServers } from "./Server/AllServers";
|
import { AllServers } from "./Server/AllServers";
|
||||||
import { Server } from "./Server/Server";
|
import { Server } from "./Server/Server";
|
||||||
@@ -108,7 +108,7 @@ import React from "react";
|
|||||||
|
|
||||||
|
|
||||||
function postNetburnerText() {
|
function postNetburnerText() {
|
||||||
post("Bitburner v" + CONSTANTS.Version);
|
post("Bitburner v" + CONSTANTS.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function that checks if an argument (which is a string) is a valid number
|
// Helper function that checks if an argument (which is a string) is a valid number
|
||||||
@@ -123,16 +123,16 @@ function getTerminalInput() {
|
|||||||
|
|
||||||
// Defines key commands in terminal
|
// Defines key commands in terminal
|
||||||
$(document).keydown(function(event) {
|
$(document).keydown(function(event) {
|
||||||
// Terminal
|
// Terminal
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
var terminalInput = document.getElementById("terminal-input-text-box");
|
var terminalInput = document.getElementById("terminal-input-text-box");
|
||||||
if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();}
|
if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();}
|
||||||
|
|
||||||
if (event.keyCode === KEY.ENTER) {
|
if (event.keyCode === KEY.ENTER) {
|
||||||
event.preventDefault(); // Prevent newline from being entered in Script Editor
|
event.preventDefault(); // Prevent newline from being entered in Script Editor
|
||||||
const command = getTerminalInput();
|
const command = getTerminalInput();
|
||||||
const dir = Terminal.currDir;
|
const dir = Terminal.currDir;
|
||||||
post(
|
post(
|
||||||
"<span class='prompt'>[" +
|
"<span class='prompt'>[" +
|
||||||
(FconfSettings.ENABLE_TIMESTAMPS ? getTimestamp() + " " : "") +
|
(FconfSettings.ENABLE_TIMESTAMPS ? getTimestamp() + " " : "") +
|
||||||
Player.getCurrentServer().hostname +
|
Player.getCurrentServer().hostname +
|
||||||
@@ -142,20 +142,20 @@ $(document).keydown(function(event) {
|
|||||||
if (command.length > 0) {
|
if (command.length > 0) {
|
||||||
Terminal.resetTerminalInput(); // Clear input first
|
Terminal.resetTerminalInput(); // Clear input first
|
||||||
Terminal.executeCommands(command);
|
Terminal.executeCommands(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === KEY.C && event.ctrlKey) {
|
if (event.keyCode === KEY.C && event.ctrlKey) {
|
||||||
if (Engine._actionInProgress) {
|
if (Engine._actionInProgress) {
|
||||||
// Cancel action
|
// Cancel action
|
||||||
post("Cancelling...");
|
post("Cancelling...");
|
||||||
Engine._actionInProgress = false;
|
Engine._actionInProgress = false;
|
||||||
Terminal.finishAction(true);
|
Terminal.finishAction(true);
|
||||||
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
|
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
|
||||||
// Dont prevent default so it still copies
|
// Dont prevent default so it still copies
|
||||||
Terminal.resetTerminalInput(); // Clear Terminal
|
Terminal.resetTerminalInput(); // Clear Terminal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === KEY.L && event.ctrlKey) {
|
if (event.keyCode === KEY.L && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -183,7 +183,7 @@ $(document).keydown(function(event) {
|
|||||||
}
|
}
|
||||||
var prevCommand = Terminal.commandHistory[Terminal.commandHistoryIndex];
|
var prevCommand = Terminal.commandHistory[Terminal.commandHistoryIndex];
|
||||||
terminalInput.value = prevCommand;
|
terminalInput.value = prevCommand;
|
||||||
setTimeoutRef(function(){terminalInput.selectionStart = terminalInput.selectionEnd = 10000; }, 0);
|
setTimeoutRef(function(){terminalInput.selectionStart = terminalInput.selectionEnd = 10000; }, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === KEY.DOWNARROW ||
|
if (event.keyCode === KEY.DOWNARROW ||
|
||||||
@@ -295,44 +295,44 @@ $(document).keydown(function(event) {
|
|||||||
// ^k clears line after cursor
|
// ^k clears line after cursor
|
||||||
// ^u clears line before cursor
|
// ^u clears line before cursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Keep terminal in focus
|
// Keep terminal in focus
|
||||||
let terminalCtrlPressed = false, shiftKeyPressed = false;
|
let terminalCtrlPressed = false, shiftKeyPressed = false;
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
$('.terminal-input').focus();
|
$('.terminal-input').focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).keydown(function(e) {
|
$(document).keydown(function(e) {
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
if (e.which == KEY.CTRL) {
|
if (e.which == KEY.CTRL) {
|
||||||
terminalCtrlPressed = true;
|
terminalCtrlPressed = true;
|
||||||
} else if (e.shiftKey) {
|
} else if (e.shiftKey) {
|
||||||
shiftKeyPressed = true;
|
shiftKeyPressed = true;
|
||||||
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
|
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
|
||||||
// Don't focus
|
// Don't focus
|
||||||
} else {
|
} else {
|
||||||
var inputTextBox = document.getElementById("terminal-input-text-box");
|
var inputTextBox = document.getElementById("terminal-input-text-box");
|
||||||
if (inputTextBox != null) {inputTextBox.focus();}
|
if (inputTextBox != null) {inputTextBox.focus();}
|
||||||
|
|
||||||
terminalCtrlPressed = false;
|
terminalCtrlPressed = false;
|
||||||
shiftKeyPressed = false;
|
shiftKeyPressed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).keyup(function(e) {
|
$(document).keyup(function(e) {
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
if (e.which == KEY.CTRL) {
|
if (e.which == KEY.CTRL) {
|
||||||
terminalCtrlPressed = false;
|
terminalCtrlPressed = false;
|
||||||
}
|
}
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
shiftKeyPressed = false;
|
shiftKeyPressed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let Terminal = {
|
let Terminal = {
|
||||||
@@ -361,14 +361,14 @@ let Terminal = {
|
|||||||
if (FconfSettings.WRAP_INPUT) {
|
if (FconfSettings.WRAP_INPUT) {
|
||||||
document.getElementById("terminal-input-td").innerHTML =
|
document.getElementById("terminal-input-td").innerHTML =
|
||||||
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
||||||
`<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\"/>`;
|
`<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\" autocomplete="off" />`;
|
||||||
|
|
||||||
// Auto re-size the line element as it wraps
|
// Auto re-size the line element as it wraps
|
||||||
autosize(document.getElementById("terminal-input-text-box"));
|
autosize(document.getElementById("terminal-input-text-box"));
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("terminal-input-td").innerHTML =
|
document.getElementById("terminal-input-td").innerHTML =
|
||||||
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
||||||
`<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\"/>`;
|
`<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\" autocomplete="off" />`;
|
||||||
}
|
}
|
||||||
const hdr = document.getElementById("terminal-input-header");
|
const hdr = document.getElementById("terminal-input-header");
|
||||||
hdr.style.display = "inline";
|
hdr.style.display = "inline";
|
||||||
@@ -512,16 +512,16 @@ let Terminal = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Complete the hack/analyze command
|
// Complete the hack/analyze command
|
||||||
finishHack: function(cancelled = false) {
|
finishHack: function(cancelled = false) {
|
||||||
if (cancelled == false) {
|
if (cancelled == false) {
|
||||||
var server = Player.getCurrentServer();
|
var server = Player.getCurrentServer();
|
||||||
|
|
||||||
// Calculate whether hack was successful
|
// Calculate whether hack was successful
|
||||||
var hackChance = calculateHackingChance(server, Player);
|
var hackChance = calculateHackingChance(server, Player);
|
||||||
var rand = Math.random();
|
var rand = Math.random();
|
||||||
var expGainedOnSuccess = calculateHackingExpGain(server, Player);
|
var expGainedOnSuccess = calculateHackingExpGain(server, Player);
|
||||||
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
||||||
if (rand < hackChance) { // Success!
|
if (rand < hackChance) { // Success!
|
||||||
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
||||||
if (Player.bitNodeN == null) {
|
if (Player.bitNodeN == null) {
|
||||||
@@ -531,26 +531,26 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
server.manuallyHacked = true;
|
server.manuallyHacked = true;
|
||||||
var moneyGained = calculatePercentMoneyHacked(server, Player);
|
var moneyGained = calculatePercentMoneyHacked(server, Player);
|
||||||
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
||||||
|
|
||||||
if (moneyGained <= 0) {moneyGained = 0;} // Safety check
|
if (moneyGained <= 0) {moneyGained = 0;} // Safety check
|
||||||
|
|
||||||
server.moneyAvailable -= moneyGained;
|
server.moneyAvailable -= moneyGained;
|
||||||
Player.gainMoney(moneyGained);
|
Player.gainMoney(moneyGained);
|
||||||
Player.recordMoneySource(moneyGained, "hacking");
|
Player.recordMoneySource(moneyGained, "hacking");
|
||||||
Player.gainHackingExp(expGainedOnSuccess)
|
Player.gainHackingExp(expGainedOnSuccess)
|
||||||
Player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
|
Player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
|
||||||
|
|
||||||
server.fortify(CONSTANTS.ServerFortifyAmount);
|
server.fortify(CONSTANTS.ServerFortifyAmount);
|
||||||
|
|
||||||
postElement(<>Hack successful! Gained {Money(moneyGained)} and {numeralWrapper.formatExp(expGainedOnSuccess)} hacking exp</>);
|
postElement(<>Hack successful! Gained {Money(moneyGained)} and {numeralWrapper.formatExp(expGainedOnSuccess)} hacking exp</>);
|
||||||
} else { // Failure
|
} else { // Failure
|
||||||
// Player only gains 25% exp for failure? TODO Can change this later to balance
|
// Player only gains 25% exp for failure? TODO Can change this later to balance
|
||||||
Player.gainHackingExp(expGainedOnFailure)
|
Player.gainHackingExp(expGainedOnFailure)
|
||||||
post(`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`);
|
post(`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
||||||
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
||||||
@@ -559,55 +559,55 @@ let Terminal = {
|
|||||||
$('input[class=terminal-input]').prop('disabled', false);
|
$('input[class=terminal-input]').prop('disabled', false);
|
||||||
|
|
||||||
Terminal.hackFlag = false;
|
Terminal.hackFlag = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
finishAnalyze: function(cancelled = false) {
|
finishAnalyze: function(cancelled = false) {
|
||||||
if (cancelled == false) {
|
if (cancelled == false) {
|
||||||
let currServ = Player.getCurrentServer();
|
let currServ = Player.getCurrentServer();
|
||||||
const isHacknet = currServ instanceof HacknetServer;
|
const isHacknet = currServ instanceof HacknetServer;
|
||||||
post(currServ.hostname + ": ");
|
post(currServ.hostname + ": ");
|
||||||
post("Organization name: " + currServ.organizationName);
|
post("Organization name: " + currServ.organizationName);
|
||||||
var rootAccess = "";
|
var rootAccess = "";
|
||||||
if (currServ.hasAdminRights) {rootAccess = "YES";}
|
if (currServ.hasAdminRights) {rootAccess = "YES";}
|
||||||
else {rootAccess = "NO";}
|
else {rootAccess = "NO";}
|
||||||
post("Root Access: " + rootAccess);
|
post("Root Access: " + rootAccess);
|
||||||
if (!isHacknet) { post("Required hacking skill: " + currServ.requiredHackingSkill); }
|
if (!isHacknet) { post("Required hacking skill: " + currServ.requiredHackingSkill); }
|
||||||
post("Server security level: " + numeralWrapper.formatServerSecurity(currServ.hackDifficulty));
|
post("Server security level: " + numeralWrapper.formatServerSecurity(currServ.hackDifficulty));
|
||||||
post("Chance to hack: " + numeralWrapper.formatPercentage(calculateHackingChance(currServ, Player)));
|
post("Chance to hack: " + numeralWrapper.formatPercentage(calculateHackingChance(currServ, Player)));
|
||||||
post("Time to hack: " + convertTimeMsToTimeElapsedString(calculateHackingTime(currServ)*1000));
|
post("Time to hack: " + convertTimeMsToTimeElapsedString(calculateHackingTime(currServ, Player)*1000));
|
||||||
postElement(<>Total money available on server: {Money(currServ.moneyAvailable)}</>);
|
postElement(<>Total money available on server: {Money(currServ.moneyAvailable)}</>);
|
||||||
if (!isHacknet) { post("Required number of open ports for NUKE: " + currServ.numOpenPortsRequired); }
|
if (!isHacknet) { post("Required number of open ports for NUKE: " + currServ.numOpenPortsRequired); }
|
||||||
|
|
||||||
if (currServ.sshPortOpen) {
|
if (currServ.sshPortOpen) {
|
||||||
post("SSH port: Open")
|
post("SSH port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("SSH port: Closed")
|
post("SSH port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.ftpPortOpen) {
|
if (currServ.ftpPortOpen) {
|
||||||
post("FTP port: Open")
|
post("FTP port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("FTP port: Closed")
|
post("FTP port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.smtpPortOpen) {
|
if (currServ.smtpPortOpen) {
|
||||||
post("SMTP port: Open")
|
post("SMTP port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("SMTP port: Closed")
|
post("SMTP port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.httpPortOpen) {
|
if (currServ.httpPortOpen) {
|
||||||
post("HTTP port: Open")
|
post("HTTP port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("HTTP port: Closed")
|
post("HTTP port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.sqlPortOpen) {
|
if (currServ.sqlPortOpen) {
|
||||||
post("SQL port: Open")
|
post("SQL port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("SQL port: Closed")
|
post("SQL port: Closed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Terminal.analyzeFlag = false;
|
Terminal.analyzeFlag = false;
|
||||||
|
|
||||||
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
||||||
@@ -728,7 +728,7 @@ let Terminal = {
|
|||||||
return args;
|
return args;
|
||||||
},
|
},
|
||||||
|
|
||||||
executeCommand : function(command) {
|
executeCommand : function(command) {
|
||||||
if (Terminal.hackFlag || Terminal.analyzeFlag) {
|
if (Terminal.hackFlag || Terminal.analyzeFlag) {
|
||||||
postError(`Cannot execute command (${command}) while an action is in progress`);
|
postError(`Cannot execute command (${command}) while an action is in progress`);
|
||||||
return;
|
return;
|
||||||
@@ -743,8 +743,8 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only split the first space
|
// Only split the first space
|
||||||
var commandArray = Terminal.parseCommandArguments(command);
|
var commandArray = Terminal.parseCommandArguments(command);
|
||||||
if (commandArray.length == 0) { return; }
|
if (commandArray.length == 0) { return; }
|
||||||
|
|
||||||
/****************** Interactive Tutorial Terminal Commands ******************/
|
/****************** Interactive Tutorial Terminal Commands ******************/
|
||||||
if (ITutorial.isRunning) {
|
if (ITutorial.isRunning) {
|
||||||
@@ -820,7 +820,7 @@ let Terminal = {
|
|||||||
Terminal.startHack();
|
Terminal.startHack();
|
||||||
iTutorialNextStep();
|
iTutorialNextStep();
|
||||||
} else {post("Bad command. Please follow the tutorial");}
|
} else {post("Bad command. Please follow the tutorial");}
|
||||||
break;
|
break;
|
||||||
case iTutorialSteps.TerminalCreateScript:
|
case iTutorialSteps.TerminalCreateScript:
|
||||||
if (commandArray.length == 2 &&
|
if (commandArray.length == 2 &&
|
||||||
commandArray[0] == "nano" && commandArray[1] == "foodnstuff.script") {
|
commandArray[0] == "nano" && commandArray[1] == "foodnstuff.script") {
|
||||||
@@ -865,7 +865,7 @@ let Terminal = {
|
|||||||
|
|
||||||
/* Command parser */
|
/* Command parser */
|
||||||
var s = Player.getCurrentServer();
|
var s = Player.getCurrentServer();
|
||||||
switch (commandArray[0].toLowerCase()) {
|
switch (commandArray[0].toLowerCase()) {
|
||||||
case "alias":
|
case "alias":
|
||||||
if (commandArray.length === 1) {
|
if (commandArray.length === 1) {
|
||||||
printAliases();
|
printAliases();
|
||||||
@@ -887,13 +887,13 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
postError('Incorrect usage of alias command. Usage: alias [-g] [aliasname="value"]');
|
postError('Incorrect usage of alias command. Usage: alias [-g] [aliasname="value"]');
|
||||||
break;
|
break;
|
||||||
case "analyze":
|
case "analyze":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
post("Incorrect usage of analyze command. Usage: analyze");
|
post("Incorrect usage of analyze command. Usage: analyze");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Terminal.startAnalyze();
|
Terminal.startAnalyze();
|
||||||
break;
|
break;
|
||||||
case "buy":
|
case "buy":
|
||||||
if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
||||||
executeDarkwebTerminalCommand(commandArray);
|
executeDarkwebTerminalCommand(commandArray);
|
||||||
@@ -908,10 +908,10 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filename = Terminal.getFilepath(commandArray[1]);
|
const filename = Terminal.getFilepath(commandArray[1]);
|
||||||
if (!filename.endsWith(".msg") && !filename.endsWith(".lit") && !filename.endsWith(".txt")) {
|
if (!filename.endsWith(".msg") && !filename.endsWith(".lit") && !filename.endsWith(".txt")) {
|
||||||
postError("Only .msg, .txt, and .lit files are viewable with cat (filename must end with .msg, .txt, or .lit)");
|
postError("Only .msg, .txt, and .lit files are viewable with cat (filename must end with .msg, .txt, or .lit)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename.endsWith(".msg") || filename.endsWith(".lit")) {
|
if (filename.endsWith(".msg") || filename.endsWith(".lit")) {
|
||||||
for (let i = 0; i < s.messages.length; ++i) {
|
for (let i = 0; i < s.messages.length; ++i) {
|
||||||
@@ -996,17 +996,17 @@ let Terminal = {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "clear":
|
case "clear":
|
||||||
case "cls":
|
case "cls":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of clear/cls command. Usage: clear/cls");
|
postError("Incorrect usage of clear/cls command. Usage: clear/cls");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$("#terminal tr:not(:last)").remove();
|
$("#terminal tr:not(:last)").remove();
|
||||||
postNetburnerText();
|
postNetburnerText();
|
||||||
break;
|
break;
|
||||||
case "connect": {
|
case "connect": {
|
||||||
// Disconnect from current server in terminal and connect to new one
|
// Disconnect from current server in terminal and connect to new one
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length !== 2) {
|
||||||
postError("Incorrect usage of connect command. Usage: connect [ip/hostname]");
|
postError("Incorrect usage of connect command. Usage: connect [ip/hostname]");
|
||||||
return;
|
return;
|
||||||
@@ -1022,7 +1022,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
postError("Host not found");
|
postError("Host not found");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "download": {
|
case "download": {
|
||||||
try {
|
try {
|
||||||
@@ -1102,35 +1102,35 @@ let Terminal = {
|
|||||||
post(result);
|
post(result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "free":
|
case "free":
|
||||||
Terminal.executeFreeCommand(commandArray);
|
Terminal.executeFreeCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
case "hack": {
|
case "hack": {
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of hack command. Usage: hack");
|
postError("Incorrect usage of hack command. Usage: hack");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Hack the current PC (usually for money)
|
// Hack the current PC (usually for money)
|
||||||
// You can't hack your home pc or servers you purchased
|
// You can't hack your home pc or servers you purchased
|
||||||
if (s.purchasedByPlayer) {
|
if (s.purchasedByPlayer) {
|
||||||
postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers");
|
postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers");
|
||||||
} else if (s.hasAdminRights == false ) {
|
} else if (s.hasAdminRights == false ) {
|
||||||
postError("You do not have admin rights for this machine! Cannot hack");
|
postError("You do not have admin rights for this machine! Cannot hack");
|
||||||
} else if (s.requiredHackingSkill > Player.hacking_skill) {
|
} else if (s.requiredHackingSkill > Player.hacking_skill) {
|
||||||
postError("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill");
|
postError("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill");
|
||||||
} else if (s instanceof HacknetServer) {
|
} else if (s instanceof HacknetServer) {
|
||||||
postError("Cannot hack this type of Server")
|
postError("Cannot hack this type of Server")
|
||||||
} else {
|
} else {
|
||||||
Terminal.startHack();
|
Terminal.startHack();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "help":
|
case "help":
|
||||||
if (commandArray.length !== 1 && commandArray.length !== 2) {
|
if (commandArray.length !== 1 && commandArray.length !== 2) {
|
||||||
postError("Incorrect usage of help command. Usage: help");
|
postError("Incorrect usage of help command. Usage: help");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (commandArray.length === 1) {
|
if (commandArray.length === 1) {
|
||||||
post(TerminalHelpText);
|
post(TerminalHelpText);
|
||||||
} else {
|
} else {
|
||||||
var cmd = commandArray[1];
|
var cmd = commandArray[1];
|
||||||
@@ -1141,9 +1141,9 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
post(txt);
|
post(txt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "home":
|
case "home":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of home command. Usage: home");
|
postError("Incorrect usage of home command. Usage: home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1153,24 +1153,24 @@ let Terminal = {
|
|||||||
post("Connected to home");
|
post("Connected to home");
|
||||||
Terminal.currDir = "/";
|
Terminal.currDir = "/";
|
||||||
Terminal.resetTerminalInput();
|
Terminal.resetTerminalInput();
|
||||||
break;
|
break;
|
||||||
case "hostname":
|
case "hostname":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of hostname command. Usage: hostname");
|
postError("Incorrect usage of hostname command. Usage: hostname");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
post(Player.getCurrentServer().hostname);
|
post(Player.getCurrentServer().hostname);
|
||||||
break;
|
break;
|
||||||
case "ifconfig":
|
case "ifconfig":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of ifconfig command. Usage: ifconfig");
|
postError("Incorrect usage of ifconfig command. Usage: ifconfig");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
post(Player.getCurrentServer().ip);
|
post(Player.getCurrentServer().ip);
|
||||||
break;
|
break;
|
||||||
case "kill": {
|
case "kill": {
|
||||||
Terminal.executeKillCommand(commandArray);
|
Terminal.executeKillCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "killall": {
|
case "killall": {
|
||||||
for (let i = s.runningScripts.length - 1; i >= 0; --i) {
|
for (let i = s.runningScripts.length - 1; i >= 0; --i) {
|
||||||
@@ -1180,9 +1180,9 @@ let Terminal = {
|
|||||||
post("Killing all running scripts");
|
post("Killing all running scripts");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "ls": {
|
case "ls": {
|
||||||
Terminal.executeListCommand(commandArray);
|
Terminal.executeListCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "lscpu": {
|
case "lscpu": {
|
||||||
post(Player.getCurrentServer().cpuCores + " Core(s)");
|
post(Player.getCurrentServer().cpuCores + " Core(s)");
|
||||||
@@ -1269,25 +1269,25 @@ let Terminal = {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "nano":
|
case "nano":
|
||||||
Terminal.executeNanoCommand(commandArray);
|
Terminal.executeNanoCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
case "ps":
|
case "ps":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of ps command. Usage: ps");
|
postError("Incorrect usage of ps command. Usage: ps");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < s.runningScripts.length; i++) {
|
for (let i = 0; i < s.runningScripts.length; i++) {
|
||||||
let rsObj = s.runningScripts[i];
|
let rsObj = s.runningScripts[i];
|
||||||
let res = `(PID - ${rsObj.pid}) ${rsObj.filename}`;
|
let res = `(PID - ${rsObj.pid}) ${rsObj.filename}`;
|
||||||
for (let j = 0; j < rsObj.args.length; ++j) {
|
for (let j = 0; j < rsObj.args.length; ++j) {
|
||||||
res += (" " + rsObj.args[j].toString());
|
res += (" " + rsObj.args[j].toString());
|
||||||
}
|
}
|
||||||
post(res);
|
post(res);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "rm": {
|
case "rm": {
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length !== 2) {
|
||||||
postError("Incorrect number of arguments. Usage: rm [program/script]");
|
postError("Incorrect number of arguments. Usage: rm [program/script]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1299,14 +1299,14 @@ let Terminal = {
|
|||||||
if (!status.res) {
|
if (!status.res) {
|
||||||
postError(status.msg);
|
postError(status.msg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "run":
|
case "run":
|
||||||
// Run a program or a script
|
// Run a program or a script
|
||||||
if (commandArray.length < 2) {
|
if (commandArray.length < 2) {
|
||||||
postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
|
postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
|
||||||
} else {
|
} else {
|
||||||
var executableName = commandArray[1];
|
var executableName = commandArray[1];
|
||||||
|
|
||||||
// Secret Music player!
|
// Secret Music player!
|
||||||
if (executableName === "musicplayer") {
|
if (executableName === "musicplayer") {
|
||||||
@@ -1314,19 +1314,19 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if its a script or just a program/executable
|
// Check if its a script or just a program/executable
|
||||||
if (isScriptFilename(executableName)) {
|
if (isScriptFilename(executableName)) {
|
||||||
Terminal.runScript(commandArray);
|
Terminal.runScript(commandArray);
|
||||||
} else if (executableName.endsWith(".cct")) {
|
} else if (executableName.endsWith(".cct")) {
|
||||||
Terminal.runContract(executableName);
|
Terminal.runContract(executableName);
|
||||||
} else {
|
} else {
|
||||||
Terminal.runProgram(commandArray);
|
Terminal.runProgram(commandArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "scan":
|
case "scan":
|
||||||
Terminal.executeScanCommand(commandArray);
|
Terminal.executeScanCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
case "scan-analyze":
|
case "scan-analyze":
|
||||||
if (commandArray.length === 1) {
|
if (commandArray.length === 1) {
|
||||||
Terminal.executeScanAnalyzeCommand(1);
|
Terminal.executeScanAnalyzeCommand(1);
|
||||||
@@ -1362,7 +1362,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* eslint-disable no-case-declarations */
|
/* eslint-disable no-case-declarations */
|
||||||
case "scp":
|
case "scp":
|
||||||
Terminal.executeScpCommand(commandArray);
|
Terminal.executeScpCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
/* eslint-enable no-case-declarations */
|
/* eslint-enable no-case-declarations */
|
||||||
@@ -1378,7 +1378,7 @@ let Terminal = {
|
|||||||
post("You do NOT have root access to this machine");
|
post("You do NOT have root access to this machine");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "tail": {
|
case "tail": {
|
||||||
try {
|
try {
|
||||||
if (commandArray.length < 2) {
|
if (commandArray.length < 2) {
|
||||||
postError("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
|
postError("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
|
||||||
@@ -1407,7 +1407,7 @@ let Terminal = {
|
|||||||
Terminal.postThrownError(e);
|
Terminal.postThrownError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "theme": {
|
case "theme": {
|
||||||
let args = commandArray.slice(1);
|
let args = commandArray.slice(1);
|
||||||
@@ -1455,11 +1455,11 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "top": {
|
case "top": {
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of top command. Usage: top");
|
postError("Incorrect usage of top command. Usage: top");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers
|
// Headers
|
||||||
const scriptWidth = 40;
|
const scriptWidth = 40;
|
||||||
@@ -1477,29 +1477,29 @@ let Terminal = {
|
|||||||
|
|
||||||
const headers = `${scriptTxt}${spacesAfterScriptTxt}${pidTxt}${spacesAfterPidTxt}${threadsTxt}${spacesAfterThreadsTxt}${ramTxt}`;
|
const headers = `${scriptTxt}${spacesAfterScriptTxt}${pidTxt}${spacesAfterPidTxt}${threadsTxt}${spacesAfterThreadsTxt}${ramTxt}`;
|
||||||
|
|
||||||
post(headers);
|
post(headers);
|
||||||
|
|
||||||
let currRunningScripts = s.runningScripts;
|
let currRunningScripts = s.runningScripts;
|
||||||
// Iterate through scripts on current server
|
// Iterate through scripts on current server
|
||||||
for (let i = 0; i < currRunningScripts.length; i++) {
|
for (let i = 0; i < currRunningScripts.length; i++) {
|
||||||
let script = currRunningScripts[i];
|
let script = currRunningScripts[i];
|
||||||
|
|
||||||
// Calculate name padding
|
// Calculate name padding
|
||||||
const numSpacesScript = Math.max(0, scriptWidth - script.filename.length);
|
const numSpacesScript = Math.max(0, scriptWidth - script.filename.length);
|
||||||
const spacesScript = " ".repeat(numSpacesScript);
|
const spacesScript = " ".repeat(numSpacesScript);
|
||||||
|
|
||||||
// Calculate PID padding
|
// Calculate PID padding
|
||||||
const numSpacesPid = Math.max(0, pidWidth - (script.pid + "").length);
|
const numSpacesPid = Math.max(0, pidWidth - (script.pid + "").length);
|
||||||
const spacesPid = " ".repeat(numSpacesPid);
|
const spacesPid = " ".repeat(numSpacesPid);
|
||||||
|
|
||||||
// Calculate thread padding
|
// Calculate thread padding
|
||||||
const numSpacesThread = Math.max(0, threadsWidth - (script.threads + "").length);
|
const numSpacesThread = Math.max(0, threadsWidth - (script.threads + "").length);
|
||||||
const spacesThread = " ".repeat(numSpacesThread);
|
const spacesThread = " ".repeat(numSpacesThread);
|
||||||
|
|
||||||
// Calculate and transform RAM usage
|
// Calculate and transform RAM usage
|
||||||
const ramUsage = numeralWrapper.formatRAM(getRamUsageFromRunningScript(script) * script.threads);
|
const ramUsage = numeralWrapper.formatRAM(getRamUsageFromRunningScript(script) * script.threads);
|
||||||
|
|
||||||
const entry = [
|
const entry = [
|
||||||
script.filename,
|
script.filename,
|
||||||
spacesScript,
|
spacesScript,
|
||||||
script.pid,
|
script.pid,
|
||||||
@@ -1508,9 +1508,9 @@ let Terminal = {
|
|||||||
spacesThread,
|
spacesThread,
|
||||||
ramUsage
|
ramUsage
|
||||||
].join("");
|
].join("");
|
||||||
post(entry);
|
post(entry);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "unalias": {
|
case "unalias": {
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length !== 2) {
|
||||||
@@ -1555,10 +1555,10 @@ let Terminal = {
|
|||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
postError(`Command ${commandArray[0]} not found`);
|
postError(`Command ${commandArray[0]} not found`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
connectToServer: function(ip) {
|
connectToServer: function(ip) {
|
||||||
var serv = getServer(ip);
|
var serv = getServer(ip);
|
||||||
@@ -1783,12 +1783,13 @@ let Terminal = {
|
|||||||
const script = Terminal.getScript(filename);
|
const script = Terminal.getScript(filename);
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
let code = ""
|
let code = ""
|
||||||
if(filename.endsWith(".ns")) {
|
if(filename.endsWith(".ns") || filename.endsWith(".js")) {
|
||||||
code = `export async function main(ns) {
|
code = `export async function main(ns) {
|
||||||
|
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
Engine.loadScriptEditorContent(filepath, code);
|
Engine.loadScriptEditorContent(filepath, code);
|
||||||
|
getCurrentEditor().setCursor({row: 1, column: 4});
|
||||||
} else {
|
} else {
|
||||||
Engine.loadScriptEditorContent(filepath, script.code);
|
Engine.loadScriptEditorContent(filepath, script.code);
|
||||||
}
|
}
|
||||||
@@ -2003,24 +2004,24 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// First called when the "run [program]" command is called. Checks to see if you
|
// First called when the "run [program]" command is called. Checks to see if you
|
||||||
// have the executable and, if you do, calls the executeProgram() function
|
// have the executable and, if you do, calls the executeProgram() function
|
||||||
runProgram: function(commandArray) {
|
runProgram: function(commandArray) {
|
||||||
if (commandArray.length < 2) { return; }
|
if (commandArray.length < 2) { return; }
|
||||||
|
|
||||||
// Check if you have the program on your computer. If you do, execute it, otherwise
|
// Check if you have the program on your computer. If you do, execute it, otherwise
|
||||||
// display an error message
|
// display an error message
|
||||||
const programName = commandArray[1];
|
const programName = commandArray[1];
|
||||||
|
|
||||||
if (Player.hasProgram(programName)) {
|
if (Player.hasProgram(programName)) {
|
||||||
Terminal.executeProgram(commandArray);
|
Terminal.executeProgram(commandArray);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)");
|
post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)");
|
||||||
},
|
},
|
||||||
|
|
||||||
// Contains the implementations of all possible programs
|
// Contains the implementations of all possible programs
|
||||||
executeProgram: function(commandArray) {
|
executeProgram: function(commandArray) {
|
||||||
if (commandArray.length < 2) { return; }
|
if (commandArray.length < 2) { return; }
|
||||||
|
|
||||||
var s = Player.getCurrentServer();
|
var s = Player.getCurrentServer();
|
||||||
@@ -2139,23 +2140,11 @@ let Terminal = {
|
|||||||
const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement*30)
|
const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement*30)
|
||||||
const fulfilled = Player.augmentations.length >= numAugReq &&
|
const fulfilled = Player.augmentations.length >= numAugReq &&
|
||||||
Player.money.gt(1e11) &&
|
Player.money.gt(1e11) &&
|
||||||
((Player.hacking_skill >= 2500)||
|
Player.hacking_skill >= 2500;
|
||||||
(Player.strength >= 1500 &&
|
|
||||||
Player.defense >= 1500 &&
|
|
||||||
Player.dexterity >= 1500 &&
|
|
||||||
Player.agility >= 1500));
|
|
||||||
if(!fulfilled) {
|
if(!fulfilled) {
|
||||||
post(`Augmentations: ${Player.augmentations.length} / ${numAugReq}`);
|
post(`Augmentations: ${Player.augmentations.length} / ${numAugReq}`);
|
||||||
|
|
||||||
postElement(<>Money: {Money(Player.money.toNumber())} / {Money(1e11)}</>);
|
postElement(<>Money: {Money(Player.money.toNumber())} / {Money(1e11)}</>);
|
||||||
post("One path below must be fulfilled...");
|
|
||||||
post("----------HACKING PATH----------");
|
|
||||||
post(`Hacking skill: ${Player.hacking_skill} / 2500`);
|
post(`Hacking skill: ${Player.hacking_skill} / 2500`);
|
||||||
post("----------COMBAT PATH----------");
|
|
||||||
post(`Strength: ${Player.strength} / 1500`);
|
|
||||||
post(`Defense: ${Player.defense} / 1500`);
|
|
||||||
post(`Dexterity: ${Player.dexterity} / 1500`);
|
|
||||||
post(`Agility: ${Player.agility} / 1500`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2185,7 +2174,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
programHandlers[programName](s, splitArgs);
|
programHandlers[programName](s, splitArgs);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a filename, returns that file's full path. This takes into account
|
* Given a filename, returns that file's full path. This takes into account
|
||||||
@@ -2283,13 +2272,13 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
runScript: function(commandArray) {
|
runScript: function(commandArray) {
|
||||||
if (commandArray.length < 2) {
|
if (commandArray.length < 2) {
|
||||||
dialogBoxCreate(`Bug encountered with Terminal.runScript(). Command array has a length of less than 2: ${commandArray}`);
|
dialogBoxCreate(`Bug encountered with Terminal.runScript(). Command array has a length of less than 2: ${commandArray}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = Player.getCurrentServer();
|
const server = Player.getCurrentServer();
|
||||||
|
|
||||||
let numThreads = 1;
|
let numThreads = 1;
|
||||||
const args = [];
|
const args = [];
|
||||||
@@ -2319,23 +2308,23 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the script exists and if it does run it
|
// Check if the script exists and if it does run it
|
||||||
for (var i = 0; i < server.scripts.length; i++) {
|
for (var i = 0; i < server.scripts.length; i++) {
|
||||||
if (server.scripts[i].filename === scriptName) {
|
if (server.scripts[i].filename === scriptName) {
|
||||||
// Check for admin rights and that there is enough RAM availble to run
|
// Check for admin rights and that there is enough RAM availble to run
|
||||||
var script = server.scripts[i];
|
var script = server.scripts[i];
|
||||||
var ramUsage = script.ramUsage * numThreads;
|
var ramUsage = script.ramUsage * numThreads;
|
||||||
var ramAvailable = server.maxRam - server.ramUsed;
|
var ramAvailable = server.maxRam - server.ramUsed;
|
||||||
|
|
||||||
if (server.hasAdminRights == false) {
|
if (server.hasAdminRights == false) {
|
||||||
post("Need root access to run script");
|
post("Need root access to run script");
|
||||||
return;
|
return;
|
||||||
} else if (ramUsage > ramAvailable){
|
} else if (ramUsage > ramAvailable){
|
||||||
post("This machine does not have enough RAM to run this script with " +
|
post("This machine does not have enough RAM to run this script with " +
|
||||||
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
|
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Able to run script
|
// Able to run script
|
||||||
var runningScriptObj = new RunningScript(script, args);
|
var runningScriptObj = new RunningScript(script, args);
|
||||||
runningScriptObj.threads = numThreads;
|
runningScriptObj.threads = numThreads;
|
||||||
|
|
||||||
@@ -2345,12 +2334,12 @@ let Terminal = {
|
|||||||
postError(`Failed to start script`);
|
postError(`Failed to start script`);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post("ERROR: No such script");
|
post("ERROR: No such script");
|
||||||
},
|
},
|
||||||
|
|
||||||
runContract: async function(contractName) {
|
runContract: async function(contractName) {
|
||||||
// There's already an opened contract
|
// There's already an opened contract
|
||||||
@@ -2391,4 +2380,4 @@ let Terminal = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export {postNetburnerText, Terminal};
|
export {postNetburnerText, Terminal};
|
||||||
@@ -612,8 +612,7 @@ const Engine = {
|
|||||||
}));
|
}));
|
||||||
Engine.Display.factionsContent.appendChild(createElement("p", {
|
Engine.Display.factionsContent.appendChild(createElement("p", {
|
||||||
width:"70%",
|
width:"70%",
|
||||||
innerText:"Lists factions you have been invited to, as well as " +
|
innerText:"Lists factions you have been invited to. You can accept " +
|
||||||
"factions you have previously rejected. You can accept " +
|
|
||||||
"these faction invitations at any time."
|
"these faction invitations at any time."
|
||||||
}));
|
}));
|
||||||
var invitationsList = createElement("ul");
|
var invitationsList = createElement("ul");
|
||||||
@@ -778,7 +777,7 @@ const Engine = {
|
|||||||
createProgramNotifications: 10,
|
createProgramNotifications: 10,
|
||||||
augmentationsNotifications: 10,
|
augmentationsNotifications: 10,
|
||||||
checkFactionInvitations: 100,
|
checkFactionInvitations: 100,
|
||||||
passiveFactionGrowth: 600,
|
passiveFactionGrowth: 5,
|
||||||
messages: 150,
|
messages: 150,
|
||||||
mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
|
mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
|
||||||
contractGeneration: 3000, // Generate Coding Contracts
|
contractGeneration: 3000, // Generate Coding Contracts
|
||||||
@@ -912,9 +911,9 @@ const Engine = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Engine.Counters.passiveFactionGrowth <= 0) {
|
if (Engine.Counters.passiveFactionGrowth <= 0) {
|
||||||
var adjustedCycles = Math.floor((600 - Engine.Counters.passiveFactionGrowth));
|
var adjustedCycles = Math.floor((5 - Engine.Counters.passiveFactionGrowth));
|
||||||
processPassiveFactionRepGain(adjustedCycles);
|
processPassiveFactionRepGain(adjustedCycles);
|
||||||
Engine.Counters.passiveFactionGrowth = 600;
|
Engine.Counters.passiveFactionGrowth = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Engine.Counters.messages <= 0) {
|
if (Engine.Counters.messages <= 0) {
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<table id="terminal">
|
<table id="terminal">
|
||||||
<tr id="terminal-input">
|
<tr id="terminal-input">
|
||||||
<td id="terminal-input-td" tabindex="2">$
|
<td id="terminal-input-td" tabindex="2">$
|
||||||
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" />
|
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -274,16 +274,16 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<div id="infiltration-left-panel">
|
<div id="infiltration-left-panel">
|
||||||
<p id="infiltration-level-text"> </p>
|
<p id="infiltration-level-text"> </p>
|
||||||
<div id="infiltration-buttons">
|
<div id="infiltration-buttons">
|
||||||
<a class="a-link-button tooltip" id="infiltration-kill"> </a>
|
<button class="a-link-button tooltip" id="infiltration-kill"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-knockout"> </a>
|
<button class="a-link-button tooltip" id="infiltration-knockout"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-stealthknockout"> </a>
|
<button class="a-link-button tooltip" id="infiltration-stealthknockout"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-assassinate"> </a>
|
<button class="a-link-button tooltip" id="infiltration-assassinate"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-hacksecurity"> </a>
|
<button class="a-link-button tooltip" id="infiltration-hacksecurity"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-destroysecurity"> </a>
|
<button class="a-link-button tooltip" id="infiltration-destroysecurity"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-sneak"> </a>
|
<button class="a-link-button tooltip" id="infiltration-sneak"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-pickdoor"> </a>
|
<button class="a-link-button tooltip" id="infiltration-pickdoor"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-bribe"> </a>
|
<button class="a-link-button tooltip" id="infiltration-bribe"> </button>
|
||||||
<a class="a-link-button tooltip" id="infiltration-escape"> </a>
|
<button class="a-link-button tooltip" id="infiltration-escape"> </button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="infiltration-right-panel">
|
<div id="infiltration-right-panel">
|
||||||
@@ -394,13 +394,13 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
|
|
||||||
<!-- Status text -->
|
<!-- Status text -->
|
||||||
<div id="status-text-container">
|
<div id="status-text-container">
|
||||||
<p id="status-text"> </p>
|
<p id="status-text"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Game Options -->
|
<!-- Game Options -->
|
||||||
<div id="game-options-container" class="popup-box-container">
|
<div id="game-options-container" class="popup-box-container">
|
||||||
<div id="game-options-content" class="game-options-box">
|
<div id="game-options-content" class="game-options-box">
|
||||||
<button id="game-options-close-button">×</button>
|
<button id="game-options-close-button" aria-label="close options dialog">×</button>
|
||||||
<h1> Game Options </h1>
|
<h1> Game Options </h1>
|
||||||
<br />
|
<br />
|
||||||
<div id="game-options-left-panel">
|
<div id="game-options-left-panel">
|
||||||
@@ -524,6 +524,16 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- View city as list of buttons instead of ASCII art. -->
|
||||||
|
<fieldset>
|
||||||
|
<label for="settingsDisableASCIIArt" class="tooltip">Disable ASCII art:
|
||||||
|
<span class="tooltiptexthigh">
|
||||||
|
If this is set all ASCII art will be disabled.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<!-- Locale for displaying numbers -->
|
<!-- Locale for displaying numbers -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="settingsLocale" class="tooltip">Locale:
|
<label for="settingsLocale" class="tooltip">Locale:
|
||||||
@@ -562,6 +572,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<div id="game-options-right-panel">
|
<div id="game-options-right-panel">
|
||||||
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> Changelog </a>
|
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> Changelog </a>
|
||||||
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a>
|
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a>
|
||||||
|
<a class="a-link-button" href="https://discord.gg/TFc3hKD" target="_blank">Discord</a>
|
||||||
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
|
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
|
||||||
<button id="save-game-link" class="a-link-button"> Save Game </button>
|
<button id="save-game-link" class="a-link-button"> Save Game </button>
|
||||||
<button id="delete-game-link" class="a-link-button"> Delete Game </button>
|
<button id="delete-game-link" class="a-link-button"> Delete Game </button>
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
function Hacknet(): React.ReactElement {
|
function Hacknet(): React.ReactElement {
|
||||||
// Can't import HacknetHelpers for some reason.
|
// Can't import HacknetHelpers for some reason.
|
||||||
if(!(p.bitNodeN === 9 || SourceFileFlags[9] > 0)) {
|
if(!(p.bitNodeN === 9 || SourceFileFlags[9] > 0)) {
|
||||||
return <><span>Hacknet Nodes owned: {p.hacknetNodes.length}</span><br /></>
|
return <><span>{`Hacknet Nodes owned: ${p.hacknetNodes.length}`}</span><br /></>
|
||||||
} else {
|
} else {
|
||||||
return <><span>Hacknet Servers owned: {p.hacknetNodes.length} / {HacknetServerConstants.MaxServers}</span><br /></>
|
return <><span>{`Hacknet Servers owned: ${p.hacknetNodes.length} / ${HacknetServerConstants.MaxServers}`}</span><br /></>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +51,7 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
if (src.bladeburner) { parts.push([`Bladeburner:`, Money(src.bladeburner)]) };
|
if (src.bladeburner) { parts.push([`Bladeburner:`, Money(src.bladeburner)]) };
|
||||||
if (src.codingcontract) { parts.push([`Coding Contracts:`, Money(src.codingcontract)]) };
|
if (src.codingcontract) { parts.push([`Coding Contracts:`, Money(src.codingcontract)]) };
|
||||||
if (src.work) { parts.push([`Company Work:`, Money(src.work)]) };
|
if (src.work) { parts.push([`Company Work:`, Money(src.work)]) };
|
||||||
|
if (src.class) { parts.push([`Class:`, Money(src.class)]) };
|
||||||
if (src.corporation) { parts.push([`Corporation:`, Money(src.corporation)]) };
|
if (src.corporation) { parts.push([`Corporation:`, Money(src.corporation)]) };
|
||||||
if (src.crime) { parts.push([`Crimes:`, Money(src.crime)]) };
|
if (src.crime) { parts.push([`Crimes:`, Money(src.crime)]) };
|
||||||
if (src.gang) { parts.push([`Gang:`, Money(src.gang)]) };
|
if (src.gang) { parts.push([`Gang:`, Money(src.gang)]) };
|
||||||
@@ -59,6 +60,7 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
if (src.hospitalization) { parts.push([`Hospitalization:`, Money(src.hospitalization)]) };
|
if (src.hospitalization) { parts.push([`Hospitalization:`, Money(src.hospitalization)]) };
|
||||||
if (src.infiltration) { parts.push([`Infiltration:`, Money(src.infiltration)]) };
|
if (src.infiltration) { parts.push([`Infiltration:`, Money(src.infiltration)]) };
|
||||||
if (src.stock) { parts.push([`Stock Market:`, Money(src.stock)]) };
|
if (src.stock) { parts.push([`Stock Market:`, Money(src.stock)]) };
|
||||||
|
if (src.casino) { parts.push([`Casino:`, Money(src.casino)]) };
|
||||||
|
|
||||||
return StatsTable(parts, "");
|
return StatsTable(parts, "");
|
||||||
}
|
}
|
||||||
@@ -97,8 +99,8 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{props.rows.map((r: any) => <tr key={r[0]}>
|
{props.rows.map((r: any) => <tr key={r[0]}>
|
||||||
<td key='0'>{r[0]} multiplier: </td>
|
<td key='0'>{`${r[0]} multiplier:`}</td>
|
||||||
<td key='1' style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
|
<td key='1' style={{textAlign: 'right', paddingLeft: '5px'}}>{numeralWrapper.formatPercentage(r[1])}</td>
|
||||||
{bn5Stat(r)}
|
{bn5Stat(r)}
|
||||||
</tr>)}
|
</tr>)}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -234,9 +236,9 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
]} /><br /><br />
|
]} /><br /><br />
|
||||||
|
|
||||||
<b>Misc.</b><br /><br />
|
<b>Misc.</b><br /><br />
|
||||||
<span>Servers owned: {p.purchasedServers.length} / {getPurchaseServerLimit()}</span><br />
|
<span>{`Servers owned: ${p.purchasedServers.length} / ${getPurchaseServerLimit()}`}</span><br />
|
||||||
<Hacknet />
|
<Hacknet />
|
||||||
<span>Augmentations installed: {p.augmentations.length}</span><br /><br />
|
<span>{`Augmentations installed: ${p.augmentations.length}`}</span><br /><br />
|
||||||
{StatsTable(timeRows, null)}
|
{StatsTable(timeRows, null)}
|
||||||
<br />
|
<br />
|
||||||
<CurrentBitNode />
|
<CurrentBitNode />
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class CharacterOverviewComponent extends Component {
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr id="character-hp-wrapper">
|
<tr id="character-hp-wrapper">
|
||||||
<td className="character-hp-cell">Hp:</td><td id="character-hp-text" className="character-hp-cell character-stat-cell">{Player.hp + " / " + Player.max_hp}</td>
|
<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>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="character-money-wrapper">
|
<tr id="character-money-wrapper">
|
||||||
<td className="character-money-cell">Money: </td><td id="character-money-text" className="character-money-cell character-stat-cell">{numeralWrapper.formatMoney(Player.money.toNumber())}</td>
|
<td className="character-money-cell">Money: </td><td id="character-money-text" className="character-money-cell character-stat-cell">{numeralWrapper.formatMoney(Player.money.toNumber())}</td>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class NumeralFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatHp(n: number): string {
|
formatHp(n: number): string {
|
||||||
return this.format(n, "0.0");
|
return this.format(n, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
formatMoney(n: number): string {
|
formatMoney(n: number): string {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ function setSettingsLabels() {
|
|||||||
const suppressHospitalizationPopup = document.getElementById("settingsSuppressHospitalizationPopup");
|
const suppressHospitalizationPopup = document.getElementById("settingsSuppressHospitalizationPopup");
|
||||||
const autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel");
|
const autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel");
|
||||||
const disableHotkeys = document.getElementById("settingsDisableHotkeys");
|
const disableHotkeys = document.getElementById("settingsDisableHotkeys");
|
||||||
|
const disableASCIIArt = document.getElementById("settingsDisableASCIIArt");
|
||||||
const locale = document.getElementById("settingsLocale");
|
const locale = document.getElementById("settingsLocale");
|
||||||
|
|
||||||
//Initialize values on labels
|
//Initialize values on labels
|
||||||
@@ -36,6 +37,7 @@ function setSettingsLabels() {
|
|||||||
suppressHospitalizationPopup.checked = Settings.SuppressHospitalizationPopup;
|
suppressHospitalizationPopup.checked = Settings.SuppressHospitalizationPopup;
|
||||||
setAutosaveLabel(autosaveInterval);
|
setAutosaveLabel(autosaveInterval);
|
||||||
disableHotkeys.checked = Settings.DisableHotkeys;
|
disableHotkeys.checked = Settings.DisableHotkeys;
|
||||||
|
disableASCIIArt.checked = Settings.CityListView;
|
||||||
locale.value = Settings.Locale;
|
locale.value = Settings.Locale;
|
||||||
numeralWrapper.updateLocale(Settings.Locale); //Initialize locale
|
numeralWrapper.updateLocale(Settings.Locale); //Initialize locale
|
||||||
|
|
||||||
@@ -99,6 +101,10 @@ function setSettingsLabels() {
|
|||||||
Settings.DisableHotkeys = this.checked;
|
Settings.DisableHotkeys = this.checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableASCIIArt.onclick = function() {
|
||||||
|
Settings.DisableASCIIArt = this.checked;
|
||||||
|
}
|
||||||
|
|
||||||
//Locale selector
|
//Locale selector
|
||||||
locale.onchange = function() {
|
locale.onchange = function() {
|
||||||
if (!numeralWrapper.updateLocale(locale.value)) {
|
if (!numeralWrapper.updateLocale(locale.value)) {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export class MoneySourceTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bladeburner: number = 0;
|
bladeburner: number = 0;
|
||||||
|
casino: number = 0;
|
||||||
|
class: number = 0;
|
||||||
codingcontract: number = 0;
|
codingcontract: number = 0;
|
||||||
corporation: number = 0;
|
corporation: number = 0;
|
||||||
crime: number = 0;
|
crime: number = 0;
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export function yesNoBoxCreate(txt: string | JSX.Element) {
|
|||||||
yesNoBoxOpen = true;
|
yesNoBoxOpen = true;
|
||||||
|
|
||||||
if (yesNoBoxTextElement) {
|
if (yesNoBoxTextElement) {
|
||||||
|
ReactDOM.unmountComponentAtNode(yesNoBoxTextElement);
|
||||||
|
yesNoBoxTextElement.innerHTML = '';
|
||||||
if(typeof txt === 'string') {
|
if(typeof txt === 'string') {
|
||||||
yesNoBoxTextElement.innerHTML = txt as string;
|
yesNoBoxTextElement.innerHTML = txt as string;
|
||||||
} else {
|
} else {
|
||||||
@@ -134,7 +136,10 @@ export function yesNoTxtInpBoxGetInput(): string {
|
|||||||
export function yesNoTxtInpBoxCreate(txt: string | JSX.Element) {
|
export function yesNoTxtInpBoxCreate(txt: string | JSX.Element) {
|
||||||
yesNoBoxOpen = true;
|
yesNoBoxOpen = true;
|
||||||
|
|
||||||
|
|
||||||
if (yesNoTextInputBoxTextElement) {
|
if (yesNoTextInputBoxTextElement) {
|
||||||
|
ReactDOM.unmountComponentAtNode(yesNoTextInputBoxTextElement);
|
||||||
|
yesNoTextInputBoxTextElement.innerHTML = '';
|
||||||
if(typeof txt === 'string') {
|
if(typeof txt === 'string') {
|
||||||
yesNoTextInputBoxTextElement.innerHTML = txt;
|
yesNoTextInputBoxTextElement.innerHTML = txt;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user