mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 14:28:36 +02:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87c63cde59 | ||
|
|
83137a2364 | ||
|
|
78d9c25671 | ||
|
|
56c8a23631 | ||
|
|
1d4cf45a92 | ||
|
|
b1e37acaa1 | ||
|
|
65ee49fb92 | ||
|
|
6a795a7c50 | ||
|
|
ae33a23db4 | ||
|
|
faad0ae8a7 | ||
|
|
1ff7f4bcd4 | ||
|
|
1335ca8e01 | ||
|
|
8e07cc999d | ||
|
|
06775b20fa | ||
|
|
30554560da | ||
|
|
ac3a6b9a6f | ||
|
|
b126bd01ee | ||
|
|
8f13363466 | ||
|
|
828c9c2de6 | ||
|
|
dd61fd6efb | ||
|
|
383b02fdbb | ||
|
|
010f43e5d4 | ||
|
|
3d36982a56 | ||
|
|
3fd26bea9b | ||
|
|
41de3102c7 | ||
|
|
e9ba4ae9a2 | ||
|
|
12b192ab43 | ||
|
|
cdbbc657e2 | ||
|
|
995a0b11d9 | ||
|
|
06df10d2f9 | ||
|
|
01d15176ac | ||
|
|
f9afff57b2 | ||
|
|
2bf47c60df | ||
|
|
783750051e | ||
|
|
752534bc4d | ||
|
|
3346f3539c | ||
|
|
0aa26df9d7 | ||
|
|
bbf3a1d19a | ||
|
|
a2599f19d7 | ||
|
|
8e4722c5e7 | ||
|
|
e91c183d37 | ||
|
|
2ed29e10b3 | ||
|
|
effa9f15af | ||
|
|
4355420349 | ||
|
|
35ebb06761 | ||
|
|
5d21bd7840 | ||
|
|
815b04037c | ||
|
|
3cd0ae51e7 | ||
|
|
ed57a8c4f4 | ||
|
|
0f7ad063ca | ||
|
|
809f9117b8 | ||
|
|
38e165100f | ||
|
|
f4ecbd9b48 | ||
|
|
7db1164a1a | ||
|
|
3ca7c49ce8 | ||
|
|
528a8f30db | ||
|
|
500063e87e | ||
|
|
ec3037f8c6 | ||
|
|
8d7f0488f8 | ||
|
|
7d0536a4d2 | ||
|
|
2958034ad4 | ||
|
|
a7dfb1a537 | ||
|
|
be29481689 | ||
|
|
1d488565c6 | ||
|
|
42890843fb | ||
|
|
c06aff3437 | ||
|
|
62bdfb1875 | ||
|
|
123f071c12 | ||
|
|
0edd4ffdf1 | ||
|
|
8e5c10cc2f | ||
|
|
15a03dd532 | ||
|
|
8e58482db0 | ||
|
|
b1d1de9118 | ||
|
|
83a84c6d38 | ||
|
|
75a2742911 | ||
|
|
a420a87eba | ||
|
|
f579ee398b | ||
|
|
4901c84d34 | ||
|
|
227fbd7060 | ||
|
|
70796e7674 | ||
|
|
da746a63c3 | ||
|
|
2f677c7ec8 | ||
|
|
c5e29dafc4 | ||
|
|
bb0bdb776b | ||
|
|
48b839d68c | ||
|
|
c47a5bc8cc | ||
|
|
33ea31be87 | ||
|
|
27fc90c87a | ||
|
|
d58e2df9c7 | ||
|
|
c989e6713f | ||
|
|
880654c222 | ||
|
|
4fc6d393e4 | ||
|
|
d21382e96e | ||
|
|
81fd2c1236 | ||
|
|
bdb10217db | ||
|
|
ab2ffb112f | ||
|
|
7304e5379f | ||
|
|
ee0532eba7 | ||
|
|
1a749505e7 | ||
|
|
fae6e6d22f | ||
|
|
826357e8b8 | ||
|
|
94550dbaee | ||
|
|
83c159e901 | ||
|
|
3f5b412547 | ||
|
|
1fdb5c33c7 | ||
|
|
665d25650a | ||
|
|
447731c5f3 | ||
|
|
cc02701e97 | ||
|
|
793d9b34ce |
@@ -99,7 +99,6 @@ module.exports = {
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-cond-assign": ["off", "except-parens"],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["off"],
|
||||
"no-const-assign": ["error"],
|
||||
|
||||
@@ -84,6 +84,28 @@ changes are okay to contribute:
|
||||
- Changes that directly affect the game's balance
|
||||
- New gameplay mechanics
|
||||
|
||||
### How to setup fork properly
|
||||
|
||||
Fork and clone the repo
|
||||
|
||||
```
|
||||
# This will add the game original code as a repo in your local copy
|
||||
$ git remote add danielyxie git@github.com:danielyxie/bitburner.git
|
||||
|
||||
# You can verify you did this right by doing the following command
|
||||
$ git remote show
|
||||
danielyxie
|
||||
origin
|
||||
|
||||
# Then download all the branches from the game. (there might be more branches)
|
||||
$ git fetch danielyxie
|
||||
From github.com:danielyxie/bitburner
|
||||
* [new branch] dev -> danielyxie/dev
|
||||
* [new branch] master -> danielyxie/master
|
||||
|
||||
# Makes sure you always start from `danielyxie/dev` to avoid merge conflicts.
|
||||
```
|
||||
|
||||
#### Submitting a Pull Request
|
||||
|
||||
When submitting a pull request with your code contributions, please abide by
|
||||
|
||||
23
css/staneksgift.scss
Normal file
23
css/staneksgift.scss
Normal file
@@ -0,0 +1,23 @@
|
||||
.staneksgift_row {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.staneksgift_cell {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
background-color: #808080;
|
||||
font-color: white;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
border: 1px solid black;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.staneksgift_cell:first-child {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
.staneksgift_container {
|
||||
position: fixed;
|
||||
}
|
||||
98
dist/vendor.bundle.js
vendored
98
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
.. _gameplay_sourcefiles:
|
||||
|
||||
.. warning:: This page contains spoilers regarding the game's story/plot-line.
|
||||
.. warning:: This page contains spoilers for the game
|
||||
|
||||
Source-Files
|
||||
============
|
||||
|
||||
@@ -3,6 +3,109 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.56.0 - 2021-10-11 Trimming the backlog (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
** BREAKING **
|
||||
|
||||
* The 'write' function is now async. This helps when making scripts that write scripts.
|
||||
|
||||
** Terminal **
|
||||
|
||||
* 'grow' and 'weaken' have been added as terminal command. This should help player transition
|
||||
from commands to scripts. The tutorial also talks about it.
|
||||
* 'cp' command added
|
||||
* Improved performance by rate limiting refresh.
|
||||
|
||||
** IP vs Hostname **
|
||||
|
||||
* The game now uses hostname as primary key for it's servers (yeah believe it or not IPs were
|
||||
used until then). This has caused some issues with purchased servers (they couldn't be sold).
|
||||
You might need to soft reset for the game to fully convert itself.
|
||||
|
||||
** Sleeve **
|
||||
|
||||
* Fixed bug where they couldn't train at Volhaven.
|
||||
* No longer consume all bonus time at once, making it look buggy.
|
||||
|
||||
** SF9 **
|
||||
|
||||
* Now boosts hacknet production by 8/12/14%
|
||||
|
||||
** Hacknet Servers **
|
||||
|
||||
* production nerfed by 10%
|
||||
* Max money increase gets weaker above 10t max money
|
||||
|
||||
** Corporation **
|
||||
|
||||
* Warehouse tooltip now also displays the amount of space taken by products.
|
||||
* Changed research box completely to avoid dependency on Treant (Treant is a pita)
|
||||
* All textbox should accept MAX/MP case insensitive.
|
||||
* Fixed export popup not refreshing dropdowns correctly.
|
||||
* Fixed product mku becoming zero
|
||||
* Increased scaling of Wilson to avoid feedback loop.
|
||||
* Can no longer get in debt by buying real estate
|
||||
* Bonus time is consumed faster.
|
||||
|
||||
** Netscript **
|
||||
|
||||
* isBusy takes bitverse and infiltration into account
|
||||
* hospitalize can't be called when in infiltration.
|
||||
* setToCommitCrime now accepts crime rough name instead of perfect name.
|
||||
* disableLog All now works for bladeburner functions.
|
||||
* Fixed netscript port for ns1.
|
||||
|
||||
** Augmentation **
|
||||
|
||||
* Added augmentation to Ti Di Hui that removes penalty for being unfocused.
|
||||
* Neuroflux no longer appears in special factions.
|
||||
|
||||
** Script Editor **
|
||||
|
||||
* Ram check is debounced instead of refreshed every second.
|
||||
* Added the vscode extension documentation to the game (it doesn't work well, thought)
|
||||
* Fixed issue where autocomplete list would grow forever
|
||||
* Added semi-monokai as theme.
|
||||
* Fixed issue where modifying filename would mess it up.
|
||||
* Font size can be changed now.
|
||||
|
||||
** Infiltration **
|
||||
|
||||
* Fixed issue where game controls would become unfocused.
|
||||
|
||||
** Misc. **
|
||||
|
||||
* Fixed loader incorrectly assuming some null values are incorrect.
|
||||
* installBackdoor trigger Bitverse sequence
|
||||
* Some improvements to the theme editor
|
||||
* Improved documentation about where to learn javascript.
|
||||
* Added some instructions for contributors.
|
||||
* Fixed typo in corporation sell shares modal (@Saynt_Garmo)
|
||||
* Fixed pagination being black on black in Active Scripts
|
||||
* Create Script tab renamed to Script Editor
|
||||
* Fixed an issue where corp some textbox wouldn't update when changing city.
|
||||
* Fixed an issue where hacknet online time was always 0.
|
||||
* Netscript function prompt fixed.
|
||||
* Fixed miscalculation in growth.
|
||||
* Script with syntax errors will try to be a tad more helpful.
|
||||
* Corporations can no longer bribe bladeburners.
|
||||
* Augmentation Graphene Branchiblade renamed to Brachi, like the rest of them.
|
||||
* All ram is displayed in GB/TB/PB now.
|
||||
* Game now saves when saving a file, this can be turned off.
|
||||
* Several improvement to log window.
|
||||
* Bladeburner current action returns General type instead of the name of the action.
|
||||
* Bladeburner travel and Sleeve travel respect disable ASCII.
|
||||
* Tutorial fits on small screens.
|
||||
* Import is much slower but more consistent now.
|
||||
* Fix intelligence not updating properly.
|
||||
* Added SF -1: Time Compression
|
||||
* ReadTheDoc theme now matches the game.
|
||||
* Logbox should wrap text better
|
||||
* Logbox behavior should feel better.
|
||||
* Fix font for AutoLink.exe
|
||||
* nerf noodle bar
|
||||
|
||||
v0.55.0 - 2021-09-20 Material UI (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
|
||||
@@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.55'
|
||||
version = '0.56'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.55.0'
|
||||
release = '0.56.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -189,3 +189,4 @@ intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
def setup(app):
|
||||
print("Initializing (setup())");
|
||||
app.add_stylesheet('maxwidthoverride.css')
|
||||
app.add_stylesheet('dark_theme.css')
|
||||
|
||||
@@ -30,5 +30,6 @@ to reach out to the developer!
|
||||
Gang API <netscript/netscriptgangapi>
|
||||
Coding Contract API <netscript/netscriptcodingcontractapi>
|
||||
Sleeve API <netscript/netscriptsleeveapi>
|
||||
Stanek API <netscript/netscriptstanekapi>
|
||||
Formulas API <netscript/netscriptformulasapi>
|
||||
Miscellaneous <netscript/netscriptmisc>
|
||||
|
||||
@@ -6,8 +6,6 @@ getServer() Netscript Function
|
||||
:RAM cost: 2 GB
|
||||
:param string hostname: Hostname of the server, defaults to host server.
|
||||
|
||||
If you are not in BitNode-5, then you must have Source-File 5-1 in order to run this function.
|
||||
|
||||
This function is meant to be used in conjunction with the :doc:`formulas API<../netscriptformulasapi>`.
|
||||
|
||||
Returns an object with the Server's stats. The object has the following properties::
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
growthAnalyze() Netscript Function
|
||||
==================================
|
||||
|
||||
.. js:function:: growthAnalyze(hostname, growthAmount)
|
||||
.. js:function:: growthAnalyze(hostname, growthAmount[, cores])
|
||||
|
||||
:RAM cost: 1 GB
|
||||
:param string hostname: Hostname of server to analyze.
|
||||
:param number growthAmount: Multiplicative factor by which the server is
|
||||
grown. Decimal form. Must be >= 1.
|
||||
:param number cores: Amount of cores on the server that would run the growth, defaults to 1
|
||||
:returns: The amount of :doc:`grow<grow>` threads needed to grow the specified
|
||||
server by the specified amount.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ help you learn some basic programming concepts.
|
||||
Here are some good tutorials for learning programming/JavaScript as a beginner:
|
||||
|
||||
* `Learn-JS <http://www.learn-js.org/en/Welcome>`_
|
||||
* `programiz <https://www.programiz.com/javascript/get-started>`_
|
||||
* `Speaking JavaScript <http://speakingjs.com/es5/index.html>`_
|
||||
This is a bit on the longer side. You can skip all of the historical
|
||||
background stuff. Recommended chapters: 1, 7-18
|
||||
|
||||
20
doc/source/netscript/netscriptstanekapi.rst
Normal file
20
doc/source/netscript/netscriptstanekapi.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
.. _netscriptstanek:
|
||||
|
||||
Netscript Stanek Functions
|
||||
============================
|
||||
|
||||
.. warning:: This page contains spoilers for the game.
|
||||
|
||||
The Stanek API allow you to control Stanek's Gift.
|
||||
|
||||
All these function require Source-File 13-1 or to be in BitNode 13.
|
||||
|
||||
.. toctree::
|
||||
charge() <stanekapi/charge>
|
||||
fragmentDefinitions() <stanekapi/fragmentDefinitions>
|
||||
placedFragments() <stanekapi/placedFragments>
|
||||
clear() <stanekapi/clear>
|
||||
canPlace() <stanekapi/canPlace>
|
||||
place() <stanekapi/place>
|
||||
fragmentAt() <stanekapi/fragmentAt>
|
||||
deleteAt() <stanekapi/deleteAt>
|
||||
15
doc/source/netscript/stanekapi/canPlace.rst
Normal file
15
doc/source/netscript/stanekapi/canPlace.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
canPlace() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: canPlace(worldX, worldY, fragmentId)
|
||||
|
||||
:RAM cost: 0.5 GB
|
||||
:param int worldX: World X against which to align the top left of the fragment.
|
||||
:param int worldY: World Y against which to align the top left of the fragment.
|
||||
:param int fragmentId: ID of the fragment to place.
|
||||
:returns: `true` if the fragment can be placed at that position. `false` otherwise.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
canPlace(0, 4, 17); // returns true
|
||||
21
doc/source/netscript/stanekapi/charge.rst
Normal file
21
doc/source/netscript/stanekapi/charge.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
charge() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: charge(worldX, worldY)
|
||||
|
||||
:RAM cost: 0.4 GB
|
||||
:param int worldX: World X of the fragment to charge.
|
||||
:param int worldY: World Y of the fragment to charge.
|
||||
|
||||
Charge a fragment, increasing it's power but also it's heat. The
|
||||
effectiveness of the charge depends on the amount of ram the running script
|
||||
consumes as well as the fragments current heat. This operation takes time to
|
||||
complete.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
charge(0, 4); // Finishes 5 seconds later.
|
||||
.. warning::
|
||||
|
||||
Netscript JS users: This function is `async`
|
||||
13
doc/source/netscript/stanekapi/clear.rst
Normal file
13
doc/source/netscript/stanekapi/clear.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
clear() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: clear()
|
||||
|
||||
:RAM cost: 0 GB
|
||||
|
||||
Completely clear Stanek's Gift.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
clear(); // No more fragments.
|
||||
16
doc/source/netscript/stanekapi/deleteAt.rst
Normal file
16
doc/source/netscript/stanekapi/deleteAt.rst
Normal file
@@ -0,0 +1,16 @@
|
||||
deleteAt() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: deleteAt(worldX, worldY)
|
||||
|
||||
:RAM cost: 0.15 GB
|
||||
:param int worldX: World X coordinate of the fragment to delete.
|
||||
:param int worldY: World Y coordinate of the fragment to delete.
|
||||
:returns: `true` if the fragment was deleted. `false` otherwise.
|
||||
|
||||
Delete the fragment located at `[worldX, worldY]`.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
deleteAt(0, 4); // returns true
|
||||
28
doc/source/netscript/stanekapi/fragmentAt.rst
Normal file
28
doc/source/netscript/stanekapi/fragmentAt.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
fragmentAt() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: fragmentAt(worldX, worldY)
|
||||
|
||||
:RAM cost: 2 GB
|
||||
:param int worldX: World X coordinate of the fragment.
|
||||
:param int worldY: World Y coordinate of the fragment.
|
||||
:returns: The fragment located at `[worldX, worldY]` in Stanek's Gift, or null.
|
||||
|
||||
.. code-block:: typescript
|
||||
{
|
||||
// In world coordinates
|
||||
x: number;
|
||||
y: number;
|
||||
heat: number;
|
||||
charge: number;
|
||||
id: number;
|
||||
shape: boolean[][];
|
||||
type: string;
|
||||
magnitude: number;
|
||||
limit: number;
|
||||
}
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
var fragment = fragmentAt(0, 4);
|
||||
print(fragment); // {'heat': 50, 'charge': 98}
|
||||
23
doc/source/netscript/stanekapi/fragmentDefinitions.rst
Normal file
23
doc/source/netscript/stanekapi/fragmentDefinitions.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
fragmentDefinitions() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: fragmentDefinitions()
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:returns: The list of all fragment that can be embedded in Stanek's Gift.
|
||||
|
||||
.. code-block:: typescript
|
||||
[
|
||||
{
|
||||
id: number;
|
||||
shape: boolean[][];
|
||||
type: string;
|
||||
magnitude: number;
|
||||
limit: number;
|
||||
}
|
||||
]
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
var fragments = fragmentDefinitions();
|
||||
print(fragment); // prints all possible fragments
|
||||
15
doc/source/netscript/stanekapi/place.rst
Normal file
15
doc/source/netscript/stanekapi/place.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
place() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: place(worldX, worldY, fragmentId)
|
||||
|
||||
:RAM cost: 5 GB
|
||||
:param int worldX: World X against which to align the top left of the fragment.
|
||||
:param int worldY: World Y against which to align the top left of the fragment.
|
||||
:param int fragmentId: ID of the fragment to place.
|
||||
:returns: `true` if the fragment has been placed at that position. `false` otherwise.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
place(0, 4, 17); // returns true
|
||||
27
doc/source/netscript/stanekapi/placedFragments.rst
Normal file
27
doc/source/netscript/stanekapi/placedFragments.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
placedFragments() Netscript Function
|
||||
=======================================
|
||||
|
||||
.. js:function:: placedFragments()
|
||||
|
||||
:RAM cost: 5 GB
|
||||
:returns: The list of all fragment that are embedded in Stanek's Gift.
|
||||
|
||||
.. code-block:: typescript
|
||||
[
|
||||
{
|
||||
// In world coordinates
|
||||
x: number;
|
||||
y: number;
|
||||
heat: number;
|
||||
charge: number;
|
||||
id: number;
|
||||
shape: boolean[][];
|
||||
type: string;
|
||||
magnitude: number;
|
||||
limit: number;
|
||||
}
|
||||
]
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
var myFragments = placedFragments();
|
||||
453
doc/source/ystatic/dark_theme.css
Normal file
453
doc/source/ystatic/dark_theme.css
Normal file
@@ -0,0 +1,453 @@
|
||||
:root {
|
||||
--dark-text-color: #0c0;
|
||||
--dark-link-color: #090;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.wy-nav-content-wrap {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-nav-content {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.section {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.rst-content .highlighted {
|
||||
background: #333;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #17181c;
|
||||
}
|
||||
|
||||
.highlight .nn {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.highlight .nb {
|
||||
color: #8bb8df;
|
||||
}
|
||||
|
||||
.highlight .kn,
|
||||
.highlight .kc,
|
||||
.highlight .k {
|
||||
color: #41c2ea;
|
||||
}
|
||||
|
||||
.highlight .s1,
|
||||
.highlight .s2 {
|
||||
color: #b3e87f;
|
||||
}
|
||||
|
||||
.highlight .nt {
|
||||
color: #ccb350;
|
||||
}
|
||||
|
||||
.highlight .c1 {
|
||||
color: #686868;
|
||||
}
|
||||
|
||||
.rst-content div[class^="highlight"] {
|
||||
border-color: #1a1a1a;
|
||||
}
|
||||
|
||||
.icon,
|
||||
.icon-home {
|
||||
color: var(--dark-link-color);
|
||||
}
|
||||
|
||||
.wy-nav-content a,
|
||||
.wy-nav-content a:visited {
|
||||
color: var(--dark-link-color) !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn-neutral {
|
||||
background-color: #17181c !important;
|
||||
}
|
||||
|
||||
.btn-neutral:hover {
|
||||
background-color: #101114 !important;
|
||||
}
|
||||
|
||||
.btn-neutral:visited {
|
||||
color: #c1c1c1 !important;
|
||||
}
|
||||
|
||||
.btn {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: #bdbdbd;
|
||||
}
|
||||
|
||||
.wy-nav-side {
|
||||
background-color: #000;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
.wy-menu-vertical > a {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current > a,
|
||||
.wy-menu-vertical li.on a {
|
||||
background-color: #000;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.toctree-l1.current > a,
|
||||
.wy-menu-vertical li.current a {
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.wy-menu-vertical header,
|
||||
.wy-menu-vertical p.caption {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
html.writer-html4 .rst-content dl:not(.docutils) > dt,
|
||||
html.writer-html5
|
||||
.rst-content
|
||||
dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)
|
||||
> dt {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current a {
|
||||
color: #090;
|
||||
}
|
||||
.wy-menu-vertical a {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current a:hover {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.wy-menu-vertical a:hover,
|
||||
.wy-menu-vertical li.current > a:hover,
|
||||
.wy-menu-vertical li.on a:hover {
|
||||
background-color: #000;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.toctree-l2.current > a,
|
||||
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-side-nav-search {
|
||||
background-color: #000;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-side-nav-search .wy-dropdown > a,
|
||||
.wy-side-nav-search > a {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-side-nav-search input[type="text"] {
|
||||
border-left: 0px;
|
||||
border-right: 0px;
|
||||
border-top: 0px;
|
||||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
border-bottom-color: #0c0;
|
||||
background-color: #333;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.theme-switcher {
|
||||
background-color: #0b0c0d;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
writer-html4 .rst-content dl:not(.docutils) > dt,
|
||||
writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt {
|
||||
background-color: #0b0b0b;
|
||||
color: #007dce;
|
||||
border-color: #282828;
|
||||
}
|
||||
|
||||
.rst-content code,
|
||||
.rst-content tt {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt,
|
||||
writer-html5
|
||||
.rst-content
|
||||
dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)
|
||||
dl:not(.field-list)
|
||||
> dt {
|
||||
background-color: #0f0f0f;
|
||||
color: #959595;
|
||||
border-color: #2b2b2b;
|
||||
}
|
||||
|
||||
.rst-content code,
|
||||
.rst-content tt,
|
||||
code {
|
||||
background-color: #2d2d2d;
|
||||
border-color: #1c1c1c;
|
||||
}
|
||||
|
||||
.rst-content code.xref,
|
||||
.rst-content tt.xref,
|
||||
a .rst-content code,
|
||||
a .rst-content tt {
|
||||
color: #cecece;
|
||||
}
|
||||
|
||||
.rst-content .hint,
|
||||
.rst-content .important,
|
||||
.rst-content .tip,
|
||||
.rst-content .wy-alert-success.admonition,
|
||||
.rst-content .wy-alert-success.admonition-todo,
|
||||
.rst-content .wy-alert-success.attention,
|
||||
.rst-content .wy-alert-success.caution,
|
||||
.rst-content .wy-alert-success.danger,
|
||||
.rst-content .wy-alert-success.error,
|
||||
.rst-content .wy-alert-success.note,
|
||||
.rst-content .wy-alert-success.seealso,
|
||||
.rst-content .wy-alert-success.warning,
|
||||
.wy-alert.wy-alert-success {
|
||||
background-color: #00392e;
|
||||
}
|
||||
|
||||
.rst-content .hint .admonition-title,
|
||||
.rst-content .hint .wy-alert-title,
|
||||
.rst-content .important .admonition-title,
|
||||
.rst-content .important .wy-alert-title,
|
||||
.rst-content .tip .admonition-title,
|
||||
.rst-content .tip .wy-alert-title,
|
||||
.rst-content .wy-alert-success.admonition-todo .admonition-title,
|
||||
.rst-content .wy-alert-success.admonition-todo .wy-alert-title,
|
||||
.rst-content .wy-alert-success.admonition .admonition-title,
|
||||
.rst-content .wy-alert-success.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-success.attention .admonition-title,
|
||||
.rst-content .wy-alert-success.attention .wy-alert-title,
|
||||
.rst-content .wy-alert-success.caution .admonition-title,
|
||||
.rst-content .wy-alert-success.caution .wy-alert-title,
|
||||
.rst-content .wy-alert-success.danger .admonition-title,
|
||||
.rst-content .wy-alert-success.danger .wy-alert-title,
|
||||
.rst-content .wy-alert-success.error .admonition-title,
|
||||
.rst-content .wy-alert-success.error .wy-alert-title,
|
||||
.rst-content .wy-alert-success.note .admonition-title,
|
||||
.rst-content .wy-alert-success.note .wy-alert-title,
|
||||
.rst-content .wy-alert-success.seealso .admonition-title,
|
||||
.rst-content .wy-alert-success.seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-success.warning .admonition-title,
|
||||
.rst-content .wy-alert-success.warning .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-success .admonition-title,
|
||||
.wy-alert.wy-alert-success .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-success .wy-alert-title {
|
||||
background-color: #006a56;
|
||||
}
|
||||
|
||||
.rst-content .note,
|
||||
.rst-content .seealso,
|
||||
.rst-content .wy-alert-info.admonition,
|
||||
.rst-content .wy-alert-info.admonition-todo,
|
||||
.rst-content .wy-alert-info.attention,
|
||||
.rst-content .wy-alert-info.caution,
|
||||
.rst-content .wy-alert-info.danger,
|
||||
.rst-content .wy-alert-info.error,
|
||||
.rst-content .wy-alert-info.hint,
|
||||
.rst-content .wy-alert-info.important,
|
||||
.rst-content .wy-alert-info.tip,
|
||||
.rst-content .wy-alert-info.warning,
|
||||
.wy-alert.wy-alert-info {
|
||||
background-color: #002c4d;
|
||||
}
|
||||
|
||||
.rst-content .note .admonition-title,
|
||||
.rst-content .note .wy-alert-title,
|
||||
.rst-content .seealso .admonition-title,
|
||||
.rst-content .seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-info.admonition-todo .admonition-title,
|
||||
.rst-content .wy-alert-info.admonition-todo .wy-alert-title,
|
||||
.rst-content .wy-alert-info.admonition .admonition-title,
|
||||
.rst-content .wy-alert-info.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-info.attention .admonition-title,
|
||||
.rst-content .wy-alert-info.attention .wy-alert-title,
|
||||
.rst-content .wy-alert-info.caution .admonition-title,
|
||||
.rst-content .wy-alert-info.caution .wy-alert-title,
|
||||
.rst-content .wy-alert-info.danger .admonition-title,
|
||||
.rst-content .wy-alert-info.danger .wy-alert-title,
|
||||
.rst-content .wy-alert-info.error .admonition-title,
|
||||
.rst-content .wy-alert-info.error .wy-alert-title,
|
||||
.rst-content .wy-alert-info.hint .admonition-title,
|
||||
.rst-content .wy-alert-info.hint .wy-alert-title,
|
||||
.rst-content .wy-alert-info.important .admonition-title,
|
||||
.rst-content .wy-alert-info.important .wy-alert-title,
|
||||
.rst-content .wy-alert-info.tip .admonition-title,
|
||||
.rst-content .wy-alert-info.tip .wy-alert-title,
|
||||
.rst-content .wy-alert-info.warning .admonition-title,
|
||||
.rst-content .wy-alert-info.warning .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-info .admonition-title,
|
||||
.wy-alert.wy-alert-info .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-info .wy-alert-title {
|
||||
background-color: #004a7b;
|
||||
}
|
||||
|
||||
.rst-content dl:not(.docutils) dt {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.rst-content {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.rst-content .admonition-todo,
|
||||
.rst-content .attention,
|
||||
.rst-content .caution,
|
||||
.rst-content .warning,
|
||||
.rst-content .wy-alert-warning.admonition,
|
||||
.rst-content .wy-alert-warning.danger,
|
||||
.rst-content .wy-alert-warning.error,
|
||||
.rst-content .wy-alert-warning.hint,
|
||||
.rst-content .wy-alert-warning.important,
|
||||
.rst-content .wy-alert-warning.note,
|
||||
.rst-content .wy-alert-warning.seealso,
|
||||
.rst-content .wy-alert-warning.tip,
|
||||
.wy-alert.wy-alert-warning {
|
||||
background-color: #533500;
|
||||
}
|
||||
|
||||
.rst-content .admonition-todo .admonition-title,
|
||||
.rst-content .admonition-todo .wy-alert-title,
|
||||
.rst-content .attention .admonition-title,
|
||||
.rst-content .attention .wy-alert-title,
|
||||
.rst-content .caution .admonition-title,
|
||||
.rst-content .caution .wy-alert-title,
|
||||
.rst-content .warning .admonition-title,
|
||||
.rst-content .warning .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.admonition .admonition-title,
|
||||
.rst-content .wy-alert-warning.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.danger .admonition-title,
|
||||
.rst-content .wy-alert-warning.danger .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.error .admonition-title,
|
||||
.rst-content .wy-alert-warning.error .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.hint .admonition-title,
|
||||
.rst-content .wy-alert-warning.hint .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.important .admonition-title,
|
||||
.rst-content .wy-alert-warning.important .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.note .admonition-title,
|
||||
.rst-content .wy-alert-warning.note .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.seealso .admonition-title,
|
||||
.rst-content .wy-alert-warning.seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.tip .admonition-title,
|
||||
.rst-content .wy-alert-warning.tip .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-warning .admonition-title,
|
||||
.wy-alert.wy-alert-warning .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-warning .wy-alert-title {
|
||||
background-color: #803b00;
|
||||
}
|
||||
|
||||
.rst-content .danger,
|
||||
.rst-content .error,
|
||||
.rst-content .wy-alert-danger.admonition,
|
||||
.rst-content .wy-alert-danger.admonition-todo,
|
||||
.rst-content .wy-alert-danger.attention,
|
||||
.rst-content .wy-alert-danger.caution,
|
||||
.rst-content .wy-alert-danger.hint,
|
||||
.rst-content .wy-alert-danger.important,
|
||||
.rst-content .wy-alert-danger.note,
|
||||
.rst-content .wy-alert-danger.seealso,
|
||||
.rst-content .wy-alert-danger.tip,
|
||||
.rst-content .wy-alert-danger.warning,
|
||||
.wy-alert.wy-alert-danger {
|
||||
background-color: #82231a;
|
||||
}
|
||||
|
||||
.rst-content .danger .admonition-title,
|
||||
.rst-content .danger .wy-alert-title,
|
||||
.rst-content .error .admonition-title,
|
||||
.rst-content .error .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.admonition-todo .admonition-title,
|
||||
.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.admonition .admonition-title,
|
||||
.rst-content .wy-alert-danger.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.attention .admonition-title,
|
||||
.rst-content .wy-alert-danger.attention .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.caution .admonition-title,
|
||||
.rst-content .wy-alert-danger.caution .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.hint .admonition-title,
|
||||
.rst-content .wy-alert-danger.hint .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.important .admonition-title,
|
||||
.rst-content .wy-alert-danger.important .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.note .admonition-title,
|
||||
.rst-content .wy-alert-danger.note .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.seealso .admonition-title,
|
||||
.rst-content .wy-alert-danger.seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.tip .admonition-title,
|
||||
.rst-content .wy-alert-danger.tip .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.warning .admonition-title,
|
||||
.rst-content .wy-alert-danger.warning .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-danger .admonition-title,
|
||||
.wy-alert.wy-alert-danger .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-danger .wy-alert-title {
|
||||
background-color: #b9372b;
|
||||
}
|
||||
|
||||
.wy-nav-top {
|
||||
background-color: #0b152d;
|
||||
}
|
||||
|
||||
.rst-content table.docutils thead,
|
||||
.rst-content table.field-list thead,
|
||||
.wy-table thead {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,
|
||||
.wy-table-backed,
|
||||
.wy-table-odd td,
|
||||
.wy-table-striped tr:nth-child(2n-1) td {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.rst-content table.docutils:not(.field-list) tr:nth-child(2n) td,
|
||||
.wy-table-backed,
|
||||
.wy-table-odd td,
|
||||
.wy-table-striped tr:nth-child(2n) td {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.rst-content table.docutils td,
|
||||
.wy-table-bordered-all td,
|
||||
writer-html5 .rst-content table.docutils th,
|
||||
.rst-content table.docutils,
|
||||
.wy-table-bordered-all {
|
||||
border-color: #262626;
|
||||
}
|
||||
|
||||
.rst-content table.docutils caption,
|
||||
.rst-content table.field-list caption,
|
||||
.wy-table caption {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.toctree-l3.current > a,
|
||||
.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-side-nav-search > div.version {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
@@ -39,11 +39,13 @@
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
* {
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar {
|
||||
*::-webkit-scrollbar {
|
||||
display: none; /* for Chrome, Safari, and Opera */
|
||||
}
|
||||
</style>
|
||||
@@ -51,5 +53,5 @@
|
||||
<body>
|
||||
<div id="root"/>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body>
|
||||
<script src="src/ThirdParty/raphael.min.js"></script>
|
||||
<!-- http://plaza.dsolver.ca/m/hydroflame4418 -->
|
||||
</html>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
62
package-lock.json
generated
62
package-lock.json
generated
@@ -21,6 +21,7 @@
|
||||
"@types/numeral": "0.0.25",
|
||||
"@types/react": "^17.0.21",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-resizable": "^1.7.3",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"ajv": "^5.1.5",
|
||||
@@ -53,7 +54,9 @@
|
||||
"numeral": "2.0.6",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-draggable": "^4.4.4",
|
||||
"react-modal": "^3.12.1",
|
||||
"react-resizable": "^3.0.4",
|
||||
"sprintf-js": "^1.1.1",
|
||||
"tapable": "^1.0.0",
|
||||
"treant-js": "^1.0.1",
|
||||
@@ -4673,6 +4676,14 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-resizable": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-resizable/-/react-resizable-1.7.3.tgz",
|
||||
"integrity": "sha512-DAx+hdnHFMJHgl8geiKo3jLt1GCT838SwQixjCtbRRfqCBawAKriVLCZ1nvp7B/2Pxd94MWod8NyJEnAAmNHNA==",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
@@ -22097,6 +22108,19 @@
|
||||
"react": "17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-draggable": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.4.tgz",
|
||||
"integrity": "sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==",
|
||||
"dependencies": {
|
||||
"clsx": "^1.1.1",
|
||||
"prop-types": "^15.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.3.0",
|
||||
"react-dom": ">= 16.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz",
|
||||
@@ -22130,6 +22154,18 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-resizable": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.4.tgz",
|
||||
"integrity": "sha512-StnwmiESiamNzdRHbSSvA65b0ZQJ7eVQpPusrSmcpyGKzC0gojhtO62xxH6YOBmepk9dQTBi9yxidL3W4s3EBA==",
|
||||
"dependencies": {
|
||||
"prop-types": "15.x",
|
||||
"react-draggable": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
@@ -31573,6 +31609,14 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-resizable": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-resizable/-/react-resizable-1.7.3.tgz",
|
||||
"integrity": "sha512-DAx+hdnHFMJHgl8geiKo3jLt1GCT838SwQixjCtbRRfqCBawAKriVLCZ1nvp7B/2Pxd94MWod8NyJEnAAmNHNA==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
@@ -45494,6 +45538,15 @@
|
||||
"scheduler": "^0.20.2"
|
||||
}
|
||||
},
|
||||
"react-draggable": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.4.tgz",
|
||||
"integrity": "sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==",
|
||||
"requires": {
|
||||
"clsx": "^1.1.1",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz",
|
||||
@@ -45521,6 +45574,15 @@
|
||||
"integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
|
||||
"dev": true
|
||||
},
|
||||
"react-resizable": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.4.tgz",
|
||||
"integrity": "sha512-StnwmiESiamNzdRHbSSvA65b0ZQJ7eVQpPusrSmcpyGKzC0gojhtO62xxH6YOBmepk9dQTBi9yxidL3W4s3EBA==",
|
||||
"requires": {
|
||||
"prop-types": "15.x",
|
||||
"react-draggable": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"version": "0.53.0",
|
||||
"version": "0.56.0",
|
||||
"main": "electron-main.js",
|
||||
"author": {
|
||||
"name": "Daniel Xie"
|
||||
@@ -22,6 +22,7 @@
|
||||
"@types/numeral": "0.0.25",
|
||||
"@types/react": "^17.0.21",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-resizable": "^1.7.3",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"ajv": "^5.1.5",
|
||||
@@ -54,7 +55,9 @@
|
||||
"numeral": "2.0.6",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-draggable": "^4.4.4",
|
||||
"react-modal": "^3.12.1",
|
||||
"react-resizable": "^3.0.4",
|
||||
"sprintf-js": "^1.1.1",
|
||||
"tapable": "^1.0.0",
|
||||
"treant-js": "^1.0.1",
|
||||
|
||||
@@ -2,433 +2,366 @@ const numSpaces = 4;
|
||||
const maxLineLength = 160;
|
||||
|
||||
module.exports = {
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
extends: "eslint:recommended",
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
"ecmaVersion": 8,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{
|
||||
"getWithoutSet": false,
|
||||
"setWithoutGet": true
|
||||
}
|
||||
],
|
||||
"array-bracket-newline": ["error"],
|
||||
"array-bracket-spacing": ["error"],
|
||||
"array-callback-return": ["error"],
|
||||
"array-element-newline": ["error"],
|
||||
"arrow-body-style": ["error"],
|
||||
"arrow-parens": ["error"],
|
||||
"arrow-spacing": ["error"],
|
||||
"block-scoped-var": ["error"],
|
||||
"block-spacing": ["error"],
|
||||
"brace-style": ["error"],
|
||||
"callback-return": ["error"],
|
||||
"camelcase": ["error"],
|
||||
"capitalized-comments": ["error"],
|
||||
"class-methods-use-this": ["error"],
|
||||
"comma-dangle": ["error"],
|
||||
"comma-spacing": ["error"],
|
||||
"comma-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"complexity": ["error"],
|
||||
"computed-property-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"consistent-return": ["error"],
|
||||
"consistent-this": ["error"],
|
||||
"constructor-super": ["error"],
|
||||
"curly": ["error"],
|
||||
"default-case": ["error"],
|
||||
"dot-location": [
|
||||
"error",
|
||||
"property"
|
||||
],
|
||||
"dot-notation": ["error"],
|
||||
"eol-last": ["error"],
|
||||
"eqeqeq": ["error"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["error"],
|
||||
"func-name-matching": ["error"],
|
||||
"func-names": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"func-style": ["error"],
|
||||
"function-paren-newline": ["error"],
|
||||
"generator-star-spacing": [
|
||||
"error",
|
||||
"before"
|
||||
],
|
||||
"getter-return": [
|
||||
"error",
|
||||
{
|
||||
"allowImplicit": false
|
||||
}
|
||||
],
|
||||
"global-require": ["error"],
|
||||
"guard-for-in": ["error"],
|
||||
"handle-callback-err": ["error"],
|
||||
"id-blacklist": ["error"],
|
||||
"id-length": ["error"],
|
||||
"id-match": ["error"],
|
||||
"implicit-arrow-linebreak": [
|
||||
"error",
|
||||
"beside"
|
||||
],
|
||||
"indent": [
|
||||
"error",
|
||||
numSpaces,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"init-declarations": ["error"],
|
||||
"jsx-quotes": ["error"],
|
||||
"key-spacing": ["error"],
|
||||
"keyword-spacing": ["error"],
|
||||
"line-comment-position": ["error"],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"windows"
|
||||
],
|
||||
"lines-around-comment": ["error"],
|
||||
"lines-between-class-members": ["error"],
|
||||
"max-depth": ["error"],
|
||||
"max-len": [
|
||||
"error",
|
||||
maxLineLength
|
||||
],
|
||||
"max-lines": [
|
||||
"error",
|
||||
{
|
||||
"skipBlankLines": true,
|
||||
"skipComments": true
|
||||
}
|
||||
],
|
||||
"max-nested-callbacks": ["error"],
|
||||
"max-params": ["error"],
|
||||
"max-statements": ["error"],
|
||||
"max-statements-per-line": ["error"],
|
||||
"multiline-comment-style": [
|
||||
"off",
|
||||
"starred-block"
|
||||
],
|
||||
"multiline-ternary": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"new-cap": ["error"],
|
||||
"new-parens": ["error"],
|
||||
// TODO: configure this...
|
||||
"newline-before-return": ["error"],
|
||||
"newline-per-chained-call": ["error"],
|
||||
"no-alert": ["error"],
|
||||
"no-array-constructor": ["error"],
|
||||
"no-await-in-loop": ["error"],
|
||||
"no-bitwise": ["error"],
|
||||
"no-buffer-constructor": ["error"],
|
||||
"no-caller": ["error"],
|
||||
"no-case-declarations": ["error"],
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-cond-assign": [
|
||||
"error",
|
||||
"except-parens"
|
||||
],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["error"],
|
||||
"no-const-assign": ["error"],
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-continue": ["off"],
|
||||
"no-control-regex": ["error"],
|
||||
"no-debugger": ["error"],
|
||||
"no-delete-var": ["error"],
|
||||
"no-div-regex": ["error"],
|
||||
"no-dupe-args": ["error"],
|
||||
"no-dupe-class-members": ["error"],
|
||||
"no-dupe-keys": ["error"],
|
||||
"no-duplicate-case": ["error"],
|
||||
"no-duplicate-imports": [
|
||||
"error",
|
||||
{
|
||||
"includeExports": true
|
||||
}
|
||||
],
|
||||
"no-else-return": ["error"],
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
"allowEmptyCatch": false
|
||||
}
|
||||
],
|
||||
"no-empty-character-class": ["error"],
|
||||
"no-empty-function": ["error"],
|
||||
"no-empty-pattern": ["error"],
|
||||
"no-eq-null": ["error"],
|
||||
"no-eval": ["error"],
|
||||
"no-ex-assign": ["error"],
|
||||
"no-extend-native": ["error"],
|
||||
"no-extra-bind": ["error"],
|
||||
"no-extra-boolean-cast": ["error"],
|
||||
"no-extra-label": ["error"],
|
||||
"no-extra-parens": [
|
||||
"error",
|
||||
"all",
|
||||
{
|
||||
"conditionalAssign": false
|
||||
}
|
||||
],
|
||||
"no-extra-semi": ["error"],
|
||||
"no-fallthrough": ["error"],
|
||||
"no-floating-decimal": ["error"],
|
||||
"no-func-assign": ["error"],
|
||||
"no-global-assign": ["error"],
|
||||
"no-implicit-coercion": ["error"],
|
||||
"no-implicit-globals": ["error"],
|
||||
"no-implied-eval": ["error"],
|
||||
"no-inline-comments": ["error"],
|
||||
"no-inner-declarations": [
|
||||
"error",
|
||||
"both"
|
||||
],
|
||||
"no-invalid-regexp": ["error"],
|
||||
"no-invalid-this": ["error"],
|
||||
"no-irregular-whitespace": [
|
||||
"error",
|
||||
{
|
||||
"skipComments": false,
|
||||
"skipRegExps": false,
|
||||
"skipStrings": false,
|
||||
"skipTemplates": false
|
||||
}
|
||||
],
|
||||
"no-iterator": ["error"],
|
||||
"no-label-var": ["error"],
|
||||
"no-labels": ["error"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-lonely-if": ["error"],
|
||||
"no-loop-func": ["error"],
|
||||
"no-magic-numbers": [
|
||||
"error",
|
||||
{
|
||||
"ignore": [
|
||||
-1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"ignoreArrayIndexes": true
|
||||
}
|
||||
],
|
||||
"no-mixed-operators": ["error"],
|
||||
"no-mixed-requires": ["error"],
|
||||
"no-mixed-spaces-and-tabs": ["error"],
|
||||
"no-multi-assign": ["error"],
|
||||
"no-multi-spaces": ["error"],
|
||||
"no-multi-str": ["error"],
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{
|
||||
"max": 1
|
||||
}
|
||||
],
|
||||
"no-native-reassign": ["error"],
|
||||
"no-negated-condition": ["error"],
|
||||
"no-negated-in-lhs": ["error"],
|
||||
"no-nested-ternary": ["error"],
|
||||
"no-new": ["error"],
|
||||
"no-new-func": ["error"],
|
||||
"no-new-object": ["error"],
|
||||
"no-new-require": ["error"],
|
||||
"no-new-symbol": ["error"],
|
||||
"no-new-wrappers": ["error"],
|
||||
"no-obj-calls": ["error"],
|
||||
"no-octal": ["error"],
|
||||
"no-octal-escape": ["error"],
|
||||
"no-param-reassign": ["error"],
|
||||
"no-path-concat": ["error"],
|
||||
"no-plusplus": [
|
||||
"error",
|
||||
{
|
||||
"allowForLoopAfterthoughts": true
|
||||
}
|
||||
],
|
||||
"no-process-env": ["error"],
|
||||
"no-process-exit": ["error"],
|
||||
"no-proto": ["error"],
|
||||
"no-prototype-builtins": ["error"],
|
||||
"no-redeclare": ["error"],
|
||||
"no-regex-spaces": ["error"],
|
||||
"no-restricted-globals": ["error"],
|
||||
"no-restricted-imports": ["error"],
|
||||
"no-restricted-modules": ["error"],
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
"message": "'log' is too general, use an appropriate level when logging.",
|
||||
"object": "console",
|
||||
"property": "log"
|
||||
}
|
||||
],
|
||||
"no-restricted-syntax": ["error"],
|
||||
"no-return-assign": ["error"],
|
||||
"no-return-await": ["error"],
|
||||
"no-script-url": ["error"],
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
"props": false
|
||||
}
|
||||
],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
"no-shadow": ["error"],
|
||||
"no-shadow-restricted-names": ["error"],
|
||||
"no-spaced-func": ["error"],
|
||||
"no-sparse-arrays": ["error"],
|
||||
"no-sync": ["error"],
|
||||
"no-tabs": ["error"],
|
||||
"no-template-curly-in-string": ["error"],
|
||||
"no-ternary": ["off"],
|
||||
"no-this-before-super": ["error"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-undef": ["error"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-undefined": ["error"],
|
||||
"no-underscore-dangle": ["error"],
|
||||
"no-unexpected-multiline": ["error"],
|
||||
"no-unmodified-loop-condition": ["error"],
|
||||
"no-unneeded-ternary": ["error"],
|
||||
"no-unreachable": ["error"],
|
||||
"no-unsafe-finally": ["error"],
|
||||
"no-unsafe-negation": ["error"],
|
||||
"no-unused-expressions": ["error"],
|
||||
"no-unused-labels": ["error"],
|
||||
"no-unused-vars": ["error"],
|
||||
"no-use-before-define": ["error"],
|
||||
"no-useless-call": ["error"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-concat": ["error"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-escape": ["error"],
|
||||
"no-useless-rename": [
|
||||
"error",
|
||||
{
|
||||
"ignoreDestructuring": false,
|
||||
"ignoreExport": false,
|
||||
"ignoreImport": false
|
||||
}
|
||||
],
|
||||
"no-useless-return": ["error"],
|
||||
"no-var": ["error"],
|
||||
"no-void": ["error"],
|
||||
"no-warning-comments": ["error"],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"no-with": ["error"],
|
||||
"nonblock-statement-body-position": [
|
||||
"error",
|
||||
"below"
|
||||
],
|
||||
"object-curly-newline": ["error"],
|
||||
"object-curly-spacing": ["error"],
|
||||
"object-property-newline": ["error"],
|
||||
"object-shorthand": ["error"],
|
||||
"one-var": ["off"],
|
||||
"one-var-declaration-per-line": ["error"],
|
||||
"operator-assignment": ["error"],
|
||||
"operator-linebreak": [
|
||||
"error",
|
||||
"none"
|
||||
],
|
||||
"padded-blocks": ["off"],
|
||||
"padding-line-between-statements": ["error"],
|
||||
"prefer-arrow-callback": ["error"],
|
||||
"prefer-const": ["error"],
|
||||
"prefer-destructuring": ["off"],
|
||||
"prefer-numeric-literals": ["error"],
|
||||
"prefer-promise-reject-errors": ["off"],
|
||||
"prefer-reflect": ["error"],
|
||||
"prefer-rest-params": ["error"],
|
||||
"prefer-spread": ["error"],
|
||||
"prefer-template": ["error"],
|
||||
"quote-props": ["error"],
|
||||
"quotes": ["error"],
|
||||
"radix": [
|
||||
"error",
|
||||
"as-needed"
|
||||
],
|
||||
"require-await": ["error"],
|
||||
"require-jsdoc": ["off"],
|
||||
"require-yield": ["error"],
|
||||
"rest-spread-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"semi": ["error"],
|
||||
"semi-spacing": ["error"],
|
||||
"semi-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"sort-imports": ["error"],
|
||||
"sort-keys": ["error"],
|
||||
"sort-vars": ["error"],
|
||||
"space-before-blocks": ["error"],
|
||||
"space-before-function-paren": ["off"],
|
||||
"space-in-parens": ["error"],
|
||||
"space-infix-ops": ["error"],
|
||||
"space-unary-ops": ["error"],
|
||||
"spaced-comment": ["error"],
|
||||
"strict": ["error"],
|
||||
"switch-colon-spacing": [
|
||||
"error",
|
||||
{
|
||||
"after": true,
|
||||
"before": false
|
||||
}
|
||||
],
|
||||
"symbol-description": ["error"],
|
||||
"template-curly-spacing": ["error"],
|
||||
"template-tag-spacing": ["error"],
|
||||
"unicode-bom": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"use-isnan": ["error"],
|
||||
"valid-jsdoc": ["error"],
|
||||
"valid-typeof": ["error"],
|
||||
"vars-on-top": ["error"],
|
||||
"wrap-iife": [
|
||||
"error",
|
||||
"any"
|
||||
],
|
||||
"wrap-regex": ["error"],
|
||||
"yield-star-spacing": [
|
||||
"error",
|
||||
"before"
|
||||
],
|
||||
"yoda": [
|
||||
"error",
|
||||
"never"
|
||||
]
|
||||
}
|
||||
ecmaVersion: 8,
|
||||
sourceType: "module",
|
||||
},
|
||||
rules: {
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{
|
||||
getWithoutSet: false,
|
||||
setWithoutGet: true,
|
||||
},
|
||||
],
|
||||
"array-bracket-newline": ["error"],
|
||||
"array-bracket-spacing": ["error"],
|
||||
"array-callback-return": ["error"],
|
||||
"array-element-newline": ["error"],
|
||||
"arrow-body-style": ["error"],
|
||||
"arrow-parens": ["error"],
|
||||
"arrow-spacing": ["error"],
|
||||
"block-scoped-var": ["error"],
|
||||
"block-spacing": ["error"],
|
||||
"brace-style": ["error"],
|
||||
"callback-return": ["error"],
|
||||
camelcase: ["error"],
|
||||
"capitalized-comments": ["error"],
|
||||
"class-methods-use-this": ["error"],
|
||||
"comma-dangle": ["error"],
|
||||
"comma-spacing": ["error"],
|
||||
"comma-style": ["error", "last"],
|
||||
complexity: ["error"],
|
||||
"computed-property-spacing": ["error", "never"],
|
||||
"consistent-return": ["error"],
|
||||
"consistent-this": ["error"],
|
||||
"constructor-super": ["error"],
|
||||
curly: ["error"],
|
||||
"default-case": ["error"],
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": ["error"],
|
||||
"eol-last": ["error"],
|
||||
eqeqeq: ["error"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["error"],
|
||||
"func-name-matching": ["error"],
|
||||
"func-names": ["error", "never"],
|
||||
"func-style": ["error"],
|
||||
"function-paren-newline": ["error"],
|
||||
"generator-star-spacing": ["error", "before"],
|
||||
"getter-return": [
|
||||
"error",
|
||||
{
|
||||
allowImplicit: false,
|
||||
},
|
||||
],
|
||||
"global-require": ["error"],
|
||||
"guard-for-in": ["error"],
|
||||
"handle-callback-err": ["error"],
|
||||
"id-blacklist": ["error"],
|
||||
"id-length": ["error"],
|
||||
"id-match": ["error"],
|
||||
"implicit-arrow-linebreak": ["error", "beside"],
|
||||
indent: [
|
||||
"error",
|
||||
numSpaces,
|
||||
{
|
||||
SwitchCase: 1,
|
||||
},
|
||||
],
|
||||
"init-declarations": ["error"],
|
||||
"jsx-quotes": ["error"],
|
||||
"key-spacing": ["error"],
|
||||
"keyword-spacing": ["error"],
|
||||
"line-comment-position": ["error"],
|
||||
"linebreak-style": ["error", "windows"],
|
||||
"lines-around-comment": ["error"],
|
||||
"lines-between-class-members": ["error"],
|
||||
"max-depth": ["error"],
|
||||
"max-len": ["error", maxLineLength],
|
||||
"max-lines": [
|
||||
"error",
|
||||
{
|
||||
skipBlankLines: true,
|
||||
skipComments: true,
|
||||
},
|
||||
],
|
||||
"max-nested-callbacks": ["error"],
|
||||
"max-params": ["error"],
|
||||
"max-statements": ["error"],
|
||||
"max-statements-per-line": ["error"],
|
||||
"multiline-comment-style": ["off", "starred-block"],
|
||||
"multiline-ternary": ["error", "never"],
|
||||
"new-cap": ["error"],
|
||||
"new-parens": ["error"],
|
||||
// TODO: configure this...
|
||||
"newline-before-return": ["error"],
|
||||
"newline-per-chained-call": ["error"],
|
||||
"no-alert": ["error"],
|
||||
"no-array-constructor": ["error"],
|
||||
"no-await-in-loop": ["error"],
|
||||
"no-bitwise": ["error"],
|
||||
"no-buffer-constructor": ["error"],
|
||||
"no-caller": ["error"],
|
||||
"no-case-declarations": ["error"],
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-cond-assign": ["error", "except-parens"],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["error"],
|
||||
"no-const-assign": ["error"],
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
checkLoops: false,
|
||||
},
|
||||
],
|
||||
"no-continue": ["off"],
|
||||
"no-control-regex": ["error"],
|
||||
"no-debugger": ["error"],
|
||||
"no-delete-var": ["error"],
|
||||
"no-div-regex": ["error"],
|
||||
"no-dupe-args": ["error"],
|
||||
"no-dupe-class-members": ["error"],
|
||||
"no-dupe-keys": ["error"],
|
||||
"no-duplicate-case": ["error"],
|
||||
"no-duplicate-imports": [
|
||||
"error",
|
||||
{
|
||||
includeExports: true,
|
||||
},
|
||||
],
|
||||
"no-else-return": ["error"],
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
allowEmptyCatch: false,
|
||||
},
|
||||
],
|
||||
"no-empty-character-class": ["error"],
|
||||
"no-empty-function": ["error"],
|
||||
"no-empty-pattern": ["error"],
|
||||
"no-eq-null": ["error"],
|
||||
"no-eval": ["error"],
|
||||
"no-ex-assign": ["error"],
|
||||
"no-extend-native": ["error"],
|
||||
"no-extra-bind": ["error"],
|
||||
"no-extra-boolean-cast": ["error"],
|
||||
"no-extra-label": ["error"],
|
||||
"no-extra-parens": [
|
||||
"error",
|
||||
"all",
|
||||
{
|
||||
conditionalAssign: false,
|
||||
},
|
||||
],
|
||||
"no-extra-semi": ["error"],
|
||||
"no-fallthrough": ["error"],
|
||||
"no-floating-decimal": ["error"],
|
||||
"no-func-assign": ["error"],
|
||||
"no-global-assign": ["error"],
|
||||
"no-implicit-coercion": ["error"],
|
||||
"no-implicit-globals": ["error"],
|
||||
"no-implied-eval": ["error"],
|
||||
"no-inline-comments": ["error"],
|
||||
"no-inner-declarations": ["error", "both"],
|
||||
"no-invalid-regexp": ["error"],
|
||||
"no-invalid-this": ["error"],
|
||||
"no-irregular-whitespace": [
|
||||
"error",
|
||||
{
|
||||
skipComments: false,
|
||||
skipRegExps: false,
|
||||
skipStrings: false,
|
||||
skipTemplates: false,
|
||||
},
|
||||
],
|
||||
"no-iterator": ["error"],
|
||||
"no-label-var": ["error"],
|
||||
"no-labels": ["error"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-lonely-if": ["error"],
|
||||
"no-loop-func": ["error"],
|
||||
"no-magic-numbers": [
|
||||
"error",
|
||||
{
|
||||
ignore: [-1, 0, 1],
|
||||
ignoreArrayIndexes: true,
|
||||
},
|
||||
],
|
||||
"no-mixed-operators": ["error"],
|
||||
"no-mixed-requires": ["error"],
|
||||
"no-mixed-spaces-and-tabs": ["error"],
|
||||
"no-multi-assign": ["error"],
|
||||
"no-multi-spaces": ["error"],
|
||||
"no-multi-str": ["error"],
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{
|
||||
max: 1,
|
||||
},
|
||||
],
|
||||
"no-native-reassign": ["error"],
|
||||
"no-negated-condition": ["error"],
|
||||
"no-negated-in-lhs": ["error"],
|
||||
"no-nested-ternary": ["error"],
|
||||
"no-new": ["error"],
|
||||
"no-new-func": ["error"],
|
||||
"no-new-object": ["error"],
|
||||
"no-new-require": ["error"],
|
||||
"no-new-symbol": ["error"],
|
||||
"no-new-wrappers": ["error"],
|
||||
"no-obj-calls": ["error"],
|
||||
"no-octal": ["error"],
|
||||
"no-octal-escape": ["error"],
|
||||
"no-param-reassign": ["error"],
|
||||
"no-path-concat": ["error"],
|
||||
"no-plusplus": [
|
||||
"error",
|
||||
{
|
||||
allowForLoopAfterthoughts: true,
|
||||
},
|
||||
],
|
||||
"no-process-env": ["error"],
|
||||
"no-process-exit": ["error"],
|
||||
"no-proto": ["error"],
|
||||
"no-prototype-builtins": ["error"],
|
||||
"no-redeclare": ["error"],
|
||||
"no-regex-spaces": ["error"],
|
||||
"no-restricted-globals": ["error"],
|
||||
"no-restricted-imports": ["error"],
|
||||
"no-restricted-modules": ["error"],
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
message: "'log' is too general, use an appropriate level when logging.",
|
||||
object: "console",
|
||||
property: "log",
|
||||
},
|
||||
],
|
||||
"no-restricted-syntax": ["error"],
|
||||
"no-return-assign": ["error"],
|
||||
"no-return-await": ["error"],
|
||||
"no-script-url": ["error"],
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
props: false,
|
||||
},
|
||||
],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
"no-shadow": ["error"],
|
||||
"no-shadow-restricted-names": ["error"],
|
||||
"no-spaced-func": ["error"],
|
||||
"no-sparse-arrays": ["error"],
|
||||
"no-sync": ["error"],
|
||||
"no-tabs": ["error"],
|
||||
"no-template-curly-in-string": ["error"],
|
||||
"no-ternary": ["off"],
|
||||
"no-this-before-super": ["error"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-undef": ["error"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-undefined": ["error"],
|
||||
"no-underscore-dangle": ["error"],
|
||||
"no-unexpected-multiline": ["error"],
|
||||
"no-unmodified-loop-condition": ["error"],
|
||||
"no-unneeded-ternary": ["error"],
|
||||
"no-unreachable": ["error"],
|
||||
"no-unsafe-finally": ["error"],
|
||||
"no-unsafe-negation": ["error"],
|
||||
"no-unused-expressions": ["error"],
|
||||
"no-unused-labels": ["error"],
|
||||
"no-unused-vars": ["error"],
|
||||
"no-use-before-define": ["error"],
|
||||
"no-useless-call": ["error"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-concat": ["error"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-escape": ["error"],
|
||||
"no-useless-rename": [
|
||||
"error",
|
||||
{
|
||||
ignoreDestructuring: false,
|
||||
ignoreExport: false,
|
||||
ignoreImport: false,
|
||||
},
|
||||
],
|
||||
"no-useless-return": ["error"],
|
||||
"no-var": ["error"],
|
||||
"no-void": ["error"],
|
||||
"no-warning-comments": ["error"],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"no-with": ["error"],
|
||||
"nonblock-statement-body-position": ["error", "below"],
|
||||
"object-curly-newline": ["error"],
|
||||
"object-curly-spacing": ["error"],
|
||||
"object-property-newline": ["error"],
|
||||
"object-shorthand": ["error"],
|
||||
"one-var": ["off"],
|
||||
"one-var-declaration-per-line": ["error"],
|
||||
"operator-assignment": ["error"],
|
||||
"operator-linebreak": ["error", "none"],
|
||||
"padded-blocks": ["off"],
|
||||
"padding-line-between-statements": ["error"],
|
||||
"prefer-arrow-callback": ["error"],
|
||||
"prefer-const": ["error"],
|
||||
"prefer-destructuring": ["off"],
|
||||
"prefer-numeric-literals": ["error"],
|
||||
"prefer-promise-reject-errors": ["off"],
|
||||
"prefer-reflect": ["error"],
|
||||
"prefer-rest-params": ["error"],
|
||||
"prefer-spread": ["error"],
|
||||
"prefer-template": ["error"],
|
||||
"quote-props": ["error"],
|
||||
quotes: ["error"],
|
||||
radix: ["error", "as-needed"],
|
||||
"require-await": ["error"],
|
||||
"require-jsdoc": ["off"],
|
||||
"require-yield": ["error"],
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
semi: ["error"],
|
||||
"semi-spacing": ["error"],
|
||||
"semi-style": ["error", "last"],
|
||||
"sort-imports": ["error"],
|
||||
"sort-keys": ["error"],
|
||||
"sort-vars": ["error"],
|
||||
"space-before-blocks": ["error"],
|
||||
"space-before-function-paren": ["off"],
|
||||
"space-in-parens": ["error"],
|
||||
"space-infix-ops": ["error"],
|
||||
"space-unary-ops": ["error"],
|
||||
"spaced-comment": ["error"],
|
||||
strict: ["error"],
|
||||
"switch-colon-spacing": [
|
||||
"error",
|
||||
{
|
||||
after: true,
|
||||
before: false,
|
||||
},
|
||||
],
|
||||
"symbol-description": ["error"],
|
||||
"template-curly-spacing": ["error"],
|
||||
"template-tag-spacing": ["error"],
|
||||
"unicode-bom": ["error", "never"],
|
||||
"use-isnan": ["error"],
|
||||
"valid-jsdoc": ["error"],
|
||||
"valid-typeof": ["error"],
|
||||
"vars-on-top": ["error"],
|
||||
"wrap-iife": ["error", "any"],
|
||||
"wrap-regex": ["error"],
|
||||
"yield-star-spacing": ["error", "before"],
|
||||
yoda: ["error", "never"],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -8,66 +8,74 @@ const path = require("path");
|
||||
const exec = require("child_process").exec;
|
||||
const semver = require("./semver");
|
||||
|
||||
const getPackageJson = () => new Promise((resolve, reject) => {
|
||||
const getPackageJson = () =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
/* eslint-disable-next-line global-require */
|
||||
resolve(require(path.resolve(process.cwd(), "package.json")));
|
||||
/* eslint-disable-next-line global-require */
|
||||
resolve(require(path.resolve(process.cwd(), "package.json")));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const getEngines = (data) => new Promise((resolve, reject) => {
|
||||
const getEngines = (data) =>
|
||||
new Promise((resolve, reject) => {
|
||||
let versions = null;
|
||||
|
||||
if (data.engines) {
|
||||
versions = data.engines;
|
||||
versions = data.engines;
|
||||
}
|
||||
|
||||
if (versions) {
|
||||
resolve(versions);
|
||||
resolve(versions);
|
||||
} else {
|
||||
reject("Missing or improper 'engines' property in 'package.json'");
|
||||
reject("Missing or improper 'engines' property in 'package.json'");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
|
||||
const checkNpmVersion = (engines) =>
|
||||
new Promise((resolve, reject) => {
|
||||
exec("npm -v", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(`Unable to find NPM version\n${stderr}`);
|
||||
}
|
||||
if (error) {
|
||||
reject(`Unable to find NPM version\n${stderr}`);
|
||||
}
|
||||
|
||||
const npmVersion = stdout.trim();
|
||||
const engineVersion = engines.npm || ">=0";
|
||||
const npmVersion = stdout.trim();
|
||||
const engineVersion = engines.npm || ">=0";
|
||||
|
||||
if (semver.satisfies(npmVersion, engineVersion)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
|
||||
}
|
||||
if (semver.satisfies(npmVersion, engineVersion)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(
|
||||
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
|
||||
const checkNodeVersion = (engines) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const nodeVersion = process.version.substring(1);
|
||||
|
||||
if (semver.satisfies(nodeVersion, engines.node)) {
|
||||
resolve(engines);
|
||||
resolve(engines);
|
||||
} else {
|
||||
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
|
||||
reject(
|
||||
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
getPackageJson()
|
||||
.then(getEngines)
|
||||
.then(checkNodeVersion)
|
||||
.then(checkNpmVersion)
|
||||
.then(
|
||||
() => true,
|
||||
(error) => {
|
||||
// Specifically disable these as the error message gets lost in the normal unhandled output.
|
||||
/* eslint-disable no-console, no-process-exit */
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
);
|
||||
.then(getEngines)
|
||||
.then(checkNodeVersion)
|
||||
.then(checkNpmVersion)
|
||||
.then(
|
||||
() => true,
|
||||
(error) => {
|
||||
// Specifically disable these as the error message gets lost in the normal unhandled output.
|
||||
/* eslint-disable no-console, no-process-exit */
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
},
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -533,6 +533,7 @@ export class Augmentation {
|
||||
console.warn(`Invalid Faction object in addToAllFactions(). Key value: ${fac}`);
|
||||
continue;
|
||||
}
|
||||
if (facObj.getInfo().special) continue;
|
||||
facObj.augmentations.push(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2366,6 +2366,145 @@ function initAugmentations(): void {
|
||||
resetAugmentation(BladesSimulacrum);
|
||||
}
|
||||
|
||||
// Special CotMG Augmentations
|
||||
const ChurchOfTheMachineGodFactionName = "Church of the Machine God";
|
||||
if (factionExists(ChurchOfTheMachineGodFactionName)) {
|
||||
const StaneksGift1 = new Augmentation({
|
||||
name: AugmentationNames.StaneksGift1,
|
||||
repCost: 0,
|
||||
moneyCost: 0,
|
||||
info:
|
||||
'Allison "Mother" Stanek imparts you with her gift. An ' +
|
||||
"experimental Augmentation implanted at the base of the neck. " +
|
||||
"It allows you to overclock your entire system by carefully " +
|
||||
"changing the configuration.",
|
||||
isSpecial: true,
|
||||
hacking_chance_mult: 0.9,
|
||||
hacking_speed_mult: 0.9,
|
||||
hacking_money_mult: 0.9,
|
||||
hacking_grow_mult: 0.9,
|
||||
hacking_mult: 0.9,
|
||||
strength_mult: 0.9,
|
||||
defense_mult: 0.9,
|
||||
dexterity_mult: 0.9,
|
||||
agility_mult: 0.9,
|
||||
charisma_mult: 0.9,
|
||||
hacking_exp_mult: 0.9,
|
||||
strength_exp_mult: 0.9,
|
||||
defense_exp_mult: 0.9,
|
||||
dexterity_exp_mult: 0.9,
|
||||
agility_exp_mult: 0.9,
|
||||
charisma_exp_mult: 0.9,
|
||||
company_rep_mult: 0.9,
|
||||
faction_rep_mult: 0.9,
|
||||
crime_money_mult: 0.9,
|
||||
crime_success_mult: 0.9,
|
||||
hacknet_node_money_mult: 0.9,
|
||||
hacknet_node_purchase_cost_mult: 1.1,
|
||||
hacknet_node_ram_cost_mult: 1.1,
|
||||
hacknet_node_core_cost_mult: 1.1,
|
||||
hacknet_node_level_cost_mult: 1.1,
|
||||
work_money_mult: 0.9,
|
||||
stats: <>Its unstable nature decreases all your stats by 10%</>,
|
||||
});
|
||||
StaneksGift1.addToFactions([ChurchOfTheMachineGodFactionName]);
|
||||
resetAugmentation(StaneksGift1);
|
||||
|
||||
const StaneksGift2 = new Augmentation({
|
||||
name: AugmentationNames.StaneksGift2,
|
||||
repCost: 1000,
|
||||
moneyCost: 0,
|
||||
info:
|
||||
'TODO, something about Mother being bullshit and you get more control over her "gift"<br><br>' +
|
||||
"The penalty for the gift is only 5%",
|
||||
prereqs: [AugmentationNames.StaneksGift1],
|
||||
isSpecial: true,
|
||||
hacking_chance_mult: 0.95 / 0.9,
|
||||
hacking_speed_mult: 0.95 / 0.9,
|
||||
hacking_money_mult: 0.95 / 0.9,
|
||||
hacking_grow_mult: 0.95 / 0.9,
|
||||
hacking_mult: 0.95 / 0.9,
|
||||
strength_mult: 0.95 / 0.9,
|
||||
defense_mult: 0.95 / 0.9,
|
||||
dexterity_mult: 0.95 / 0.9,
|
||||
agility_mult: 0.95 / 0.9,
|
||||
charisma_mult: 0.95 / 0.9,
|
||||
hacking_exp_mult: 0.95 / 0.9,
|
||||
strength_exp_mult: 0.95 / 0.9,
|
||||
defense_exp_mult: 0.95 / 0.9,
|
||||
dexterity_exp_mult: 0.95 / 0.9,
|
||||
agility_exp_mult: 0.95 / 0.9,
|
||||
charisma_exp_mult: 0.95 / 0.9,
|
||||
company_rep_mult: 0.95 / 0.9,
|
||||
faction_rep_mult: 0.95 / 0.9,
|
||||
crime_money_mult: 0.95 / 0.9,
|
||||
crime_success_mult: 0.95 / 0.9,
|
||||
hacknet_node_money_mult: 0.95 / 0.9,
|
||||
hacknet_node_purchase_cost_mult: 1.05 / 1.1,
|
||||
hacknet_node_ram_cost_mult: 1.05 / 1.1,
|
||||
hacknet_node_core_cost_mult: 1.05 / 1.1,
|
||||
hacknet_node_level_cost_mult: 1.05 / 1.1,
|
||||
work_money_mult: 0.95 / 0.9,
|
||||
stats: null,
|
||||
});
|
||||
StaneksGift2.addToFactions([ChurchOfTheMachineGodFactionName]);
|
||||
resetAugmentation(StaneksGift2);
|
||||
|
||||
const StaneksGift3 = new Augmentation({
|
||||
name: AugmentationNames.StaneksGift3,
|
||||
repCost: 10000,
|
||||
moneyCost: 0,
|
||||
info:
|
||||
"TODO, learn more about Allisons scheme, gain full control over the gift.<br><br>" +
|
||||
"Finally freed from the penalty of the gift.",
|
||||
prereqs: [AugmentationNames.StaneksGift2],
|
||||
isSpecial: true,
|
||||
hacking_chance_mult: 1 / 0.95,
|
||||
hacking_speed_mult: 1 / 0.95,
|
||||
hacking_money_mult: 1 / 0.95,
|
||||
hacking_grow_mult: 1 / 0.95,
|
||||
hacking_mult: 1 / 0.95,
|
||||
strength_mult: 1 / 0.95,
|
||||
defense_mult: 1 / 0.95,
|
||||
dexterity_mult: 1 / 0.95,
|
||||
agility_mult: 1 / 0.95,
|
||||
charisma_mult: 1 / 0.95,
|
||||
hacking_exp_mult: 1 / 0.95,
|
||||
strength_exp_mult: 1 / 0.95,
|
||||
defense_exp_mult: 1 / 0.95,
|
||||
dexterity_exp_mult: 1 / 0.95,
|
||||
agility_exp_mult: 1 / 0.95,
|
||||
charisma_exp_mult: 1 / 0.95,
|
||||
company_rep_mult: 1 / 0.95,
|
||||
faction_rep_mult: 1 / 0.95,
|
||||
crime_money_mult: 1 / 0.95,
|
||||
crime_success_mult: 1 / 0.95,
|
||||
hacknet_node_money_mult: 1 / 0.95,
|
||||
hacknet_node_purchase_cost_mult: 1 / 1.05,
|
||||
hacknet_node_ram_cost_mult: 1 / 1.05,
|
||||
hacknet_node_core_cost_mult: 1 / 1.05,
|
||||
hacknet_node_level_cost_mult: 1 / 1.05,
|
||||
work_money_mult: 1 / 0.95,
|
||||
stats: null,
|
||||
});
|
||||
StaneksGift3.addToFactions([ChurchOfTheMachineGodFactionName]);
|
||||
resetAugmentation(StaneksGift3);
|
||||
|
||||
const StaneksGiftAscension4 = new Augmentation({
|
||||
name: AugmentationNames.StaneksGift4,
|
||||
repCost: 500000000,
|
||||
moneyCost: 0,
|
||||
info:
|
||||
"Allow Allison to install an Ascension port in her Gift. Allowing you to connect with the Machine God.<br><br>" +
|
||||
"(hydro notes: Finishes the BN, eventually)",
|
||||
prereqs: [AugmentationNames.StaneksGift3],
|
||||
isSpecial: true,
|
||||
stats: null,
|
||||
});
|
||||
StaneksGiftAscension4.addToFactions([ChurchOfTheMachineGodFactionName]);
|
||||
resetAugmentation(StaneksGiftAscension4);
|
||||
}
|
||||
|
||||
// Update costs based on how many have been purchased
|
||||
mult = Math.pow(
|
||||
CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]],
|
||||
|
||||
@@ -1,6 +1,118 @@
|
||||
import { IMap } from "../../types";
|
||||
|
||||
export const AugmentationNames: IMap<string> = {
|
||||
export const AugmentationNames: {
|
||||
Targeting1: string;
|
||||
Targeting2: string;
|
||||
Targeting3: string;
|
||||
SyntheticHeart: string;
|
||||
SynfibrilMuscle: string;
|
||||
CombatRib1: string;
|
||||
CombatRib2: string;
|
||||
CombatRib3: string;
|
||||
NanofiberWeave: string;
|
||||
SubdermalArmor: string;
|
||||
WiredReflexes: string;
|
||||
GrapheneBoneLacings: string;
|
||||
BionicSpine: string;
|
||||
GrapheneBionicSpine: string;
|
||||
BionicLegs: string;
|
||||
GrapheneBionicLegs: string;
|
||||
SpeechProcessor: string;
|
||||
TITN41Injection: string;
|
||||
EnhancedSocialInteractionImplant: string;
|
||||
BitWire: string;
|
||||
ArtificialBioNeuralNetwork: string;
|
||||
ArtificialSynapticPotentiation: string;
|
||||
EnhancedMyelinSheathing: string;
|
||||
SynapticEnhancement: string;
|
||||
NeuralRetentionEnhancement: string;
|
||||
DataJack: string;
|
||||
ENM: string;
|
||||
ENMCore: string;
|
||||
ENMCoreV2: string;
|
||||
ENMCoreV3: string;
|
||||
ENMAnalyzeEngine: string;
|
||||
ENMDMA: string;
|
||||
Neuralstimulator: string;
|
||||
NeuralAccelerator: string;
|
||||
CranialSignalProcessorsG1: string;
|
||||
CranialSignalProcessorsG2: string;
|
||||
CranialSignalProcessorsG3: string;
|
||||
CranialSignalProcessorsG4: string;
|
||||
CranialSignalProcessorsG5: string;
|
||||
NeuronalDensification: string;
|
||||
NeuroreceptorManager: string;
|
||||
NuoptimalInjectorImplant: string;
|
||||
SpeechEnhancement: string;
|
||||
FocusWire: string;
|
||||
PCDNI: string;
|
||||
PCDNIOptimizer: string;
|
||||
PCDNINeuralNetwork: string;
|
||||
PCMatrix: string;
|
||||
ADRPheromone1: string;
|
||||
ADRPheromone2: string;
|
||||
ShadowsSimulacrum: string;
|
||||
HacknetNodeCPUUpload: string;
|
||||
HacknetNodeCacheUpload: string;
|
||||
HacknetNodeNICUpload: string;
|
||||
HacknetNodeKernelDNI: string;
|
||||
HacknetNodeCoreDNI: string;
|
||||
NeuroFluxGovernor: string;
|
||||
Neurotrainer1: string;
|
||||
Neurotrainer2: string;
|
||||
Neurotrainer3: string;
|
||||
Hypersight: string;
|
||||
LuminCloaking1: string;
|
||||
LuminCloaking2: string;
|
||||
HemoRecirculator: string;
|
||||
SmartSonar: string;
|
||||
PowerRecirculator: string;
|
||||
QLink: string;
|
||||
TheRedPill: string;
|
||||
SPTN97: string;
|
||||
HiveMind: string;
|
||||
CordiARCReactor: string;
|
||||
SmartJaw: string;
|
||||
Neotra: string;
|
||||
Xanipher: string;
|
||||
nextSENS: string;
|
||||
OmniTekInfoLoad: string;
|
||||
PhotosyntheticCells: string;
|
||||
Neurolink: string;
|
||||
TheBlackHand: string;
|
||||
UnstableCircadianModulator: string;
|
||||
CRTX42AA: string;
|
||||
Neuregen: string;
|
||||
CashRoot: string;
|
||||
NutriGen: string;
|
||||
INFRARet: string;
|
||||
DermaForce: string;
|
||||
GrapheneBrachiBlades: string;
|
||||
GrapheneBionicArms: string;
|
||||
BrachiBlades: string;
|
||||
BionicArms: string;
|
||||
SNA: string;
|
||||
HydroflameLeftArm: string;
|
||||
EsperEyewear: string;
|
||||
EMS4Recombination: string;
|
||||
OrionShoulder: string;
|
||||
HyperionV1: string;
|
||||
HyperionV2: string;
|
||||
GolemSerum: string;
|
||||
VangelisVirus: string;
|
||||
VangelisVirus3: string;
|
||||
INTERLINKED: string;
|
||||
BladeRunner: string;
|
||||
BladeArmor: string;
|
||||
BladeArmorPowerCells: string;
|
||||
BladeArmorEnergyShielding: string;
|
||||
BladeArmorUnibeam: string;
|
||||
BladeArmorOmnibeam: string;
|
||||
BladeArmorIPU: string;
|
||||
BladesSimulacrum: string;
|
||||
StaneksGift1: string;
|
||||
StaneksGift2: string;
|
||||
StaneksGift3: string;
|
||||
StaneksGift4: string;
|
||||
} = {
|
||||
Targeting1: "Augmented Targeting I",
|
||||
Targeting2: "Augmented Targeting II",
|
||||
Targeting3: "Augmented Targeting III",
|
||||
@@ -87,7 +199,7 @@ export const AugmentationNames: IMap<string> = {
|
||||
NutriGen: "NutriGen Implant",
|
||||
INFRARet: "INFRARET Enhancement",
|
||||
DermaForce: "DermaForce Particle Barrier",
|
||||
GrapheneBrachiBlades: "Graphene BranchiBlades Upgrade",
|
||||
GrapheneBrachiBlades: "Graphene BrachiBlades Upgrade",
|
||||
GrapheneBionicArms: "Graphene Bionic Arms Upgrade",
|
||||
BrachiBlades: "BrachiBlades",
|
||||
BionicArms: "Bionic Arms",
|
||||
@@ -111,6 +223,11 @@ export const AugmentationNames: IMap<string> = {
|
||||
BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade",
|
||||
BladesSimulacrum: "The Blade's Simulacrum",
|
||||
|
||||
StaneksGift1: "Stanek's Gift - Genesis",
|
||||
StaneksGift2: "Stanek's Gift - Awakening",
|
||||
StaneksGift3: "Stanek's Gift - Serenity",
|
||||
StaneksGift4: "Stanek's Gift - Ascension",
|
||||
|
||||
//Wasteland Augs
|
||||
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System
|
||||
//PepBoyForceField Generates plasma force fields
|
||||
|
||||
@@ -396,6 +396,15 @@ BitNodes["BitNode9"] = new BitNode(
|
||||
<br />
|
||||
(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT when installing
|
||||
Augmentations)
|
||||
<br />
|
||||
<br />
|
||||
This Source-File also increases your hacknet multipliers by:
|
||||
<br />
|
||||
Level 1: 8%
|
||||
<br />
|
||||
Level 2: 12%
|
||||
<br />
|
||||
Level 3: 14%
|
||||
</>
|
||||
),
|
||||
);
|
||||
@@ -521,8 +530,38 @@ BitNodes["BitNode12"] = new BitNode(
|
||||
</>
|
||||
),
|
||||
);
|
||||
BitNodes["BitNode13"] = new BitNode(
|
||||
13,
|
||||
2,
|
||||
"They're lunatics",
|
||||
"1 step back, 2 steps forward",
|
||||
(
|
||||
<>
|
||||
With the invention of Augmentations in the 2040s a religious group known as the Church of the Machine God has
|
||||
rallied far more support than anyone would have hoped.
|
||||
<br />
|
||||
<br />
|
||||
Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any
|
||||
other. Find her in Chongquing and gain her trust.
|
||||
<br />
|
||||
<br />
|
||||
In this BitNode:
|
||||
<br />
|
||||
<br />
|
||||
Every is significantly reduced
|
||||
<br />
|
||||
Stanek's Gift power is significantly increased.
|
||||
<br />
|
||||
<br />
|
||||
Destroying this BitNode will give you Source-File 13, or if you already have this Source-File it will upgrade its
|
||||
level up to a maximum of 3. This Source-File lets the Church of the Machine God appear in other BitNodes.
|
||||
<br />
|
||||
<br />
|
||||
Each level of this Source-File increases the size of Stanek's Gift.
|
||||
</>
|
||||
),
|
||||
);
|
||||
// Books: Frontera, Shiner
|
||||
BitNodes["BitNode13"] = new BitNode(13, 2, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
|
||||
BitNodes["BitNode14"] = new BitNode(14, 2, "", "COMING SOON");
|
||||
BitNodes["BitNode15"] = new BitNode(15, 2, "", "COMING SOON");
|
||||
BitNodes["BitNode16"] = new BitNode(16, 2, "", "COMING SOON");
|
||||
@@ -544,6 +583,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers[mult] = 1;
|
||||
}
|
||||
}
|
||||
// Special case.
|
||||
BitNodeMultipliers.StaneksGiftExtraSize = 0;
|
||||
|
||||
switch (p.bitNodeN) {
|
||||
case 1: // Source Genesis (every multiplier is 1)
|
||||
@@ -784,6 +825,47 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.BladeburnerSkillCost = inc;
|
||||
break;
|
||||
}
|
||||
case 13: {
|
||||
BitNodeMultipliers.DaedalusAugsRequirement = 100;
|
||||
|
||||
BitNodeMultipliers.HackingLevelMultiplier = 0.2;
|
||||
BitNodeMultipliers.StrengthLevelMultiplier = 0.2;
|
||||
BitNodeMultipliers.DefenseLevelMultiplier = 0.2;
|
||||
BitNodeMultipliers.DexterityLevelMultiplier = 0.2;
|
||||
BitNodeMultipliers.AgilityLevelMultiplier = 0.2;
|
||||
BitNodeMultipliers.CharismaLevelMultiplier = 0.2;
|
||||
|
||||
BitNodeMultipliers.ServerMaxMoney = 0.15;
|
||||
BitNodeMultipliers.ServerStartingMoney = 0.75;
|
||||
|
||||
BitNodeMultipliers.ServerStartingSecurity = 2;
|
||||
|
||||
BitNodeMultipliers.ScriptHackMoney = 0.2;
|
||||
BitNodeMultipliers.CompanyWorkMoney = 0.2;
|
||||
BitNodeMultipliers.CrimeMoney = 0.2;
|
||||
BitNodeMultipliers.HacknetNodeMoney = 0.2;
|
||||
BitNodeMultipliers.CodingContractMoney = 0.2;
|
||||
|
||||
BitNodeMultipliers.CompanyWorkExpGain = 0.1;
|
||||
BitNodeMultipliers.ClassGymExpGain = 0.1;
|
||||
BitNodeMultipliers.FactionWorkExpGain = 0.1;
|
||||
BitNodeMultipliers.HackExpGain = 0.1;
|
||||
BitNodeMultipliers.CrimeExpGain = 0.1;
|
||||
|
||||
BitNodeMultipliers.FactionWorkRepGain = 0.4;
|
||||
|
||||
BitNodeMultipliers.FourSigmaMarketDataCost = 10;
|
||||
BitNodeMultipliers.FourSigmaMarketDataApiCost = 10;
|
||||
|
||||
BitNodeMultipliers.CorporationValuation = 0.001;
|
||||
|
||||
BitNodeMultipliers.BladeburnerRank = 0.1;
|
||||
BitNodeMultipliers.BladeburnerSkillCost = 5;
|
||||
BitNodeMultipliers.GangKarmaRequirement = 20;
|
||||
BitNodeMultipliers.StaneksGiftPowerMultiplier = 2;
|
||||
BitNodeMultipliers.StaneksGiftExtraSize = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.warn("Player.bitNodeN invalid");
|
||||
break;
|
||||
|
||||
@@ -212,6 +212,16 @@ interface IBitNodeMultipliers {
|
||||
*/
|
||||
StrengthLevelMultiplier: number;
|
||||
|
||||
/**
|
||||
* Influences the power of the gift.
|
||||
*/
|
||||
StaneksGiftPowerMultiplier: number;
|
||||
|
||||
/**
|
||||
* Influences the size of the gift.
|
||||
*/
|
||||
StaneksGiftExtraSize: number;
|
||||
|
||||
// Index signature
|
||||
[key: string]: number;
|
||||
}
|
||||
@@ -274,4 +284,7 @@ export const BitNodeMultipliers: IBitNodeMultipliers = {
|
||||
|
||||
DaedalusAugsRequirement: 1,
|
||||
GangKarmaRequirement: 1,
|
||||
|
||||
StaneksGiftPowerMultiplier: 1,
|
||||
StaneksGiftExtraSize: 0,
|
||||
};
|
||||
|
||||
@@ -160,7 +160,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ O \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
|
||||
@@ -1960,6 +1960,18 @@ export class Bladeburner implements IBladeburner {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const gen = [
|
||||
"Training",
|
||||
"Recruitment",
|
||||
"FieldAnalysis",
|
||||
"Field Analysis",
|
||||
"Diplomacy",
|
||||
"Hyperbolic Regeneration Chamber",
|
||||
];
|
||||
if (gen.includes(res.type)) {
|
||||
res.type = "General";
|
||||
}
|
||||
|
||||
if (res.type == null) {
|
||||
res.type = "Idle";
|
||||
}
|
||||
|
||||
@@ -6,11 +6,10 @@ import {
|
||||
} from "./CodingContracts";
|
||||
import { Factions } from "./Faction/Factions";
|
||||
import { Player } from "./Player";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { GetServerByHostname } from "./Server/ServerHelpers";
|
||||
import { SpecialServerNames } from "./Server/SpecialServerIps";
|
||||
import { GetServer, GetAllServers } from "./Server/AllServers";
|
||||
import { SpecialServers } from "./Server/data/SpecialServers";
|
||||
import { Server } from "./Server/Server";
|
||||
import { HacknetServer } from "./Hacknet/HacknetServer";
|
||||
import { BaseServer } from "./Server/BaseServer";
|
||||
|
||||
import { getRandomInt } from "./utils/helpers/getRandomInt";
|
||||
|
||||
@@ -68,10 +67,7 @@ export function generateContract(params: IGenerateContractParams): void {
|
||||
// Server
|
||||
let server;
|
||||
if (params.server != null) {
|
||||
server = GetServerByHostname(params.server);
|
||||
if (server == null) {
|
||||
server = AllServers[params.server];
|
||||
}
|
||||
server = GetServer(params.server);
|
||||
if (server == null) {
|
||||
server = getRandomServer();
|
||||
}
|
||||
@@ -165,10 +161,10 @@ function getRandomReward(): ICodingContractReward {
|
||||
return reward;
|
||||
}
|
||||
|
||||
function getRandomServer(): Server | HacknetServer {
|
||||
const servers = Object.keys(AllServers);
|
||||
function getRandomServer(): BaseServer {
|
||||
const servers = GetAllServers();
|
||||
let randIndex = getRandomInt(0, servers.length - 1);
|
||||
let randServer = AllServers[servers[randIndex]];
|
||||
let randServer = servers[randIndex];
|
||||
|
||||
// An infinite loop shouldn't ever happen, but to be safe we'll use
|
||||
// a for loop with a limited number of tries
|
||||
@@ -176,18 +172,18 @@ function getRandomServer(): Server | HacknetServer {
|
||||
if (
|
||||
randServer instanceof Server &&
|
||||
!randServer.purchasedByPlayer &&
|
||||
randServer.hostname !== SpecialServerNames.WorldDaemon
|
||||
randServer.hostname !== SpecialServers.WorldDaemon
|
||||
) {
|
||||
break;
|
||||
}
|
||||
randIndex = getRandomInt(0, servers.length - 1);
|
||||
randServer = AllServers[servers[randIndex]];
|
||||
randServer = servers[randIndex];
|
||||
}
|
||||
|
||||
return randServer;
|
||||
}
|
||||
|
||||
function getRandomFilename(server: Server | HacknetServer, reward: ICodingContractReward): string {
|
||||
function getRandomFilename(server: BaseServer, reward: ICodingContractReward): string {
|
||||
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
|
||||
|
||||
for (let i = 0; i < 1000; ++i) {
|
||||
|
||||
116
src/Constants.ts
116
src/Constants.ts
@@ -114,7 +114,7 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: number;
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
Version: "0.55.0",
|
||||
Version: "0.56.0",
|
||||
|
||||
// Speed (in ms) at which the main loop is updated
|
||||
_idleSpeed: 200,
|
||||
@@ -281,31 +281,107 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
LatestUpdate: `
|
||||
v0.55.0 - 2021-09-20 Material UI (hydroflame & community)
|
||||
v0.56.0 - 2021-10-11 Trimming the backlog (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
** Global **
|
||||
** BREAKING **
|
||||
|
||||
* The game is now 100% in typescript, react, and Material-UI
|
||||
* The 'write' function is now async. This helps when making scripts that write scripts.
|
||||
|
||||
** Terminal **
|
||||
|
||||
* 'grow' and 'weaken' have been added as terminal command. This should help player transition
|
||||
from commands to scripts. The tutorial also talks about it.
|
||||
* 'cp' command added
|
||||
* Improved performance by rate limiting refresh.
|
||||
|
||||
** IP vs Hostname **
|
||||
|
||||
* The game now uses hostname as primary key for it's servers (yeah believe it or not IPs were
|
||||
used until then). This has caused some issues with purchased servers (they couldn't be sold).
|
||||
You might need to soft reset for the game to fully convert itself.
|
||||
|
||||
** Sleeve **
|
||||
|
||||
* Fixed bug where they couldn't train at Volhaven.
|
||||
* No longer consume all bonus time at once, making it look buggy.
|
||||
|
||||
** SF9 **
|
||||
|
||||
* Now boosts hacknet production by 8/12/14%
|
||||
|
||||
** Hacknet Servers **
|
||||
|
||||
* production nerfed by 10%
|
||||
* Max money increase gets weaker above 10t max money
|
||||
|
||||
** Corporation **
|
||||
|
||||
* Warehouse tooltip now also displays the amount of space taken by products.
|
||||
* Changed research box completely to avoid dependency on Treant (Treant is a pita)
|
||||
* All textbox should accept MAX/MP case insensitive.
|
||||
* Fixed export popup not refreshing dropdowns correctly.
|
||||
* Fixed product mku becoming zero
|
||||
* Increased scaling of Wilson to avoid feedback loop.
|
||||
* Can no longer get in debt by buying real estate
|
||||
* Bonus time is consumed faster.
|
||||
|
||||
** Netscript **
|
||||
|
||||
* isBusy takes bitverse and infiltration into account
|
||||
* hospitalize can't be called when in infiltration.
|
||||
* setToCommitCrime now accepts crime rough name instead of perfect name.
|
||||
* disableLog All now works for bladeburner functions.
|
||||
* Fixed netscript port for ns1.
|
||||
|
||||
** Augmentation **
|
||||
|
||||
* Added augmentation to Ti Di Hui that removes penalty for being unfocused.
|
||||
* Neuroflux no longer appears in special factions.
|
||||
|
||||
** Script Editor **
|
||||
|
||||
* Ram check is debounced instead of refreshed every second.
|
||||
* Added the vscode extension documentation to the game (it doesn't work well, thought)
|
||||
* Fixed issue where autocomplete list would grow forever
|
||||
* Added semi-monokai as theme.
|
||||
* Fixed issue where modifying filename would mess it up.
|
||||
* Font size can be changed now.
|
||||
|
||||
** Infiltration **
|
||||
|
||||
* Fixed issue where game controls would become unfocused.
|
||||
|
||||
** Misc. **
|
||||
|
||||
* Corporations can no longer bribe special factions
|
||||
* Infiltration can no longer lose focus of the keyboard.
|
||||
* Fix terminal line limit
|
||||
* Added theme editor
|
||||
* Theme applies on game load (@Nolshine)
|
||||
* Sleeves no longer consume all bonus time for some actions
|
||||
* Fix a bug where the autocomlete list would get duplicates
|
||||
* Fix tutorial not scaling properly on small screens
|
||||
* Import should be more consistent
|
||||
* Typo with 'help' command
|
||||
* Fix infinite loop in casino
|
||||
* Fixed loader incorrectly assuming some null values are incorrect.
|
||||
* installBackdoor trigger Bitverse sequence
|
||||
* Some improvements to the theme editor
|
||||
* Improved documentation about where to learn javascript.
|
||||
* Added some instructions for contributors.
|
||||
* Fixed typo in corporation sell shares modal (@Saynt_Garmo)
|
||||
* Fixed pagination being black on black in Active Scripts
|
||||
* Create Script tab renamed to Script Editor
|
||||
* Fixed an issue where corp some textbox wouldn't update when changing city.
|
||||
* Fixed an issue where hacknet online time was always 0.
|
||||
* Netscript function prompt fixed.
|
||||
* Fixed miscalculation in growth.
|
||||
* Script with syntax errors will try to be a tad more helpful.
|
||||
* Corporations can no longer bribe bladeburners.
|
||||
* Augmentation Graphene Branchiblade renamed to Brachi, like the rest of them.
|
||||
* All ram is displayed in GB/TB/PB now.
|
||||
* Game now saves when saving a file, this can be turned off.
|
||||
* Several improvement to log window.
|
||||
* Bladeburner current action returns General type instead of the name of the action.
|
||||
* Bladeburner travel and Sleeve travel respect disable ASCII.
|
||||
* Tutorial fits on small screens.
|
||||
* Import is much slower but more consistent now.
|
||||
* Fix intelligence not updating properly.
|
||||
* Added SF -1: Time Compression
|
||||
* ReadTheDoc theme now matches the game.
|
||||
* Logbox should wrap text better
|
||||
* Logbox behavior should feel better.
|
||||
* Fix font for AutoLink.exe
|
||||
* nerf noodle bar
|
||||
`,
|
||||
|
||||
/*
|
||||
|
||||
|
||||
*/
|
||||
};
|
||||
|
||||
@@ -105,6 +105,7 @@ export function SellMaterial(mat: Material, amt: string, price: string): void {
|
||||
}
|
||||
|
||||
//Parse quantity
|
||||
amt = amt.toUpperCase();
|
||||
if (amt.includes("MAX") || amt.includes("PROD")) {
|
||||
let q = amt.replace(/\s+/g, "");
|
||||
q = q.replace(/[^-()\d/*+.MAXPROD]/g, "");
|
||||
@@ -168,6 +169,7 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
const cities = Object.keys(Cities);
|
||||
|
||||
// Parse quantity
|
||||
amt = amt.toUpperCase();
|
||||
if (amt.includes("MAX") || amt.includes("PROD")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
let qty = amt.replace(/\s+/g, "");
|
||||
@@ -372,7 +374,7 @@ export function Research(division: IIndustry, researchName: string): void {
|
||||
|
||||
export function ExportMaterial(divisionName: string, cityName: string, material: Material, amt: string): void {
|
||||
// Sanitize amt
|
||||
let sanitizedAmt = amt.replace(/\s+/g, "");
|
||||
let sanitizedAmt = amt.replace(/\s+/g, "").toUpperCase();
|
||||
sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, "");
|
||||
let temp = sanitizedAmt.replace(/MAX/g, "1");
|
||||
try {
|
||||
|
||||
@@ -564,7 +564,7 @@ export class Industry implements IIndustry {
|
||||
buyAmt = mat.buy * CorporationConstants.SecsPerMarketCycle * marketCycles;
|
||||
|
||||
if (matName == "RealEstate") {
|
||||
maxAmt = buyAmt;
|
||||
maxAmt = corporation.funds.toNumber() / mat.bCost;
|
||||
} else {
|
||||
maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / MaterialSizes[matName]);
|
||||
}
|
||||
@@ -840,7 +840,7 @@ export class Industry implements IIndustry {
|
||||
let sellAmt;
|
||||
if (isString(mat.sllman[1])) {
|
||||
//Dynamically evaluated
|
||||
let tmp = (mat.sllman[1] as string).replace(/MAX/g, maxSell + "");
|
||||
let tmp = (mat.sllman[1] as string).replace(/MAX/g, (maxSell + "").toUpperCase());
|
||||
tmp = tmp.replace(/PROD/g, mat.prd + "");
|
||||
try {
|
||||
sellAmt = eval(tmp);
|
||||
@@ -893,7 +893,7 @@ export class Industry implements IIndustry {
|
||||
const exp = mat.exp[expI];
|
||||
const amtStr = exp.amt.replace(
|
||||
/MAX/g,
|
||||
mat.qty / (CorporationConstants.SecsPerMarketCycle * marketCycles) + "",
|
||||
(mat.qty / (CorporationConstants.SecsPerMarketCycle * marketCycles) + "").toUpperCase(),
|
||||
);
|
||||
let amt = 0;
|
||||
try {
|
||||
@@ -1201,7 +1201,7 @@ export class Industry implements IIndustry {
|
||||
let sellAmt;
|
||||
if (product.sllman[city][0] && isString(product.sllman[city][1])) {
|
||||
//Sell amount is dynamically evaluated
|
||||
let tmp = product.sllman[city][1].replace(/MAX/g, maxSell);
|
||||
let tmp = product.sllman[city][1].replace(/MAX/g, (maxSell + "").toUpperCase());
|
||||
tmp = tmp.replace(/PROD/g, product.data[city][1]);
|
||||
try {
|
||||
tmp = eval(tmp);
|
||||
|
||||
@@ -185,11 +185,12 @@ export class Product {
|
||||
0.05 * employeeProd[EmployeePositions.Business]);
|
||||
this.calculateRating(industry);
|
||||
const advMult = 1 + Math.pow(this.advCost, 0.1) / 100;
|
||||
this.mku = 100 / (advMult * Math.pow(this.qlt + 0.001, 0.65) * (busRatio + mgmtRatio));
|
||||
const busmgtgRatio = Math.max(busRatio + mgmtRatio, 1 / employeeProd["total"]);
|
||||
this.mku = 100 / (advMult * Math.pow(this.qlt + 0.001, 0.65) * busmgtgRatio);
|
||||
|
||||
// I actually don't understand well enough to know if this is right.
|
||||
// I'm adding this to prevent a crash.
|
||||
if (this.mku === 0) this.mku = 1;
|
||||
if (this.mku === 0 || !isFinite(this.mku)) this.mku = 1;
|
||||
|
||||
this.dmd =
|
||||
industry.awareness === 0 ? 20 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness)));
|
||||
|
||||
@@ -47,7 +47,7 @@ export const CorporationUpgrades: IMap<CorporationUpgrade> = {
|
||||
"3": [
|
||||
3,
|
||||
4e9,
|
||||
1.12,
|
||||
1.5,
|
||||
0.005,
|
||||
"Wilson Analytics",
|
||||
"Purchase data and analysis from Wilson, a marketing research " +
|
||||
|
||||
@@ -38,7 +38,13 @@ export function CityTabs(props: IProps): React.ReactElement {
|
||||
</Tabs>
|
||||
|
||||
{city !== "Expand" ? (
|
||||
<Industry rerender={props.rerender} city={city} warehouse={division.warehouses[city]} office={office} />
|
||||
<Industry
|
||||
key={city}
|
||||
rerender={props.rerender}
|
||||
city={city}
|
||||
warehouse={division.warehouses[city]}
|
||||
office={office}
|
||||
/>
|
||||
) : (
|
||||
<ExpandNewCity cityStateSetter={setCity} />
|
||||
)}
|
||||
|
||||
@@ -80,10 +80,20 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
|
||||
<Typography>Division name:</Typography>
|
||||
|
||||
<Box display="flex" alignItems="center">
|
||||
<TextField autoFocus={true} value={name} onChange={onNameChange} onKeyDown={onKeyDown} type="text" />
|
||||
<Button disabled={disabled} sx={{ mx: 1 }} onClick={newIndustry}>
|
||||
Create Division
|
||||
</Button>
|
||||
<TextField
|
||||
autoFocus={true}
|
||||
value={name}
|
||||
onChange={onNameChange}
|
||||
onKeyDown={onKeyDown}
|
||||
type="text"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<Button disabled={disabled} sx={{ mx: 1 }} onClick={newIndustry}>
|
||||
Expand
|
||||
</Button>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -43,16 +43,21 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
|
||||
Would you like to expand into a new city by opening an office? This would cost{" "}
|
||||
<MoneyCost money={CorporationConstants.OfficeInitialCost} corp={corp} />
|
||||
</Typography>
|
||||
<Select value={city} onChange={onCityChange}>
|
||||
<Select
|
||||
endAdornment={
|
||||
<Button onClick={expand} disabled={disabled}>
|
||||
Confirm
|
||||
</Button>
|
||||
}
|
||||
value={city}
|
||||
onChange={onCityChange}
|
||||
>
|
||||
{possibleCities.map((cityName: string) => (
|
||||
<MenuItem key={cityName} value={cityName}>
|
||||
{cityName}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Button onClick={expand} disabled={disabled}>
|
||||
Confirm
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ export function ExportModal(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function onIndustryChange(event: SelectChangeEvent<string>): void {
|
||||
setIndustry(event.target.value);
|
||||
const div = event.target.value;
|
||||
setIndustry(div);
|
||||
setCity(Object.keys(corp.divisions[0].warehouses)[0]);
|
||||
}
|
||||
|
||||
function onAmtChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
|
||||
@@ -8,8 +8,7 @@ import { IndustryUpgrades } from "../IndustryUpgrades";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import { MakeProductModal } from "./MakeProductModal";
|
||||
import { ResearchPopup } from "./ResearchPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { ResearchModal } from "./ResearchModal";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
import { StatsTable } from "../../ui/React/StatsTable";
|
||||
@@ -96,6 +95,7 @@ function Text(): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const division = useDivision();
|
||||
const [helpOpen, setHelpOpen] = useState(false);
|
||||
const [researchOpen, setResearchOpen] = useState(false);
|
||||
const vechain = corp.unlockUpgrades[4] === 1;
|
||||
const profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber();
|
||||
|
||||
@@ -116,14 +116,6 @@ function Text(): React.ReactElement {
|
||||
});
|
||||
}
|
||||
|
||||
function openResearchPopup(): void {
|
||||
const popupId = "corporation-research-popup-box";
|
||||
createPopup(popupId, ResearchPopup, {
|
||||
industry: division,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
@@ -214,9 +206,10 @@ function Text(): React.ReactElement {
|
||||
>
|
||||
<Typography>Scientific Research: {numeralWrapper.format(division.sciResearch.qty, "0.000a")}</Typography>
|
||||
</Tooltip>
|
||||
<Button sx={{ mx: 1 }} onClick={openResearchPopup}>
|
||||
<Button sx={{ mx: 1 }} onClick={() => setResearchOpen(true)}>
|
||||
Research
|
||||
</Button>
|
||||
<ResearchModal open={researchOpen} onClose={() => setResearchOpen(false)} industry={division} />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -123,10 +123,21 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
for (const prodName in division.products) {
|
||||
const prod = division.products[prodName];
|
||||
if (prod === undefined) continue;
|
||||
breakdown = (
|
||||
<>
|
||||
{breakdown}
|
||||
{prodName}: {numeralWrapper.format(prod.data[props.warehouse.loc][0] * prod.siz, "0,0.0")}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Tooltip title={props.warehouse.sizeUsed !== 0 ? breakdown : ""}>
|
||||
<Tooltip title={props.warehouse.sizeUsed !== 0 ? <Typography>{breakdown}</Typography> : ""}>
|
||||
<Typography color={props.warehouse.sizeUsed >= props.warehouse.size ? "error" : "primary"}>
|
||||
Storage: {numeralWrapper.formatBigNumber(props.warehouse.sizeUsed)} /{" "}
|
||||
{numeralWrapper.formatBigNumber(props.warehouse.size)}
|
||||
|
||||
122
src/Corporation/ui/ResearchModal.tsx
Normal file
122
src/Corporation/ui/ResearchModal.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { IndustryResearchTrees } from "../IndustryData";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Research } from "../Actions";
|
||||
import { Node } from "../ResearchTree";
|
||||
import { ResearchMap } from "../ResearchMap";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
import ListItemButton from "@mui/material/ListItemButton";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import ExpandMore from "@mui/icons-material/ExpandMore";
|
||||
import ExpandLess from "@mui/icons-material/ExpandLess";
|
||||
interface INodeProps {
|
||||
n: Node | null;
|
||||
division: IIndustry;
|
||||
}
|
||||
function Upgrade({ n, division }: INodeProps): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
if (n === null) return <></>;
|
||||
const r = ResearchMap[n.text];
|
||||
let disabled = division.sciResearch.qty < r.cost || n.researched;
|
||||
const parent = n.parent;
|
||||
if (parent !== null) {
|
||||
disabled = disabled || !parent.researched;
|
||||
}
|
||||
|
||||
function research(): void {
|
||||
if (n === null || disabled) return;
|
||||
try {
|
||||
Research(division, n.text);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
return;
|
||||
}
|
||||
|
||||
dialogBoxCreate(
|
||||
`Researched ${n.text}. It may take a market cycle ` +
|
||||
`(~${CorporationConstants.SecsPerMarketCycle} seconds) before the effects of ` +
|
||||
`the Research apply.`,
|
||||
);
|
||||
}
|
||||
|
||||
const but = (
|
||||
<Box>
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Research points: {r.cost}
|
||||
<br />
|
||||
{r.desc}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<Button disabled={disabled} onClick={research}>
|
||||
{n.text}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
);
|
||||
|
||||
if (n.children.length === 0) return but;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box display="flex">
|
||||
{but}
|
||||
<ListItemButton onClick={() => setOpen((old) => !old)}>
|
||||
<ListItemText />
|
||||
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
|
||||
</ListItemButton>
|
||||
</Box>
|
||||
<Collapse in={open} unmountOnExit>
|
||||
<Box m={4}>
|
||||
{n.children.map((m) => (
|
||||
<Upgrade key={m.text} division={division} n={m} />
|
||||
))}
|
||||
</Box>
|
||||
</Collapse>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
industry: IIndustry;
|
||||
}
|
||||
|
||||
// Create the Research Tree UI for this Industry
|
||||
export function ResearchModal(props: IProps): React.ReactElement {
|
||||
const researchTree = IndustryResearchTrees[props.industry.type];
|
||||
if (researchTree === undefined) return <></>;
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Upgrade division={props.industry} n={researchTree.root} />
|
||||
<Typography>
|
||||
Research points: {props.industry.sciResearch.qty.toFixed(3)}
|
||||
<br />
|
||||
Multipliers from research:
|
||||
<br />* Advertising Multiplier: x{researchTree.getAdvertisingMultiplier()}
|
||||
<br />* Employee Charisma Multiplier: x{researchTree.getEmployeeChaMultiplier()}
|
||||
<br />* Employee Creativity Multiplier: x{researchTree.getEmployeeCreMultiplier()}
|
||||
<br />* Employee Efficiency Multiplier: x{researchTree.getEmployeeEffMultiplier()}
|
||||
<br />* Employee Intelligence Multiplier: x{researchTree.getEmployeeIntMultiplier()}
|
||||
<br />* Production Multiplier: x{researchTree.getProductionMultiplier()}
|
||||
<br />* Sales Multiplier: x{researchTree.getSalesMultiplier()}
|
||||
<br />* Scientific Research Multiplier: x{researchTree.getScientificResearchMultiplier()}
|
||||
<br />* Storage Multiplier: x{researchTree.getStorageMultiplier()}
|
||||
</Typography>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { IndustryResearchTrees } from "../IndustryData";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { Treant } from "treant-js";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Research } from "../Actions";
|
||||
|
||||
interface IProps {
|
||||
industry: IIndustry;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
// Create the Research Tree UI for this Industry
|
||||
export function ResearchPopup(props: IProps): React.ReactElement {
|
||||
const researchTree = IndustryResearchTrees[props.industry.type];
|
||||
if (researchTree === undefined) return <></>;
|
||||
useEffect(() => {
|
||||
{
|
||||
const boxContent = document.getElementById(`${props.popupId}-content`);
|
||||
if (boxContent != null) {
|
||||
boxContent.style.minHeight = "80vh";
|
||||
}
|
||||
}
|
||||
|
||||
// Get the tree's markup (i.e. config) for Treant
|
||||
const markup = researchTree.createTreantMarkup();
|
||||
markup.chart.container = "#" + props.popupId + "-content";
|
||||
markup.chart.nodeAlign = "BOTTOM";
|
||||
markup.chart.rootOrientation = "WEST";
|
||||
markup.chart.siblingSeparation = 40;
|
||||
markup.chart.connectors = {
|
||||
type: "step",
|
||||
style: {
|
||||
"arrow-end": "block-wide-long",
|
||||
stroke: "white",
|
||||
"stroke-width": 2,
|
||||
},
|
||||
};
|
||||
|
||||
Treant(markup);
|
||||
|
||||
// Add Event Listeners for all Nodes
|
||||
const allResearch = researchTree.getAllNodes();
|
||||
for (let i = 0; i < allResearch.length; ++i) {
|
||||
// If this is already Researched, skip it
|
||||
if (props.industry.researched[allResearch[i]] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the DOM Element to add a click listener to it
|
||||
const sanitizedName = allResearch[i].replace(/\s/g, "");
|
||||
const div = document.getElementById(sanitizedName + "-corp-research-click-listener");
|
||||
if (div == null) {
|
||||
console.warn(`Could not find Research Tree div for ${sanitizedName}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
div.addEventListener("click", () => {
|
||||
try {
|
||||
Research(props.industry, allResearch[i]);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
return;
|
||||
}
|
||||
|
||||
dialogBoxCreate(
|
||||
`Researched ${allResearch[i]}. It may take a market cycle ` +
|
||||
`(~${CorporationConstants.SecsPerMarketCycle} seconds) before the effects of ` +
|
||||
`the Research apply.`,
|
||||
);
|
||||
removePopup(props.popupId);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div id={props.popupId}>
|
||||
<div>
|
||||
Research points: {props.industry.sciResearch.qty}
|
||||
<br />
|
||||
Multipliers from research:
|
||||
<br />* Advertising Multiplier: x{researchTree.getAdvertisingMultiplier()}
|
||||
<br />* Employee Charisma Multiplier: x{researchTree.getEmployeeChaMultiplier()}
|
||||
<br />* Employee Creativity Multiplier: x{researchTree.getEmployeeCreMultiplier()}
|
||||
<br />* Employee Efficiency Multiplier: x{researchTree.getEmployeeEffMultiplier()}
|
||||
<br />* Employee Intelligence Multiplier: x{researchTree.getEmployeeIntMultiplier()}
|
||||
<br />* Production Multiplier: x{researchTree.getProductionMultiplier()}
|
||||
<br />* Sales Multiplier: x{researchTree.getSalesMultiplier()}
|
||||
<br />* Scientific Research Multiplier: x{researchTree.getScientificResearchMultiplier()}
|
||||
<br />* Storage Multiplier: x{researchTree.getStorageMultiplier()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import { ICorporation } from "../ICorporation";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
@@ -73,10 +73,11 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
player.recordMoneySource(profit, "corporation");
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
`Sold {numeralWrapper.formatMoney(shares)} shares for ` +
|
||||
`${numeralWrapper.formatMoney(profit)}. ` +
|
||||
`The corporation's stock price fell to ${numeralWrapper.formatMoney(corp.sharePrice)} ` +
|
||||
`as a result of dilution.`,
|
||||
<>
|
||||
Sold {numeralWrapper.formatMoney(shares)} shares for
|
||||
<Money money={profit} />. The corporation's stock price fell to <Money money={corp.sharePrice} />
|
||||
as a result of dilution.
|
||||
</>,
|
||||
);
|
||||
|
||||
props.rerender();
|
||||
|
||||
90
src/CotMG/ActiveFragment.ts
Normal file
90
src/CotMG/ActiveFragment.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Fragment, FragmentById } from "./Fragment";
|
||||
import { FragmentType } from "./FragmentType";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||
|
||||
const noCharge = [FragmentType.None, FragmentType.Delete, FragmentType.Booster];
|
||||
|
||||
export interface IActiveFragmentParams {
|
||||
x: number;
|
||||
y: number;
|
||||
fragment: Fragment;
|
||||
}
|
||||
|
||||
export class ActiveFragment {
|
||||
id: number;
|
||||
charge: number;
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
constructor(params?: IActiveFragmentParams) {
|
||||
if (params) {
|
||||
this.id = params.fragment.id;
|
||||
this.x = params.x;
|
||||
this.y = params.y;
|
||||
this.charge = 1;
|
||||
if (noCharge.includes(params.fragment.type)) this.charge = 0;
|
||||
} else {
|
||||
this.id = -1;
|
||||
this.x = -1;
|
||||
this.y = -1;
|
||||
this.charge = -1;
|
||||
}
|
||||
}
|
||||
|
||||
collide(other: ActiveFragment): boolean {
|
||||
const thisFragment = this.fragment();
|
||||
const otherFragment = other.fragment();
|
||||
// These 2 variables converts 'this' local coordinates to world to other local.
|
||||
const dx: number = other.x - this.x;
|
||||
const dy: number = other.y - this.y;
|
||||
for (let j = 0; j < thisFragment.shape.length; j++) {
|
||||
for (let i = 0; i < thisFragment.shape[j].length; i++) {
|
||||
if (thisFragment.fullAt(i, j) && otherFragment.fullAt(i - dx, j - dy)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fragment(): Fragment {
|
||||
const fragment = FragmentById(this.id);
|
||||
if (fragment === null) throw new Error("ActiveFragment id refers to unknown Fragment.");
|
||||
return fragment;
|
||||
}
|
||||
|
||||
fullAt(worldX: number, worldY: number): boolean {
|
||||
return this.fragment().fullAt(worldX - this.x, worldY - this.y);
|
||||
}
|
||||
|
||||
neighboors(): number[][] {
|
||||
return this.fragment()
|
||||
.neighboors()
|
||||
.map((cell) => [this.x + cell[0], this.y + cell[1]]);
|
||||
}
|
||||
|
||||
copy(): ActiveFragment {
|
||||
// We have to do a round trip because the constructor.
|
||||
const fragment = FragmentById(this.id);
|
||||
if (fragment === null) throw new Error("ActiveFragment id refers to unknown Fragment.");
|
||||
const c = new ActiveFragment({ x: this.x, y: this.y, fragment: fragment });
|
||||
c.charge = this.charge;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize an active fragment to a JSON save state.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("ActiveFragment", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an acive fragment from a JSON save state
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): ActiveFragment {
|
||||
return Generic_fromJSON(ActiveFragment, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.ActiveFragment = ActiveFragment;
|
||||
329
src/CotMG/Fragment.ts
Normal file
329
src/CotMG/Fragment.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
import { FragmentType } from "./FragmentType";
|
||||
|
||||
export const Fragments: Fragment[] = [];
|
||||
|
||||
export class Fragment {
|
||||
id: number;
|
||||
shape: boolean[][];
|
||||
type: FragmentType;
|
||||
power: number;
|
||||
limit: number;
|
||||
|
||||
constructor(id: number, shape: boolean[][], type: FragmentType, power: number, limit: number) {
|
||||
this.id = id;
|
||||
this.shape = shape;
|
||||
this.type = type;
|
||||
this.power = power;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
fullAt(x: number, y: number): boolean {
|
||||
if (y < 0) return false;
|
||||
if (y >= this.shape.length) return false;
|
||||
if (x < 0) return false;
|
||||
if (x >= this.shape[y].length) return false;
|
||||
// Yes it's ordered y first.
|
||||
return this.shape[y][x];
|
||||
}
|
||||
|
||||
width(): number {
|
||||
// check every line for robustness.
|
||||
return Math.max(...this.shape.map((line) => line.length));
|
||||
}
|
||||
|
||||
height(): number {
|
||||
return this.shape.length;
|
||||
}
|
||||
|
||||
// List of direct neighboors of this fragment.
|
||||
neighboors(): number[][] {
|
||||
const candidates: number[][] = [];
|
||||
|
||||
const add = (x: number, y: number): void => {
|
||||
if (this.fullAt(x, y)) return;
|
||||
if (candidates.some((coord) => coord[0] === x && coord[1] === y)) return;
|
||||
candidates.push([x, y]);
|
||||
};
|
||||
for (let y = 0; y < this.shape.length; y++) {
|
||||
for (let x = 0; x < this.shape[y].length; x++) {
|
||||
// This cell is full, add all it's neighboors.
|
||||
if (!this.shape[y][x]) continue;
|
||||
add(x - 1, y);
|
||||
add(x + 1, y);
|
||||
add(x, y - 1);
|
||||
add(x, y + 1);
|
||||
}
|
||||
}
|
||||
const cells: number[][] = [];
|
||||
for (const candidate of candidates) {
|
||||
if (cells.some((cell) => cell[0] === candidate[0] && cell[1] === candidate[1])) continue;
|
||||
cells.push(candidate);
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
copy(): Fragment {
|
||||
return new Fragment(
|
||||
this.id,
|
||||
this.shape.map((a) => a.slice()),
|
||||
this.type,
|
||||
this.power,
|
||||
this.limit,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function FragmentById(id: number): Fragment | null {
|
||||
for (const fragment of Fragments) {
|
||||
if (fragment.id === id) return fragment;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
(function () {
|
||||
const _ = false;
|
||||
const X = true;
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
0, // id
|
||||
[
|
||||
// shape
|
||||
[X, X, X],
|
||||
[_, _, X],
|
||||
[_, _, X],
|
||||
],
|
||||
FragmentType.Hacking, // type
|
||||
1,
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
1, // id
|
||||
[
|
||||
// shape
|
||||
[_, X, _],
|
||||
[X, X, X],
|
||||
[_, X, _],
|
||||
],
|
||||
FragmentType.Hacking, // type
|
||||
1,
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
5, // id
|
||||
[
|
||||
// shape
|
||||
[X, X],
|
||||
],
|
||||
FragmentType.HackingSpeed, // type
|
||||
1.3,
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
6, // id
|
||||
[
|
||||
[X, _],
|
||||
[X, X],
|
||||
], // shape
|
||||
FragmentType.HackingMoney, // type
|
||||
2, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
7, // id
|
||||
[
|
||||
[X, X],
|
||||
[X, X],
|
||||
], // shape
|
||||
FragmentType.HackingGrow, // type
|
||||
0.5, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
8, // id
|
||||
[
|
||||
[X, X, X],
|
||||
[_, X, _],
|
||||
[X, X, X],
|
||||
], // shape
|
||||
FragmentType.Hacking, // type
|
||||
1, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
10, // id
|
||||
[
|
||||
[X, X],
|
||||
[_, X],
|
||||
], // shape
|
||||
FragmentType.Strength, // type
|
||||
2, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
12, // id
|
||||
[
|
||||
[_, X],
|
||||
[X, X],
|
||||
], // shape
|
||||
FragmentType.Defense, // type
|
||||
2, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
14, // id
|
||||
[
|
||||
[X, X],
|
||||
[X, _],
|
||||
], // shape
|
||||
FragmentType.Dexterity, // type
|
||||
2, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
16, // id
|
||||
[
|
||||
[X, _],
|
||||
[X, X],
|
||||
], // shape
|
||||
FragmentType.Agility, // type
|
||||
2, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
18, // id
|
||||
[
|
||||
[X, X],
|
||||
[X, _],
|
||||
], // shape
|
||||
FragmentType.Charisma, // type
|
||||
3, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
20, // id
|
||||
[
|
||||
[X, _, _],
|
||||
[X, X, _],
|
||||
[X, X, X],
|
||||
], // shape
|
||||
FragmentType.HacknetMoney, // type
|
||||
1, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
21, // id
|
||||
[
|
||||
[X, X],
|
||||
[_, X],
|
||||
[_, X],
|
||||
], // shape
|
||||
FragmentType.HacknetCost, // type
|
||||
-1, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
25, // id
|
||||
[
|
||||
[X, X, X],
|
||||
[_, X, _],
|
||||
], // shape
|
||||
FragmentType.Rep, // type
|
||||
0.5, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
27, // id
|
||||
[
|
||||
[X, _],
|
||||
[_, X],
|
||||
], // shape
|
||||
FragmentType.WorkMoney, // type
|
||||
10, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
28, // id
|
||||
[[X, X]], // shape
|
||||
FragmentType.Crime, // type
|
||||
2, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
30, // id
|
||||
[
|
||||
[X, X, X],
|
||||
[X, X, X],
|
||||
[X, X, X],
|
||||
], // shape
|
||||
FragmentType.Bladeburner, // type
|
||||
1.3, // power
|
||||
1, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
2, // id
|
||||
[
|
||||
// shape
|
||||
[X, X, X],
|
||||
[X, _, X],
|
||||
[X, X, X],
|
||||
],
|
||||
FragmentType.Booster, // type
|
||||
1.1, // power
|
||||
3, // limit
|
||||
),
|
||||
);
|
||||
Fragments.push(
|
||||
new Fragment(
|
||||
31, // id
|
||||
[
|
||||
// shape
|
||||
[X],
|
||||
[X],
|
||||
[X],
|
||||
[X],
|
||||
],
|
||||
FragmentType.Booster, // type
|
||||
1.1, // power
|
||||
3, // limit
|
||||
),
|
||||
);
|
||||
})();
|
||||
|
||||
export const NoneFragment = new Fragment(-2, [], FragmentType.None, 0, Infinity);
|
||||
export const DeleteFragment = new Fragment(-2, [], FragmentType.Delete, 0, Infinity);
|
||||
96
src/CotMG/FragmentType.ts
Normal file
96
src/CotMG/FragmentType.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
export enum FragmentType {
|
||||
// Special fragments for the UI
|
||||
None,
|
||||
Delete,
|
||||
|
||||
// Stats boosting fragments
|
||||
HackingChance,
|
||||
HackingSpeed,
|
||||
HackingMoney,
|
||||
HackingGrow,
|
||||
Hacking,
|
||||
Strength,
|
||||
Defense,
|
||||
Dexterity,
|
||||
Agility,
|
||||
Charisma,
|
||||
HacknetMoney,
|
||||
HacknetCost,
|
||||
Rep,
|
||||
WorkMoney,
|
||||
Crime,
|
||||
Bladeburner,
|
||||
|
||||
// utility fragments.
|
||||
Booster,
|
||||
}
|
||||
|
||||
export function Effect(tpe: FragmentType): string {
|
||||
switch (tpe) {
|
||||
case FragmentType.HackingChance: {
|
||||
return "+x% hack() success chance";
|
||||
break;
|
||||
}
|
||||
case FragmentType.HackingSpeed: {
|
||||
return "+x% faster hack(), grow(), and weaken()";
|
||||
break;
|
||||
}
|
||||
case FragmentType.HackingMoney: {
|
||||
return "+x% hack() power";
|
||||
break;
|
||||
}
|
||||
case FragmentType.HackingGrow: {
|
||||
return "+x% grow() power";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Hacking: {
|
||||
return "+x% hacking skill";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Strength: {
|
||||
return "+x% strength skill";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Defense: {
|
||||
return "+x% defense skill";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Dexterity: {
|
||||
return "+x% dexterity skill";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Agility: {
|
||||
return "+x% agility skill";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Charisma: {
|
||||
return "+x% charisma skill";
|
||||
break;
|
||||
}
|
||||
case FragmentType.HacknetMoney: {
|
||||
return "+x% hacknet production";
|
||||
break;
|
||||
}
|
||||
case FragmentType.HacknetCost: {
|
||||
return "-x% all hacknet cost";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Rep: {
|
||||
return "+x% reputation from factions and companies";
|
||||
break;
|
||||
}
|
||||
case FragmentType.WorkMoney: {
|
||||
return "+x% work money";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Crime: {
|
||||
return "+x% crime money";
|
||||
break;
|
||||
}
|
||||
case FragmentType.Bladeburner: {
|
||||
return "+x% all bladeburner stats";
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new Error("Calling effect for fragment type that doesn't have an effect " + tpe);
|
||||
}
|
||||
14
src/CotMG/Helper.tsx
Normal file
14
src/CotMG/Helper.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Reviver } from "../utils/JSONReviver";
|
||||
|
||||
import { IStaneksGift } from "./IStaneksGift";
|
||||
import { StaneksGift } from "./StaneksGift";
|
||||
|
||||
export let staneksGift: IStaneksGift = new StaneksGift();
|
||||
|
||||
export function loadStaneksGift(saveString: string): void {
|
||||
if (saveString) {
|
||||
staneksGift = JSON.parse(saveString, Reviver);
|
||||
} else {
|
||||
staneksGift = new StaneksGift();
|
||||
}
|
||||
}
|
||||
22
src/CotMG/IStaneksGift.ts
Normal file
22
src/CotMG/IStaneksGift.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ActiveFragment } from "./ActiveFragment";
|
||||
import { Fragment } from "./Fragment";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
|
||||
export interface IStaneksGift {
|
||||
storedCycles: number;
|
||||
fragments: ActiveFragment[];
|
||||
width(): number;
|
||||
height(): number;
|
||||
charge(worldX: number, worldY: number, ram: number): number;
|
||||
process(p: IPlayer, n: number): void;
|
||||
effect(fragment: ActiveFragment): number;
|
||||
canPlace(x: number, y: number, fragment: Fragment): boolean;
|
||||
place(x: number, y: number, fragment: Fragment): boolean;
|
||||
fragmentAt(worldX: number, worldY: number): ActiveFragment | null;
|
||||
deleteAt(worldX: number, worldY: number): boolean;
|
||||
clear(): void;
|
||||
count(fragment: Fragment): number;
|
||||
inBonus(): boolean;
|
||||
prestigeAugmentation(): void;
|
||||
prestigeSourceFile(): void;
|
||||
}
|
||||
222
src/CotMG/StaneksGift.ts
Normal file
222
src/CotMG/StaneksGift.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
import { Fragment } from "./Fragment";
|
||||
import { ActiveFragment } from "./ActiveFragment";
|
||||
import { FragmentType } from "./FragmentType";
|
||||
import { IStaneksGift } from "./IStaneksGift";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Factions } from "../Faction/Factions";
|
||||
import { CalculateEffect } from "./formulas/effect";
|
||||
import { CalculateCharge } from "./formulas/charge";
|
||||
import { StaneksGiftEvents } from "./StaneksGiftEvents";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { StanekConstants } from "./data/Constants";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { Player } from "../Player";
|
||||
|
||||
export class StaneksGift implements IStaneksGift {
|
||||
storedCycles = 0;
|
||||
fragments: ActiveFragment[] = [];
|
||||
|
||||
baseSize(): number {
|
||||
return StanekConstants.BaseSize + BitNodeMultipliers.StaneksGiftExtraSize + Player.sourceFileLvl(13);
|
||||
}
|
||||
|
||||
width(): number {
|
||||
return Math.floor(this.baseSize() / 2 + 1);
|
||||
}
|
||||
height(): number {
|
||||
return Math.floor(this.baseSize() / 2 + 0.6);
|
||||
}
|
||||
|
||||
charge(worldX: number, worldY: number, ram: number): number {
|
||||
const af = this.fragmentAt(worldX, worldY);
|
||||
if (af === null) return 0;
|
||||
|
||||
const charge = CalculateCharge(ram);
|
||||
af.charge += charge;
|
||||
|
||||
Factions["Church of the Machine God"].playerReputation += Math.log(ram) / Math.log(2);
|
||||
|
||||
return ram;
|
||||
}
|
||||
|
||||
inBonus(): boolean {
|
||||
return (this.storedCycles * CONSTANTS._idleSpeed) / 1000 > 1;
|
||||
}
|
||||
|
||||
process(p: IPlayer, numCycles = 1): void {
|
||||
this.storedCycles += numCycles;
|
||||
this.storedCycles -= 5;
|
||||
this.storedCycles = Math.max(0, this.storedCycles);
|
||||
this.updateMults(p);
|
||||
StaneksGiftEvents.emit();
|
||||
}
|
||||
|
||||
effect(fragment: ActiveFragment): number {
|
||||
// Find all the neighbooring cells
|
||||
const cells = fragment.neighboors();
|
||||
// find the neighbooring active fragments.
|
||||
const maybeFragments = cells.map((n) => this.fragmentAt(n[0], n[1]));
|
||||
|
||||
// Filter out nulls with typescript "Type guard". Whatever
|
||||
let neighboors = maybeFragments.filter((v: ActiveFragment | null): v is ActiveFragment => !!v);
|
||||
|
||||
neighboors = neighboors.filter((fragment) => fragment.fragment().type === FragmentType.Booster);
|
||||
let boost = 1;
|
||||
for (const neighboor of neighboors) {
|
||||
boost *= neighboor.fragment().power;
|
||||
}
|
||||
|
||||
return CalculateEffect(fragment.charge, fragment.fragment().power, boost);
|
||||
}
|
||||
|
||||
canPlace(x: number, y: number, fragment: Fragment): boolean {
|
||||
if (x + fragment.width() > this.width()) return false;
|
||||
if (y + fragment.height() > this.height()) return false;
|
||||
if (this.count(fragment) >= fragment.limit) return false;
|
||||
const newFrag = new ActiveFragment({ x: x, y: y, fragment: fragment });
|
||||
for (const aFrag of this.fragments) {
|
||||
if (aFrag.collide(newFrag)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
place(x: number, y: number, fragment: Fragment): boolean {
|
||||
if (!this.canPlace(x, y, fragment)) return false;
|
||||
this.fragments.push(new ActiveFragment({ x: x, y: y, fragment: fragment }));
|
||||
return true;
|
||||
}
|
||||
|
||||
fragmentAt(worldX: number, worldY: number): ActiveFragment | null {
|
||||
for (const aFrag of this.fragments) {
|
||||
if (aFrag.fullAt(worldX, worldY)) {
|
||||
return aFrag;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
count(fragment: Fragment): number {
|
||||
let amt = 0;
|
||||
for (const aFrag of this.fragments) {
|
||||
if (aFrag.fragment().id === fragment.id) amt++;
|
||||
}
|
||||
return amt;
|
||||
}
|
||||
|
||||
deleteAt(worldX: number, worldY: number): boolean {
|
||||
for (let i = 0; i < this.fragments.length; i++) {
|
||||
if (this.fragments[i].fullAt(worldX, worldY)) {
|
||||
this.fragments.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.fragments = [];
|
||||
}
|
||||
|
||||
updateMults(p: IPlayer): void {
|
||||
p.reapplyAllAugmentations(true);
|
||||
p.reapplyAllSourceFiles();
|
||||
|
||||
for (const aFrag of this.fragments) {
|
||||
const fragment = aFrag.fragment();
|
||||
|
||||
const power = this.effect(aFrag);
|
||||
switch (fragment.type) {
|
||||
case FragmentType.HackingChance:
|
||||
p.hacking_chance_mult *= power;
|
||||
break;
|
||||
case FragmentType.HackingSpeed:
|
||||
p.hacking_speed_mult *= power;
|
||||
break;
|
||||
case FragmentType.HackingMoney:
|
||||
p.hacking_money_mult *= power;
|
||||
break;
|
||||
case FragmentType.HackingGrow:
|
||||
p.hacking_grow_mult *= power;
|
||||
break;
|
||||
case FragmentType.Hacking:
|
||||
p.hacking_mult *= power;
|
||||
p.hacking_exp_mult *= power;
|
||||
break;
|
||||
case FragmentType.Strength:
|
||||
p.strength_mult *= power;
|
||||
p.strength_exp_mult *= power;
|
||||
break;
|
||||
case FragmentType.Defense:
|
||||
p.defense_mult *= power;
|
||||
p.defense_exp_mult *= power;
|
||||
break;
|
||||
case FragmentType.Dexterity:
|
||||
p.dexterity_mult *= power;
|
||||
p.dexterity_exp_mult *= power;
|
||||
break;
|
||||
case FragmentType.Agility:
|
||||
p.agility_mult *= power;
|
||||
p.agility_exp_mult *= power;
|
||||
break;
|
||||
case FragmentType.Charisma:
|
||||
p.charisma_mult *= power;
|
||||
p.charisma_exp_mult *= power;
|
||||
break;
|
||||
case FragmentType.HacknetMoney:
|
||||
p.hacknet_node_money_mult *= power;
|
||||
break;
|
||||
case FragmentType.HacknetCost:
|
||||
p.hacknet_node_purchase_cost_mult *= power;
|
||||
p.hacknet_node_ram_cost_mult *= power;
|
||||
p.hacknet_node_core_cost_mult *= power;
|
||||
p.hacknet_node_level_cost_mult *= power;
|
||||
break;
|
||||
case FragmentType.Rep:
|
||||
p.company_rep_mult *= power;
|
||||
p.faction_rep_mult *= power;
|
||||
break;
|
||||
case FragmentType.WorkMoney:
|
||||
p.work_money_mult *= power;
|
||||
break;
|
||||
case FragmentType.Crime:
|
||||
p.crime_success_mult *= power;
|
||||
p.crime_money_mult *= power;
|
||||
break;
|
||||
case FragmentType.Bladeburner:
|
||||
p.bladeburner_max_stamina_mult *= power;
|
||||
p.bladeburner_stamina_gain_mult *= power;
|
||||
p.bladeburner_analysis_mult *= power;
|
||||
p.bladeburner_success_chance_mult *= power;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prestigeAugmentation(): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
prestigeSourceFile(): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize Staneks Gift to a JSON save state.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("StaneksGift", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Staneks Gift from a JSON save state
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): StaneksGift {
|
||||
return Generic_fromJSON(StaneksGift, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.StaneksGift = StaneksGift;
|
||||
2
src/CotMG/StaneksGiftEvents.ts
Normal file
2
src/CotMG/StaneksGiftEvents.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import { EventEmitter } from "../utils/EventEmitter";
|
||||
export const StaneksGiftEvents = new EventEmitter<[]>();
|
||||
7
src/CotMG/data/Constants.ts
Normal file
7
src/CotMG/data/Constants.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const StanekConstants: {
|
||||
RAMBonus: number;
|
||||
BaseSize: number;
|
||||
} = {
|
||||
RAMBonus: 0.1,
|
||||
BaseSize: 12,
|
||||
};
|
||||
5
src/CotMG/formulas/charge.ts
Normal file
5
src/CotMG/formulas/charge.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { StanekConstants } from "../data/Constants";
|
||||
|
||||
export function CalculateCharge(ram: number): number {
|
||||
return ram * Math.pow(1 + Math.log2(ram) * StanekConstants.RAMBonus, 0.7);
|
||||
}
|
||||
3
src/CotMG/formulas/effect.ts
Normal file
3
src/CotMG/formulas/effect.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function CalculateEffect(charge: number, power: number, boost: number): number {
|
||||
return 1 + (Math.log(charge + 1) / (Math.log(3) * 100)) * power * boost;
|
||||
}
|
||||
4
src/CotMG/notes
Normal file
4
src/CotMG/notes
Normal file
@@ -0,0 +1,4 @@
|
||||
incentive for more threads
|
||||
boosters just multiply output, eg 20% * 1.5 = 30%
|
||||
|
||||
git remote add danielyxie git@github.com:danielyxie/bitburner.git
|
||||
40
src/CotMG/ui/Cell.tsx
Normal file
40
src/CotMG/ui/Cell.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import * as React from "react";
|
||||
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { TableCell as MuiTableCell, TableCellProps } from "@mui/material";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
border: "1px solid white",
|
||||
width: "5px",
|
||||
height: "5px",
|
||||
},
|
||||
});
|
||||
|
||||
export const TableCell: React.FC<TableCellProps> = (props: TableCellProps) => {
|
||||
return (
|
||||
<MuiTableCell
|
||||
{...props}
|
||||
classes={{
|
||||
root: useStyles().root,
|
||||
...props.classes,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type IProps = {
|
||||
onMouseEnter?: () => void;
|
||||
onClick?: () => void;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export function Cell(cellProps: IProps): React.ReactElement {
|
||||
return (
|
||||
<TableCell
|
||||
style={{ backgroundColor: cellProps.color }}
|
||||
onMouseEnter={cellProps.onMouseEnter}
|
||||
onClick={cellProps.onClick}
|
||||
></TableCell>
|
||||
);
|
||||
}
|
||||
79
src/CotMG/ui/FragmentInspector.tsx
Normal file
79
src/CotMG/ui/FragmentInspector.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { ActiveFragment } from "../ActiveFragment";
|
||||
import { IStaneksGift } from "../IStaneksGift";
|
||||
import { FragmentType, Effect } from "../FragmentType";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
type IProps = {
|
||||
gift: IStaneksGift;
|
||||
fragment: ActiveFragment | null;
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
export function FragmentInspector(props: IProps): React.ReactElement {
|
||||
const [, setC] = useState(new Date());
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => setC(new Date()), 250);
|
||||
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
if (props.fragment === null) {
|
||||
return (
|
||||
<Paper>
|
||||
<Typography>
|
||||
ID: N/A
|
||||
<br />
|
||||
Effect: N/A
|
||||
<br />
|
||||
Magnitude: N/A
|
||||
<br />
|
||||
Charge: N/A
|
||||
<br />
|
||||
Heat: N/A
|
||||
<br />
|
||||
Effect: N/A
|
||||
<br />
|
||||
[X, Y] N/A
|
||||
<br />
|
||||
[X, Y] {props.x}, {props.y}
|
||||
</Typography>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
const f = props.fragment.fragment();
|
||||
|
||||
let charge = numeralWrapper.formatStaneksGiftCharge(props.fragment.charge);
|
||||
let effect = "N/A";
|
||||
// Boosters and cooling don't deal with heat.
|
||||
if ([FragmentType.Booster, FragmentType.None, FragmentType.Delete].includes(f.type)) {
|
||||
charge = "N/A";
|
||||
effect = `${f.power}x adjacent fragment power`;
|
||||
} else {
|
||||
effect = Effect(f.type).replace("x%", numeralWrapper.formatPercentage(props.gift.effect(props.fragment) - 1));
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<Typography>
|
||||
ID: {props.fragment.id}
|
||||
<br />
|
||||
Effect: {effect}
|
||||
<br />
|
||||
Power: {numeralWrapper.formatStaneksGiftPower(f.power)}
|
||||
<br />
|
||||
Charge: {charge}
|
||||
<br />
|
||||
<br />
|
||||
root [X, Y] {props.fragment.x}, {props.fragment.y}
|
||||
<br />
|
||||
[X, Y] {props.x}, {props.y}
|
||||
</Typography>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
31
src/CotMG/ui/FragmentPreview.tsx
Normal file
31
src/CotMG/ui/FragmentPreview.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as React from "react";
|
||||
import { Cell } from "./Cell";
|
||||
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import { Table } from "../../ui/React/Table";
|
||||
|
||||
type IProps = {
|
||||
width: number;
|
||||
height: number;
|
||||
colorAt: (x: number, y: number) => string;
|
||||
};
|
||||
|
||||
export function FragmentPreview(props: IProps): React.ReactElement {
|
||||
// switch the width/length to make axis consistent.
|
||||
const elems = [];
|
||||
for (let j = 0; j < props.height; j++) {
|
||||
const cells = [];
|
||||
for (let i = 0; i < props.width; i++) {
|
||||
cells.push(<Cell key={i} color={props.colorAt(i, j)} />);
|
||||
}
|
||||
elems.push(<TableRow key={j}>{cells}</TableRow>);
|
||||
}
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TableBody>{elems}</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
91
src/CotMG/ui/FragmentSelector.tsx
Normal file
91
src/CotMG/ui/FragmentSelector.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React, { useState } from "react";
|
||||
import { Fragments, Fragment, NoneFragment, DeleteFragment } from "../Fragment";
|
||||
import { FragmentType, Effect } from "../FragmentType";
|
||||
import { IStaneksGift } from "../IStaneksGift";
|
||||
import { FragmentPreview } from "./FragmentPreview";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
type IOptionProps = {
|
||||
gift: IStaneksGift;
|
||||
fragment: Fragment;
|
||||
selectFragment: (fragment: Fragment) => void;
|
||||
};
|
||||
|
||||
function FragmentOption(props: IOptionProps): React.ReactElement {
|
||||
const remaining =
|
||||
props.fragment.limit !== Infinity ? (
|
||||
<>{props.fragment.limit - props.gift.count(props.fragment)} remaining</>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
return (
|
||||
<Box display="flex">
|
||||
<Box sx={{ mx: 2 }}>
|
||||
<FragmentPreview
|
||||
width={props.fragment.width()}
|
||||
height={props.fragment.height()}
|
||||
colorAt={(x, y) => {
|
||||
return !props.fragment.fullAt(x, y) ? "" : props.fragment.type === FragmentType.Booster ? "blue" : "green";
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Typography>
|
||||
{props.fragment.type === FragmentType.Booster
|
||||
? `${props.fragment.power}x adjacent fragment power`
|
||||
: Effect(props.fragment.type)}
|
||||
<br />
|
||||
power: {numeralWrapper.formatStaneksGiftPower(props.fragment.power)}
|
||||
<br />
|
||||
{remaining}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
type IProps = {
|
||||
gift: IStaneksGift;
|
||||
selectFragment: (fragment: Fragment) => void;
|
||||
};
|
||||
|
||||
export function FragmentSelector(props: IProps): React.ReactElement {
|
||||
const [value, setValue] = useState<string | number>("None");
|
||||
function onChange(event: SelectChangeEvent<string | number>): void {
|
||||
const v = event.target.value;
|
||||
setValue(v);
|
||||
if (v === "None") {
|
||||
props.selectFragment(NoneFragment);
|
||||
return;
|
||||
} else if (v === "Delete") {
|
||||
props.selectFragment(DeleteFragment);
|
||||
return;
|
||||
}
|
||||
const fragment = Fragments.find((f) => f.id === v);
|
||||
if (fragment === undefined) throw new Error("Fragment selector selected an undefined fragment with id " + v);
|
||||
if (typeof v === "number") props.selectFragment(fragment);
|
||||
}
|
||||
return (
|
||||
<Select sx={{ width: "100%" }} onChange={onChange} value={value}>
|
||||
<MenuItem value="None">
|
||||
<Typography>None</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem value="Delete">
|
||||
<Typography>Delete</Typography>
|
||||
</MenuItem>
|
||||
{Fragments.map((fragment) => (
|
||||
<MenuItem key={fragment.id} value={fragment.id}>
|
||||
<FragmentOption
|
||||
key={fragment.id}
|
||||
gift={props.gift}
|
||||
selectFragment={props.selectFragment}
|
||||
fragment={fragment}
|
||||
/>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
145
src/CotMG/ui/Grid.tsx
Normal file
145
src/CotMG/ui/Grid.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
import * as React from "react";
|
||||
import { Fragment, NoneFragment } from "../Fragment";
|
||||
import { ActiveFragment } from "../ActiveFragment";
|
||||
import { FragmentType } from "../FragmentType";
|
||||
import { IStaneksGift } from "../IStaneksGift";
|
||||
import { Cell } from "./Cell";
|
||||
import { FragmentInspector } from "./FragmentInspector";
|
||||
import { FragmentSelector } from "./FragmentSelector";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import { Table } from "../../ui/React/Table";
|
||||
|
||||
function zeros(dimensions: number[]): any {
|
||||
const array = [];
|
||||
|
||||
for (let i = 0; i < dimensions[0]; ++i) {
|
||||
array.push(dimensions.length == 1 ? 0 : zeros(dimensions.slice(1)));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
function randomColor(fragment: ActiveFragment): string {
|
||||
// Can't set Math.random seed so copy casino. TODO refactor both RNG later.
|
||||
let s1 = Math.pow((fragment.x + 1) * (fragment.y + 1), 10);
|
||||
let s2 = s1;
|
||||
let s3 = s1;
|
||||
|
||||
const colors = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
s1 = (171 * s1) % 30269;
|
||||
s2 = (172 * s2) % 30307;
|
||||
s3 = (170 * s3) % 30323;
|
||||
colors.push((s1 / 30269.0 + s2 / 30307.0 + s3 / 30323.0) % 1.0);
|
||||
}
|
||||
|
||||
return `rgb(${colors[0] * 256}, ${colors[1] * 256}, ${colors[2] * 256})`;
|
||||
}
|
||||
|
||||
type GridProps = {
|
||||
gift: IStaneksGift;
|
||||
};
|
||||
|
||||
export function Grid(props: GridProps): React.ReactElement {
|
||||
function calculateGrid(gift: IStaneksGift): any {
|
||||
const newgrid = zeros([gift.width(), gift.height()]);
|
||||
for (let i = 0; i < gift.width(); i++) {
|
||||
for (let j = 0; j < gift.height(); j++) {
|
||||
const fragment = gift.fragmentAt(i, j);
|
||||
if (fragment === null) continue;
|
||||
newgrid[i][j] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return newgrid;
|
||||
}
|
||||
|
||||
const [grid, setGrid] = React.useState(calculateGrid(props.gift));
|
||||
const [ghostGrid, setGhostGrid] = React.useState(zeros([props.gift.width(), props.gift.height()]));
|
||||
const [pos, setPos] = React.useState([0, 0]);
|
||||
const [selectedFragment, setSelectedFragment] = React.useState(NoneFragment);
|
||||
|
||||
function moveGhost(worldX: number, worldY: number): void {
|
||||
const newgrid = zeros([props.gift.width(), props.gift.height()]);
|
||||
for (let i = 0; i < selectedFragment.shape.length; i++) {
|
||||
for (let j = 0; j < selectedFragment.shape[i].length; j++) {
|
||||
if (!selectedFragment.shape[i][j]) continue;
|
||||
if (worldX + j > newgrid.length - 1) continue;
|
||||
if (worldY + i > newgrid[worldX + j].length - 1) continue;
|
||||
newgrid[worldX + j][worldY + i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
setGhostGrid(newgrid);
|
||||
setPos([worldX, worldY]);
|
||||
}
|
||||
|
||||
function deleteAt(worldX: number, worldY: number): boolean {
|
||||
return props.gift.deleteAt(worldX, worldY);
|
||||
}
|
||||
|
||||
function clickAt(worldX: number, worldY: number): void {
|
||||
if (selectedFragment.type == FragmentType.None) return;
|
||||
if (selectedFragment.type == FragmentType.Delete) {
|
||||
deleteAt(worldX, worldY);
|
||||
} else {
|
||||
if (!props.gift.canPlace(worldX, worldY, selectedFragment)) return;
|
||||
props.gift.place(worldX, worldY, selectedFragment);
|
||||
}
|
||||
setGrid(calculateGrid(props.gift));
|
||||
}
|
||||
|
||||
function color(worldX: number, worldY: number): string {
|
||||
if (ghostGrid[worldX][worldY] && grid[worldX][worldY]) return "red";
|
||||
if (ghostGrid[worldX][worldY]) return "white";
|
||||
if (grid[worldX][worldY]) {
|
||||
const fragment = props.gift.fragmentAt(worldX, worldY);
|
||||
if (fragment === null) throw new Error("ActiveFragment should not be null");
|
||||
return randomColor(fragment);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function clear(): void {
|
||||
props.gift.clear();
|
||||
setGrid(zeros([props.gift.width(), props.gift.height()]));
|
||||
}
|
||||
|
||||
// switch the width/length to make axis consistent.
|
||||
const elems = [];
|
||||
for (let j = 0; j < props.gift.height(); j++) {
|
||||
const cells = [];
|
||||
for (let i = 0; i < props.gift.width(); i++) {
|
||||
cells.push(
|
||||
<Cell key={i} onMouseEnter={() => moveGhost(i, j)} onClick={() => clickAt(i, j)} color={color(i, j)} />,
|
||||
);
|
||||
}
|
||||
elems.push(
|
||||
<TableRow key={j} className="staneksgift_row">
|
||||
{cells}
|
||||
</TableRow>,
|
||||
);
|
||||
}
|
||||
|
||||
function updateSelectedFragment(fragment: Fragment): void {
|
||||
setSelectedFragment(fragment);
|
||||
const newgrid = zeros([props.gift.width(), props.gift.height()]);
|
||||
setGhostGrid(newgrid);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={clear}>Clear</Button>
|
||||
<Box display="flex">
|
||||
<Table>
|
||||
<TableBody>{elems}</TableBody>
|
||||
</Table>
|
||||
<FragmentInspector gift={props.gift} x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} />
|
||||
</Box>
|
||||
<FragmentSelector gift={props.gift} selectFragment={updateSelectedFragment} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
36
src/CotMG/ui/StaneksGiftRoot.tsx
Normal file
36
src/CotMG/ui/StaneksGiftRoot.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { StaneksGiftEvents } from "../StaneksGiftEvents";
|
||||
import { Grid } from "./Grid";
|
||||
import { IStaneksGift } from "../IStaneksGift";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
type IProps = {
|
||||
staneksGift: IStaneksGift;
|
||||
};
|
||||
|
||||
export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
const setRerender = useState(true)[1];
|
||||
function rerender(): void {
|
||||
setRerender((o) => !o);
|
||||
}
|
||||
useEffect(() => StaneksGiftEvents.subscribe(rerender), []);
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h4">Stanek's Gift</Typography>
|
||||
<Typography>
|
||||
The gift is a grid on which you can place upgrades called fragments. The main type of fragment increases a stat,
|
||||
like your hacking skill or agility exp. Once a stat fragment is placed it then needs to be charged via scripts
|
||||
in order to become useful. The other kind of fragment is called booster fragments. They increase the efficiency
|
||||
of the charged happening on fragments neighboring them (no diagonal)
|
||||
</Typography>
|
||||
{staneksGift.storedCycles > 5 && (
|
||||
<Typography>
|
||||
Bonus time: {convertTimeMsToTimeElapsedString(CONSTANTS._idleSpeed * staneksGift.storedCycles)}
|
||||
</Typography>
|
||||
)}
|
||||
<Grid gift={staneksGift} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -2,26 +2,18 @@ import { DarkWebItems } from "./DarkWebItems";
|
||||
|
||||
import { Player } from "../Player";
|
||||
import { Terminal } from "../Terminal";
|
||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
import { isValidIPAddress } from "../utils/helpers/isValidIPAddress";
|
||||
|
||||
//Posts a "help" message if connected to DarkWeb
|
||||
export function checkIfConnectedToDarkweb(): void {
|
||||
if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
||||
const darkwebIp = SpecialServerIps.getIp("Darkweb Server");
|
||||
if (!isValidIPAddress(darkwebIp)) {
|
||||
return;
|
||||
}
|
||||
const server = Player.getCurrentServer();
|
||||
if (server !== null && darkwebIp == server.ip) {
|
||||
Terminal.print(
|
||||
"You are now connected to the dark web. From the dark web you can purchase illegal items. " +
|
||||
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +
|
||||
"to purchase an item.",
|
||||
);
|
||||
}
|
||||
const server = Player.getCurrentServer();
|
||||
if (server !== null && SpecialServers.DarkWeb == server.hostname) {
|
||||
Terminal.print(
|
||||
"You are now connected to the dark web. From the dark web you can purchase illegal items. " +
|
||||
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +
|
||||
"to purchase an item.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { IPlayer } from "./PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { IEngine } from "./IEngine";
|
||||
import { IRouter } from "./ui/Router";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
|
||||
import React from "react";
|
||||
|
||||
@@ -19,6 +20,7 @@ import { Corporation } from "./DevMenu/ui/Corporation";
|
||||
import { CodingContracts } from "./DevMenu/ui/CodingContracts";
|
||||
import { StockMarket } from "./DevMenu/ui/StockMarket";
|
||||
import { Sleeves } from "./DevMenu/ui/Sleeves";
|
||||
import { Stanek } from "./DevMenu/ui/Stanek";
|
||||
import { TimeSkip } from "./DevMenu/ui/TimeSkip";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
@@ -52,6 +54,7 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
|
||||
{props.player.hasWseAccount && <StockMarket />}
|
||||
|
||||
{props.player.sleeves.length > 0 && <Sleeves player={props.player} />}
|
||||
{props.player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1) && <Stanek />}
|
||||
|
||||
<TimeSkip player={props.player} engine={props.engine} />
|
||||
</>
|
||||
|
||||
@@ -30,8 +30,7 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function queueAllAugs(): void {
|
||||
for (const i in AugmentationNames) {
|
||||
const augName = AugmentationNames[i];
|
||||
for (const augName of Object.keys(AugmentationNames)) {
|
||||
props.player.queueAugmentation(augName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { AllServers } from "../../Server/AllServers";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import { GetServerByHostname } from "../../Server/ServerHelpers";
|
||||
import { GetServer, GetAllServers } from "../../Server/AllServers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
|
||||
export function Servers(): React.ReactElement {
|
||||
@@ -19,9 +18,9 @@ export function Servers(): React.ReactElement {
|
||||
setServer(event.target.value as string);
|
||||
}
|
||||
function rootServer(): void {
|
||||
const s = GetServerByHostname(server);
|
||||
const s = GetServer(server);
|
||||
if (s === null) return;
|
||||
if (s instanceof HacknetServer) return;
|
||||
if (!(s instanceof Server)) return;
|
||||
s.hasAdminRights = true;
|
||||
s.sshPortOpen = true;
|
||||
s.ftpPortOpen = true;
|
||||
@@ -32,9 +31,8 @@ export function Servers(): React.ReactElement {
|
||||
}
|
||||
|
||||
function rootAllServers(): void {
|
||||
for (const i in AllServers) {
|
||||
const s = AllServers[i];
|
||||
if (s instanceof HacknetServer) return;
|
||||
for (const s of GetAllServers()) {
|
||||
if (!(s instanceof Server)) return;
|
||||
s.hasAdminRights = true;
|
||||
s.sshPortOpen = true;
|
||||
s.ftpPortOpen = true;
|
||||
@@ -46,32 +44,30 @@ export function Servers(): React.ReactElement {
|
||||
}
|
||||
|
||||
function minSecurity(): void {
|
||||
const s = GetServerByHostname(server);
|
||||
const s = GetServer(server);
|
||||
if (s === null) return;
|
||||
if (s instanceof HacknetServer) return;
|
||||
if (!(s instanceof Server)) return;
|
||||
s.hackDifficulty = s.minDifficulty;
|
||||
}
|
||||
|
||||
function minAllSecurity(): void {
|
||||
for (const i in AllServers) {
|
||||
const server = AllServers[i];
|
||||
if (server instanceof HacknetServer) continue;
|
||||
server.hackDifficulty = server.minDifficulty;
|
||||
for (const s of GetAllServers()) {
|
||||
if (!(s instanceof Server)) return;
|
||||
s.hackDifficulty = s.minDifficulty;
|
||||
}
|
||||
}
|
||||
|
||||
function maxMoney(): void {
|
||||
const s = GetServerByHostname(server);
|
||||
const s = GetServer(server);
|
||||
if (s === null) return;
|
||||
if (s instanceof HacknetServer) return;
|
||||
if (!(s instanceof Server)) return;
|
||||
s.moneyAvailable = s.moneyMax;
|
||||
}
|
||||
|
||||
function maxAllMoney(): void {
|
||||
for (const i in AllServers) {
|
||||
const server = AllServers[i];
|
||||
if (server instanceof HacknetServer) continue;
|
||||
server.moneyAvailable = server.moneyMax;
|
||||
for (const s of GetAllServers()) {
|
||||
if (!(s instanceof Server)) return;
|
||||
s.moneyAvailable = s.moneyMax;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +85,7 @@ export function Servers(): React.ReactElement {
|
||||
</td>
|
||||
<td colSpan={2}>
|
||||
<Select id="dev-servers-dropdown" onChange={setServerDropdown} value={server}>
|
||||
{Object.values(AllServers).map((server) => (
|
||||
{GetAllServers().map((server) => (
|
||||
<MenuItem key={server.hostname} value={server.hostname}>
|
||||
{server.hostname}
|
||||
</MenuItem>
|
||||
|
||||
79
src/DevMenu/ui/Stanek.tsx
Normal file
79
src/DevMenu/ui/Stanek.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React from "react";
|
||||
|
||||
import { staneksGift } from "../../CotMG/Helper";
|
||||
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Adjuster } from "./Adjuster";
|
||||
|
||||
export function Stanek(): React.ReactElement {
|
||||
function addCycles(): void {
|
||||
staneksGift.storedCycles = 1e6;
|
||||
}
|
||||
|
||||
function modCycles(modify: number): (x: number) => void {
|
||||
return function (cycles: number): void {
|
||||
staneksGift.storedCycles += cycles * modify;
|
||||
};
|
||||
}
|
||||
|
||||
function resetCycles(): void {
|
||||
staneksGift.storedCycles = 0;
|
||||
}
|
||||
|
||||
function addCharge(): void {
|
||||
staneksGift.fragments.forEach((f) => (f.charge = 1e21));
|
||||
}
|
||||
|
||||
function modCharge(modify: number): (x: number) => void {
|
||||
return function (cycles: number): void {
|
||||
staneksGift.fragments.forEach((f) => (f.charge += cycles * modify));
|
||||
};
|
||||
}
|
||||
|
||||
function resetCharge(): void {
|
||||
staneksGift.fragments.forEach((f) => (f.charge = 0));
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography>Stanek's Gift</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<Adjuster
|
||||
label="cycles"
|
||||
placeholder="amt"
|
||||
tons={addCycles}
|
||||
add={modCycles(1)}
|
||||
subtract={modCycles(-1)}
|
||||
reset={resetCycles}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Adjuster
|
||||
label="all charge"
|
||||
placeholder="amt"
|
||||
tons={addCharge}
|
||||
add={modCharge(1)}
|
||||
subtract={modCharge(-1)}
|
||||
reset={resetCharge}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { GetServer, GetAllServers } from "../Server/AllServers";
|
||||
import { Modal } from "../ui/React/Modal";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
@@ -17,11 +17,12 @@ import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
interface IServerProps {
|
||||
ip: string;
|
||||
hostname: string;
|
||||
}
|
||||
|
||||
function ServerAccordion(props: IServerProps): React.ReactElement {
|
||||
const server = AllServers[props.ip];
|
||||
const server = GetServer(props.hostname);
|
||||
if (server === null) throw new Error("server should not be null");
|
||||
let totalSize = 0;
|
||||
for (const f of server.scripts) {
|
||||
totalSize += f.code.length;
|
||||
@@ -98,9 +99,9 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function FileDiagnosticModal(props: IProps): React.ReactElement {
|
||||
const ips: string[] = [];
|
||||
for (const ip of Object.keys(AllServers)) {
|
||||
ips.push(ip);
|
||||
const keys: string[] = [];
|
||||
for (const key in GetAllServers()) {
|
||||
keys.push(key);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -110,8 +111,8 @@ export function FileDiagnosticModal(props: IProps): React.ReactElement {
|
||||
Welcome to the file diagnostic! If your save file is really big it's likely because you have too many
|
||||
text/scripts. This tool can help you narrow down where they are.
|
||||
</Typography>
|
||||
{ips.map((ip: string) => (
|
||||
<ServerAccordion key={ip} ip={ip} />
|
||||
{keys.map((hostname: string) => (
|
||||
<ServerAccordion key={hostname} hostname={hostname} />
|
||||
))}
|
||||
</>
|
||||
</Modal>
|
||||
|
||||
@@ -11,10 +11,11 @@ Source-File minus 1 is extremely weak because it can be fully level up quickly.
|
||||
*/
|
||||
|
||||
export enum Exploit {
|
||||
UndocumentedFunctionCall = "UndocumentedFunctionCall",
|
||||
Unclickable = "Unclickable",
|
||||
PrototypeTampering = "PrototypeTampering",
|
||||
Bypass = "Bypass",
|
||||
PrototypeTampering = "PrototypeTampering",
|
||||
Unclickable = "Unclickable",
|
||||
UndocumentedFunctionCall = "UndocumentedFunctionCall",
|
||||
TimeCompression = "TimeCompression",
|
||||
// To the players reading this. Yes you're supposed to add EditSaveFile by
|
||||
// editing your save file, yes you could add them all, no we don't care
|
||||
// that's not the point.
|
||||
@@ -24,11 +25,12 @@ export enum Exploit {
|
||||
const names: {
|
||||
[key: string]: string;
|
||||
} = {
|
||||
UndocumentedFunctionCall: "by looking beyond the documentation.",
|
||||
Bypass: "by circumventing the ram cost of document.",
|
||||
EditSaveFile: "by editing your save file.",
|
||||
PrototypeTampering: "by tampering with Numbers prototype.",
|
||||
TimeCompression: "by compressing time",
|
||||
Unclickable: "by clicking the unclickable.",
|
||||
Bypass: "by circumventing the ram cost of document.",
|
||||
UndocumentedFunctionCall: "by looking beyond the documentation.",
|
||||
};
|
||||
|
||||
export function ExploitName(exploit: string): string {
|
||||
|
||||
@@ -2,13 +2,14 @@ import React from "react";
|
||||
import { use } from "../ui/Context";
|
||||
import { Exploit } from "./Exploit";
|
||||
|
||||
const getComputedStyle = window.getComputedStyle;
|
||||
export function Unclickable(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
|
||||
function unclickable(event: React.MouseEvent<HTMLDivElement>): void {
|
||||
if (!event.target || !(event.target instanceof Element)) return;
|
||||
const display = window.getComputedStyle(event.target as Element).display;
|
||||
const visibility = window.getComputedStyle(event.target as Element).visibility;
|
||||
const display = getComputedStyle(event.target as Element).display;
|
||||
const visibility = getComputedStyle(event.target as Element).visibility;
|
||||
if (display === "none" && visibility === "hidden" && event.isTrusted) player.giveExploit(Exploit.Unclickable);
|
||||
}
|
||||
|
||||
|
||||
35
src/Exploits/loops.ts
Normal file
35
src/Exploits/loops.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Player } from "../Player";
|
||||
import { Exploit } from "./Exploit";
|
||||
|
||||
function tampering(): void {
|
||||
if (Player.exploits.includes(Exploit.PrototypeTampering)) return;
|
||||
// Tampering
|
||||
const a = 55;
|
||||
setInterval(function () {
|
||||
if (a.toExponential() !== "5.5e+1") {
|
||||
Player.giveExploit(Exploit.PrototypeTampering);
|
||||
}
|
||||
}, 15 * 60 * 1000); // 15 minutes
|
||||
}
|
||||
|
||||
function timeCompression(): void {
|
||||
if (Player.exploits.includes(Exploit.TimeCompression)) return;
|
||||
// Time compression
|
||||
let last = new Date().getTime();
|
||||
function minute(): void {
|
||||
const now = new Date().getTime();
|
||||
if (now - last < 500) {
|
||||
// time has been compressed.
|
||||
Player.giveExploit(Exploit.TimeCompression);
|
||||
return;
|
||||
}
|
||||
last = now;
|
||||
window.setTimeout(minute, 1000);
|
||||
}
|
||||
window.setTimeout(minute, 1000);
|
||||
}
|
||||
|
||||
export function startExploits(): void {
|
||||
tampering();
|
||||
timeCompression();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { Player } from "../Player";
|
||||
import { Exploit } from "./Exploit";
|
||||
|
||||
export function startTampering(): void {
|
||||
const a = 55;
|
||||
setInterval(function () {
|
||||
if (a.toExponential() !== "5.5e+1") {
|
||||
Player.giveExploit(Exploit.PrototypeTampering);
|
||||
}
|
||||
}, 15 * 60 * 1000); // 15 minutes
|
||||
}
|
||||
@@ -50,6 +50,11 @@ export class FactionInfo {
|
||||
*/
|
||||
keep: boolean;
|
||||
|
||||
/**
|
||||
* Special faction
|
||||
*/
|
||||
special: boolean;
|
||||
|
||||
constructor(
|
||||
infoText: JSX.Element,
|
||||
enemies: string[],
|
||||
@@ -57,6 +62,7 @@ export class FactionInfo {
|
||||
offerHackingWork: boolean,
|
||||
offerFieldWork: boolean,
|
||||
offerSecurityWork: boolean,
|
||||
special: boolean,
|
||||
keep: boolean,
|
||||
) {
|
||||
this.infoText = infoText;
|
||||
@@ -70,6 +76,7 @@ export class FactionInfo {
|
||||
this.augmentationPriceMult = 1;
|
||||
this.augmentationRepRequirementMult = 1;
|
||||
this.keep = keep;
|
||||
this.special = special;
|
||||
}
|
||||
|
||||
offersWork(): boolean {
|
||||
@@ -96,6 +103,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
Daedalus: new FactionInfo(
|
||||
@@ -106,6 +114,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
"The Covenant": new FactionInfo(
|
||||
@@ -124,6 +133,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
// Megacorporations, each forms its own faction
|
||||
@@ -139,6 +149,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
@@ -158,6 +169,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
@@ -175,10 +187,11 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
"Blade Industries": new FactionInfo(<>Augmentation is Salvation.</>, [], true, true, true, true, true),
|
||||
"Blade Industries": new FactionInfo(<>Augmentation is Salvation.</>, [], true, true, true, true, false, true),
|
||||
|
||||
NWO: new FactionInfo(
|
||||
(
|
||||
@@ -193,10 +206,20 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
"Clarke Incorporated": new FactionInfo(<>The Power of the Genome - Unlocked.</>, [], true, true, true, true, true),
|
||||
"Clarke Incorporated": new FactionInfo(
|
||||
<>The Power of the Genome - Unlocked.</>,
|
||||
[],
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
"OmniTek Incorporated": new FactionInfo(
|
||||
<>Simply put, our mission is to design and build robots that make a difference.</>,
|
||||
@@ -205,6 +228,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
@@ -220,10 +244,20 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
"KuaiGong International": new FactionInfo(<>Dream big. Work hard. Make history.</>, [], true, true, true, true, true),
|
||||
"KuaiGong International": new FactionInfo(
|
||||
<>Dream big. Work hard. Make history.</>,
|
||||
[],
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
// Other Corporations
|
||||
"Fulcrum Secret Technologies": new FactionInfo(
|
||||
@@ -238,6 +272,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|
||||
@@ -261,6 +296,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
"The Black Hand": new FactionInfo(
|
||||
@@ -280,6 +316,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
// prettier-ignore
|
||||
@@ -325,6 +362,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
// City factions, essentially governments
|
||||
@@ -336,8 +374,18 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
Chongqing: new FactionInfo(
|
||||
<>Serve the People.</>,
|
||||
["Sector-12", "Aevum", "Volhaven"],
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
Chongqing: new FactionInfo(<>Serve the People.</>, ["Sector-12", "Aevum", "Volhaven"], true, true, true, true, false),
|
||||
Ishima: new FactionInfo(
|
||||
<>The East Asian Order of the Future.</>,
|
||||
["Sector-12", "Aevum", "Volhaven"],
|
||||
@@ -346,6 +394,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
"New Tokyo": new FactionInfo(
|
||||
<>Asia's World City.</>,
|
||||
@@ -355,6 +404,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
"Sector-12": new FactionInfo(
|
||||
<>The City of the Future.</>,
|
||||
@@ -364,6 +414,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
Volhaven: new FactionInfo(
|
||||
<>Benefit, Honor, and Glory.</>,
|
||||
@@ -373,6 +424,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
// Criminal Organizations/Gangs
|
||||
@@ -384,6 +436,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
"The Dark Army": new FactionInfo(
|
||||
@@ -394,9 +447,10 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
"The Syndicate": new FactionInfo(<>Honor holds you back.</>, [], true, true, true, true, false),
|
||||
"The Syndicate": new FactionInfo(<>Honor holds you back.</>, [], true, true, true, true, false, false),
|
||||
|
||||
Silhouette: new FactionInfo(
|
||||
(
|
||||
@@ -415,6 +469,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
Tetrads: new FactionInfo(
|
||||
@@ -425,14 +480,15 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
"Slum Snakes": new FactionInfo(<>Slum Snakes rule!</>, [], false, false, true, true, false),
|
||||
"Slum Snakes": new FactionInfo(<>Slum Snakes rule!</>, [], false, false, true, true, false, false),
|
||||
|
||||
// Earlygame factions - factions the player will prestige with early on that don't belong in other categories.
|
||||
Netburners: new FactionInfo(<>{"~~//*>H4CK||3T 8URN3R5**>?>\\~~"}</>, [], true, true, false, false, false),
|
||||
Netburners: new FactionInfo(<>{"~~//*>H4CK||3T 8URN3R5**>?>\\~~"}</>, [], true, true, false, false, false, false),
|
||||
|
||||
"Tian Di Hui": new FactionInfo(<>Obey Heaven and work righteously.</>, [], true, true, false, true, false),
|
||||
"Tian Di Hui": new FactionInfo(<>Obey Heaven and work righteously.</>, [], true, true, false, true, false, false),
|
||||
|
||||
CyberSec: new FactionInfo(
|
||||
(
|
||||
@@ -448,6 +504,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|
||||
// Special Factions
|
||||
@@ -466,6 +523,50 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
|
||||
// prettier-ignore
|
||||
"Church of the Machine God": new FactionInfo(<>
|
||||
{" `` "}<br />
|
||||
{" -odmmNmds: "}<br />
|
||||
{" `hNmo:..-omNh. "}<br />
|
||||
{" yMd` `hNh "}<br />
|
||||
{" mMd oNm "}<br />
|
||||
{" oMNo .mM/ "}<br />
|
||||
{" `dMN+ -mM+ "}<br />
|
||||
{" -mMNo -mN+ "}<br />
|
||||
{" .+- :mMNo/mN/ "}<br />
|
||||
{":yNMd. :NMNNN/ "}<br />
|
||||
{"-mMMMh. /NMMh` "}<br />
|
||||
{" .dMMMd. /NMMMy` "}<br />
|
||||
{" `yMMMd. /NNyNMMh` "}<br />
|
||||
{" `sMMMd. +Nm: +NMMh. "}<br />
|
||||
{" oMMMm- oNm: /NMMd. "}<br />
|
||||
{" +NMMmsMm- :mMMd. "}<br />
|
||||
{" /NMMMm- -mMMd. "}<br />
|
||||
{" /MMMm- -mMMd. "}<br />
|
||||
{" `sMNMMm- .mMmo "}<br />
|
||||
{" `sMd:hMMm. ./. "}<br />
|
||||
{" `yMy` `yNMd` "}<br />
|
||||
{" `hMs` oMMy "}<br />
|
||||
{" `hMh sMN- "}<br />
|
||||
{" /MM- .NMo "}<br />
|
||||
{" +MM: :MM+ "}<br />
|
||||
{" sNNo-.`.-omNy` "}<br />
|
||||
{" -smNNNNmdo- "}<br />
|
||||
{" `..` "}<br /><br />
|
||||
Many cultures predict an end to humanity in the near future, a final
|
||||
Armageddon that will end the world; but we disagree.
|
||||
<br /><br />Note that for this faction, reputation can
|
||||
only be gained by charging Stanek's gift.</>,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
),
|
||||
};
|
||||
|
||||
@@ -41,6 +41,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
if (isPlayersGang) {
|
||||
const augs: string[] = [];
|
||||
for (const augName in Augmentations) {
|
||||
if (augName === AugmentationNames.NeuroFluxGovernor) continue;
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug.isSpecial) {
|
||||
augs.push(augName);
|
||||
|
||||
@@ -19,8 +19,7 @@ import { HashUpgrades } from "./HashUpgrades";
|
||||
import { generateRandomContract } from "../CodingContractGenerator";
|
||||
import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
import { Server } from "../Server/Server";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
|
||||
@@ -416,11 +415,10 @@ function processAllHacknetServerEarnings(player: IPlayer, numCycles: number): nu
|
||||
// Also, update the hash rate before processing
|
||||
const ip = player.hacknetNodes[i];
|
||||
if (ip instanceof HacknetNode) throw new Error(`player nodes should not be HacketNode`);
|
||||
const hserver = AllServers[ip];
|
||||
if (hserver instanceof Server) throw new Error(`player nodes shoud not be Server`);
|
||||
const hserver = GetServer(ip);
|
||||
if (!(hserver instanceof HacknetServer)) throw new Error(`player nodes shoud not be Server`);
|
||||
hserver.updateHashRate(player.hacknet_node_money_mult);
|
||||
const h = hserver.process(numCycles);
|
||||
hserver.totalHashesGenerated += h;
|
||||
hashes += h;
|
||||
}
|
||||
|
||||
@@ -449,7 +447,7 @@ export function updateHashManagerCapacity(player: IPlayer): void {
|
||||
}
|
||||
const ip = nodes[i];
|
||||
if (ip instanceof HacknetNode) throw new Error(`player nodes should be string but isn't`);
|
||||
const h = AllServers[ip];
|
||||
const h = GetServer(ip);
|
||||
if (!(h instanceof HacknetServer)) {
|
||||
player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
@@ -489,7 +487,7 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
|
||||
}
|
||||
case "Reduce Minimum Security": {
|
||||
try {
|
||||
const target = GetServerByHostname(upgTarget);
|
||||
const target = GetServer(upgTarget);
|
||||
if (target == null) {
|
||||
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
||||
return false;
|
||||
@@ -505,14 +503,16 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
|
||||
}
|
||||
case "Increase Maximum Money": {
|
||||
try {
|
||||
const target = GetServerByHostname(upgTarget);
|
||||
const target = GetServer(upgTarget);
|
||||
if (target == null) {
|
||||
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
||||
return false;
|
||||
}
|
||||
if (!(target instanceof Server)) throw new Error(`'${upgTarget}' is not a normal server.`);
|
||||
|
||||
target.changeMaximumMoney(upg.value, true);
|
||||
const old = target.moneyMax;
|
||||
target.changeMaximumMoney(upg.value);
|
||||
console.log(target.moneyMax / old);
|
||||
} catch (e) {
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
|
||||
@@ -77,8 +77,12 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
// Process this Hacknet Server in the game loop. Returns the number of hashes generated
|
||||
process(numCycles = 1): number {
|
||||
const seconds = (numCycles * CONSTANTS.MilliPerCycle) / 1000;
|
||||
this.onlineTimeSeconds += seconds;
|
||||
|
||||
return this.hashRate * seconds;
|
||||
const hashes = this.hashRate * seconds;
|
||||
this.totalHashesGenerated += hashes;
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
upgradeCache(levels: number): void {
|
||||
|
||||
@@ -18,7 +18,7 @@ export const HacknetNodeConstants: {
|
||||
MaxRam: number;
|
||||
MaxCores: number;
|
||||
} = {
|
||||
MoneyGainPerLevel: 1.6,
|
||||
MoneyGainPerLevel: 1.5,
|
||||
|
||||
BaseCost: 1000,
|
||||
LevelBaseCost: 1,
|
||||
|
||||
@@ -28,6 +28,7 @@ import { TableCell } from "../../ui/React/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
interface IProps {
|
||||
node: HacknetNode;
|
||||
@@ -163,7 +164,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
|
||||
<Typography>RAM:</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>{node.ram}GB</Typography>
|
||||
<Typography>{numeralWrapper.formatRAM(node.ram)}</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button onClick={upgradeRamOnClick}>{upgradeRamContent}</Button>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { GeneralInfo } from "./GeneralInfo";
|
||||
import { HacknetNodeElem } from "./HacknetNodeElem";
|
||||
import { HacknetServerElem } from "./HacknetServerElem";
|
||||
import { HacknetNode } from "../HacknetNode";
|
||||
import { HacknetServer } from "../HacknetServer";
|
||||
import { HashUpgradeModal } from "./HashUpgradeModal";
|
||||
import { MultiplierButtons } from "./MultiplierButtons";
|
||||
import { PlayerInfo } from "./PlayerInfo";
|
||||
@@ -21,8 +22,7 @@ import {
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { AllServers } from "../../Server/AllServers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Grid from "@mui/material/Grid";
|
||||
@@ -50,8 +50,8 @@ export function HacknetRoot(props: IProps): React.ReactElement {
|
||||
const node = props.player.hacknetNodes[i];
|
||||
if (hasHacknetServers(props.player)) {
|
||||
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
|
||||
const hserver = AllServers[node];
|
||||
if (hserver instanceof Server) throw new Error("node was a normal server"); // should never happen
|
||||
const hserver = GetServer(node);
|
||||
if (!(hserver instanceof HacknetServer)) throw new Error("node was not hacknet server"); // should never happen
|
||||
if (hserver) {
|
||||
totalProduction += hserver.hashRate;
|
||||
} else {
|
||||
@@ -88,11 +88,11 @@ export function HacknetRoot(props: IProps): React.ReactElement {
|
||||
const nodes = props.player.hacknetNodes.map((node: string | HacknetNode) => {
|
||||
if (hasHacknetServers(props.player)) {
|
||||
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
|
||||
const hserver = AllServers[node];
|
||||
const hserver = GetServer(node);
|
||||
if (hserver == null) {
|
||||
throw new Error(`Could not find Hacknet Server object in AllServers map for IP: ${node}`);
|
||||
}
|
||||
if (hserver instanceof Server) throw new Error("node was normal server"); // should never happen
|
||||
if (!(hserver instanceof HacknetServer)) throw new Error("node was not hacknet server"); // should never happen
|
||||
return (
|
||||
<HacknetServerElem
|
||||
player={props.player}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { TableCell } from "../../ui/React/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
interface IProps {
|
||||
node: HacknetServer;
|
||||
@@ -213,7 +214,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
|
||||
<Typography>RAM:</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography>{node.maxRam}GB</Typography>
|
||||
<Typography>{numeralWrapper.formatRAM(node.maxRam)}</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button onClick={upgradeRamOnClick}>{upgradeRamContent}</Button>
|
||||
|
||||
@@ -64,13 +64,21 @@ export function HacknetUpgradeElem(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
|
||||
<Typography>{upg.desc}</Typography>
|
||||
<Button onClick={purchase} disabled={!canPurchase}>
|
||||
Purchase
|
||||
</Button>
|
||||
{level > 0 && effect && <Typography>{effect}</Typography>}
|
||||
{upg.hasTargetServer && (
|
||||
<ServerDropdown value={selectedServer} serverType={ServerType.Foreign} onChange={changeTargetServer} />
|
||||
{!upg.hasTargetServer && (
|
||||
<Button onClick={purchase} disabled={!canPurchase}>
|
||||
Buy
|
||||
</Button>
|
||||
)}
|
||||
{upg.hasTargetServer && (
|
||||
<ServerDropdown
|
||||
purchase={purchase}
|
||||
canPurchase={canPurchase}
|
||||
value={selectedServer}
|
||||
serverType={ServerType.Foreign}
|
||||
onChange={changeTargetServer}
|
||||
/>
|
||||
)}
|
||||
{level > 0 && effect && <Typography>{effect}</Typography>}
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ export function Cyberpunk2077Game(props: IMinigameProps): React.ReactElement {
|
||||
<br />
|
||||
{grid.map((line, y) => (
|
||||
<div key={y}>
|
||||
<pre>
|
||||
<Typography>
|
||||
{line.map((cell, x) => {
|
||||
if (x == pos[0] && y == pos[1])
|
||||
return (
|
||||
@@ -110,7 +110,7 @@ export function Cyberpunk2077Game(props: IMinigameProps): React.ReactElement {
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</pre>
|
||||
</Typography>
|
||||
<br />
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -85,7 +85,7 @@ export function MinesweeperGame(props: IMinigameProps): React.ReactElement {
|
||||
<Typography variant="h4">{memoryPhase ? "Remember all the mines!" : "Mark all the mines!"}</Typography>
|
||||
{minefield.map((line, y) => (
|
||||
<div key={y}>
|
||||
<pre>
|
||||
<Typography>
|
||||
{line.map((cell, x) => {
|
||||
if (memoryPhase) {
|
||||
if (minefield[y][x]) return <span key={x}>[?] </span>;
|
||||
@@ -96,7 +96,7 @@ export function MinesweeperGame(props: IMinigameProps): React.ReactElement {
|
||||
return <span key={x}>[ ] </span>;
|
||||
}
|
||||
})}
|
||||
</pre>
|
||||
</Typography>
|
||||
<br />
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -98,14 +98,14 @@ export function WireCuttingGame(props: IMinigameProps): React.ReactElement {
|
||||
{questions.map((question, i) => (
|
||||
<Typography key={i}>{question.toString()}</Typography>
|
||||
))}
|
||||
<pre>
|
||||
<Typography>
|
||||
{new Array(wires.length).fill(0).map((_, i) => (
|
||||
<span key={i}> {i + 1} </span>
|
||||
))}
|
||||
</pre>
|
||||
</Typography>
|
||||
{new Array(8).fill(0).map((_, i) => (
|
||||
<div key={i}>
|
||||
<pre>
|
||||
<Typography>
|
||||
{wires.map((wire, j) => {
|
||||
if ((i === 3 || i === 4) && cutWires[j])
|
||||
return <span key={j}> </span>;
|
||||
@@ -115,7 +115,7 @@ export function WireCuttingGame(props: IMinigameProps): React.ReactElement {
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</pre>
|
||||
</Typography>
|
||||
</div>
|
||||
))}
|
||||
<KeyHandler onKeyDown={press} onFailure={props.onFailure} />
|
||||
|
||||
@@ -84,8 +84,8 @@ Cities[CityName.Chongqing].asciiArt = `
|
||||
[world stock exchange] F |
|
||||
\\ o 78 [kuaigong international]
|
||||
\\ /
|
||||
38 o----x--x------x------A---------
|
||||
/ 39 | 41
|
||||
38 o----x--x------x------A------G--
|
||||
/ 39 | 41 [church]
|
||||
37 o + 79 o--x--x-C-0
|
||||
/ | /
|
||||
/ x-----+-----x-----0 [hospital]
|
||||
|
||||
@@ -7,7 +7,6 @@ import { CONSTANTS } from "../Constants";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { AddToAllServers, createUniqueRandomIp } from "../Server/AllServers";
|
||||
import { safetlyCreateUniqueServer } from "../Server/ServerHelpers";
|
||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
|
||||
@@ -36,10 +35,9 @@ export function purchaseTorRouter(p: IPlayer): void {
|
||||
maxRam: 1,
|
||||
});
|
||||
AddToAllServers(darkweb);
|
||||
SpecialServerIps.addIp("Darkweb Server", darkweb.ip);
|
||||
|
||||
p.getHomeComputer().serversOnNetwork.push(darkweb.ip);
|
||||
darkweb.serversOnNetwork.push(p.getHomeComputer().ip);
|
||||
p.getHomeComputer().serversOnNetwork.push(darkweb.hostname);
|
||||
darkweb.serversOnNetwork.push(p.getHomeComputer().hostname);
|
||||
dialogBoxCreate(
|
||||
"You have purchased a TOR router!<br>" +
|
||||
"You now have access to the dark web from your home computer.<br>" +
|
||||
|
||||
@@ -29,6 +29,7 @@ export enum LocationName {
|
||||
// Chongqing locations
|
||||
ChongqingKuaiGongInternational = "KuaiGong International",
|
||||
ChongqingSolarisSpaceSystems = "Solaris Space Systems",
|
||||
ChongqingChurchOfTheMachineGod = "Church of the Machine God",
|
||||
|
||||
// Sector 12
|
||||
Sector12AlphaEnterprises = "Alpha Enterprises",
|
||||
|
||||
@@ -440,4 +440,9 @@ export const LocationsMetadata: IConstructorParams[] = [
|
||||
name: LocationName.WorldStockExchange,
|
||||
types: [LocationType.StockMarket],
|
||||
},
|
||||
{
|
||||
city: CityName.Chongqing,
|
||||
name: LocationName.ChongqingChurchOfTheMachineGod,
|
||||
types: [LocationType.Special],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -23,8 +23,8 @@ import { LocationType } from "../LocationTypeEnum";
|
||||
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
import { getServer, isBackdoorInstalled } from "../../Server/ServerHelpers";
|
||||
import { isBackdoorInstalled } from "../../Server/ServerHelpers";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { use } from "../../ui/Context";
|
||||
@@ -83,8 +83,7 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
const locContent: React.ReactNode[] = getLocationSpecificContent();
|
||||
const ip = SpecialServerIps.getIp(loc.name);
|
||||
const server = getServer(ip);
|
||||
const server = GetServer(loc.name);
|
||||
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||
|
||||
return (
|
||||
|
||||
@@ -10,9 +10,8 @@ import { Location } from "../Location";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { getServer } from "../../Server/ServerHelpers";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
@@ -25,8 +24,7 @@ type IProps = {
|
||||
|
||||
export function GymLocation(props: IProps): React.ReactElement {
|
||||
function calculateCost(): number {
|
||||
const ip = SpecialServerIps.getIp(props.loc.name);
|
||||
const server = getServer(ip);
|
||||
const server = GetServer(props.loc.name);
|
||||
if (server == null || !server.hasOwnProperty("backdoorInstalled")) return props.loc.costMult;
|
||||
const discount = (server as Server).backdoorInstalled ? 0.9 : 1;
|
||||
return props.loc.costMult * discount;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { purchaseRamForHomeComputer } from "../../Server/ServerPurchases";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MathComponent } from "mathjax-react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
@@ -31,7 +32,8 @@ export function RamButton(props: IProps): React.ReactElement {
|
||||
<Tooltip title={<MathComponent tex={String.raw`\large{cost = 3.2 \times 10^3 \times 1.58^{log_2{(ram)}}}`} />}>
|
||||
<span>
|
||||
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
|
||||
Upgrade 'home' RAM ({homeComputer.maxRam}GB -> {homeComputer.maxRam * 2}GB) -
|
||||
Upgrade 'home' RAM ({numeralWrapper.formatRAM(homeComputer.maxRam)} ->
|
||||
{numeralWrapper.formatRAM(homeComputer.maxRam * 2)}) -
|
||||
<Money money={cost} player={props.p} />
|
||||
</Button>
|
||||
</span>
|
||||
|
||||
@@ -17,6 +17,9 @@ import Button from "@mui/material/Button";
|
||||
import { Location } from "../Location";
|
||||
import { CreateCorporationModal } from "../../Corporation/ui/CreateCorporationModal";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { joinFaction } from "../../Faction/FactionHelpers";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
@@ -109,6 +112,107 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return <Button onClick={handleResleeving}>Re-Sleeve</Button>;
|
||||
}
|
||||
|
||||
function handleCotMG(): void {
|
||||
const faction = Factions["Church of the Machine God"];
|
||||
if (!player.factions.includes("Church of the Machine God")) {
|
||||
joinFaction(faction);
|
||||
}
|
||||
if (
|
||||
!player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1) &&
|
||||
!player.queuedAugmentations.some((a) => a.name === AugmentationNames.StaneksGift1)
|
||||
) {
|
||||
player.queueAugmentation(AugmentationNames.StaneksGift1);
|
||||
}
|
||||
|
||||
router.toFaction(faction);
|
||||
}
|
||||
|
||||
function renderCotMG(): React.ReactElement {
|
||||
// prettier-ignore
|
||||
const symbol = <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>
|
||||
{" `` "}<br />
|
||||
{" -odmmNmds: "}<br />
|
||||
{" `hNmo:..-omNh. "}<br />
|
||||
{" yMd` `hNh "}<br />
|
||||
{" mMd oNm "}<br />
|
||||
{" oMNo .mM/ "}<br />
|
||||
{" `dMN+ -mM+ "}<br />
|
||||
{" -mMNo -mN+ "}<br />
|
||||
{" .+- :mMNo/mN/ "}<br />
|
||||
{":yNMd. :NMNNN/ "}<br />
|
||||
{"-mMMMh. /NMMh` "}<br />
|
||||
{" .dMMMd. /NMMMy` "}<br />
|
||||
{" `yMMMd. /NNyNMMh` "}<br />
|
||||
{" `sMMMd. +Nm: +NMMh. "}<br />
|
||||
{" oMMMm- oNm: /NMMd. "}<br />
|
||||
{" +NMMmsMm- :mMMd. "}<br />
|
||||
{" /NMMMm- -mMMd. "}<br />
|
||||
{" /MMMm- -mMMd. "}<br />
|
||||
{" `sMNMMm- .mMmo "}<br />
|
||||
{" `sMd:hMMm. ./. "}<br />
|
||||
{" `yMy` `yNMd` "}<br />
|
||||
{" `hMs` oMMy "}<br />
|
||||
{" `hMh sMN- "}<br />
|
||||
{" /MM- .NMo "}<br />
|
||||
{" +MM: :MM+ "}<br />
|
||||
{" sNNo-.`.-omNy` "}<br />
|
||||
{" -smNNNNmdo- "}<br />
|
||||
{" `..` "}</Typography>
|
||||
if (player.factions.includes("Church of the Machine God")) {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
<i>Allison "Mother" Stanek: Welcome back my child!</i>
|
||||
</Typography>
|
||||
{symbol}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (!player.canAccessCotMG()) {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
A decrepit altar stands in the middle of a dilapidated church.
|
||||
<br />
|
||||
<br />A symbol is carved in the altar.
|
||||
</Typography>
|
||||
<br />
|
||||
{symbol}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
player.augmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0 ||
|
||||
player.queuedAugmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0
|
||||
) {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
<i>
|
||||
Allison "Mother" Stanek: Begone you filth! My gift must be the first modification that your body should
|
||||
have!
|
||||
</i>
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
<i>
|
||||
Allison "Mother" Stanek: Welcome child, I see your body is pure. Are you ready to ascend beyond our human
|
||||
form? If you are, accept my gift.
|
||||
</i>
|
||||
</Typography>
|
||||
<Button onClick={handleCotMG}>Accept Stanek's Gift</Button>
|
||||
{symbol}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
switch (props.loc.name) {
|
||||
case LocationName.NewTokyoVitaLife: {
|
||||
return renderResleeving();
|
||||
@@ -122,6 +226,9 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
case LocationName.NewTokyoNoodleBar: {
|
||||
return renderNoodleBar();
|
||||
}
|
||||
case LocationName.ChongqingChurchOfTheMachineGod: {
|
||||
return renderCotMG();
|
||||
}
|
||||
default:
|
||||
console.error(`Location ${props.loc.name} doesn't have any special properties`);
|
||||
return <></>;
|
||||
|
||||
@@ -17,6 +17,7 @@ import { getPurchaseServerCost } from "../../Server/ServerPurchases";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { use } from "../../ui/Context";
|
||||
import { PurchaseServerModal } from "./PurchaseServerModal";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
interface IServerProps {
|
||||
ram: number;
|
||||
@@ -30,7 +31,7 @@ function ServerButton(props: IServerProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setOpen(true)} disabled={!player.canAfford(cost)}>
|
||||
Purchase {props.ram}GB Server -
|
||||
Purchase {numeralWrapper.formatRAM(props.ram)} Server -
|
||||
<Money money={cost} player={player} />
|
||||
</Button>
|
||||
<PurchaseServerModal
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user