Compare commits

...

100 Commits

Author SHA1 Message Date
Olivier Gagnon
d96ad9fa6e v0.51.8 2021-05-07 22:26:02 -04:00
Olivier Gagnon
5dd32ef4e4 Scripts transfer stats to parent on death. 2021-05-07 22:01:52 -04:00
Olivier Gagnon
6dde89f3c4 0518 2021-05-07 22:01:52 -04:00
Olivier Gagnon
9a9d2e1f81 ls-changes 2021-05-07 22:01:23 -04:00
Pimvgd
d347bf568e Update Overview.jsx
fix space
2021-05-07 19:34:57 -04:00
Daniel Ferri
62e2f0582a Fixed bug with faction invitations not getting deleted 2021-05-07 19:12:30 -04:00
Daniel Ferri
68eb68a89e Added accepting numbers in 1b format to faction donations 2021-05-07 19:12:30 -04:00
Daniel Ferri
13206a8c3e Fixed casing on import
Did not want to compile without the change
2021-05-07 19:12:30 -04:00
Olivier Gagnon
8b7f140115 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-05-07 02:14:34 -04:00
Olivier Gagnon
16c8c78b54 Add installBackdoor 2021-05-07 02:13:33 -04:00
Olivier Gagnon
cbb47772db Add installBackdoor 2021-05-07 02:09:30 -04:00
Olivier Gagnon
0642491402 hotfix backdooring the world daemon not resetting flags 2021-05-06 11:12:41 -04:00
Olivier Gagnon
c7e34d4a56 hotfix backdooring the world daemon not resetting flags 2021-05-06 11:12:04 -04:00
hydroflame
8be63be17b Merge pull request #942 from danielyxie/dev
Another build for the quick and easy stuff.
2021-05-05 21:40:14 -04:00
Olivier Gagnon
08207ac79b another build 2021-05-05 21:39:48 -04:00
Olivier Gagnon
6747a509ff Reword the Milestones 2021-05-05 21:36:43 -04:00
Olivier Gagnon
c7c86240db Faction Donation does not appear on special or gang factions, passive rep doesnt work on gang or special factions 2021-05-05 21:32:06 -04:00
hydroflame
ce0c3d71f4 Merge pull request #941 from danielyxie/dev
hotfix for some stuff
2021-05-05 21:07:09 -04:00
Olivier Gagnon
5bb6a72c90 build 2021-05-05 21:02:54 -04:00
hydroflame
5a06c60c27 Merge pull request #940 from danielyxie/0517-2
0517 hotfix
2021-05-05 21:00:14 -04:00
Olivier Gagnon
764c2533b4 hashGainRate updated to use the correct usedRam and maxRam 2021-05-05 19:18:47 -04:00
Olivier Gagnon
a9cee6f907 Fix analyze Root Access displaying always Yes 2021-05-05 19:15:56 -04:00
Olivier Gagnon
a10100bf60 You cna now cd in dir that only contain text files. 2021-05-05 19:09:14 -04:00
Olivier Gagnon
cedac23dfa CodingContractPopup now correctly displays innerHTML, desc should be changed to return jsx though. 2021-05-05 19:06:08 -04:00
Olivier Gagnon
f7c1d64033 Delete Active Scripts actually deletes active scripts on all servers, not just home 2021-05-05 18:58:53 -04:00
hydroflame
7d6d0eac32 Merge pull request #939 from ModdedGamers/dev
Make it clear that maxNumNodes returns Infinity
2021-05-05 11:03:22 -04:00
Modded Gamers
34768591b7 Make it clear that maxNumNodes returns Infinity
this function returns Infinity in some cases, so this makes that clearer.
2021-05-05 10:00:16 -04:00
Daniel Xie
827c79f70c Add build for hotfix 2021-05-05 04:31:54 -07:00
Daniel Xie
0415c7aa7c Give NeuroFlux for SF-12 before re-calculating multipliers 2021-05-05 04:23:10 -07:00
hydroflame
0c744d98b9 Merge pull request #933 from danielyxie/dev
* .ns script no longer needlessly recompile
* scping the exact same content over doesn't trigger an actual scp
* world daemon can be backdoored
* Coding contract title is click-to-copy
* Sleeve memory covenant upgrade reacts better.
2021-05-03 19:54:31 -04:00
Olivier Gagnon
11cbda6974 build 2021-05-03 19:54:11 -04:00
Olivier Gagnon
e284f49747 Covenant sleeve memory upgrade styling and more reactive text field 2021-05-03 19:52:19 -04:00
Olivier Gagnon
7777c400a5 Make coding contract title click-to-copy 2021-05-03 19:46:04 -04:00
Olivier Gagnon
dae0448744 world daemon can now be backdoored 2021-05-03 19:00:01 -04:00
Olivier Gagnon
02a4e85353 Build nsjs recompile hotfix 2021-05-03 18:54:54 -04:00
hydroflame
3cbf225c98 Fix script needlessly being recompiled (#932)
* Fix nsjs recompiling needlesly.
2021-05-03 18:53:10 -04:00
hydroflame
8006e976a5 Merge pull request #929 from danielyxie/dev
Fix research tree not appearing
2021-05-03 18:25:04 -04:00
Olivier Gagnon
5613d371c9 Fix research tree not appearing 2021-05-03 18:24:22 -04:00
hydroflame
7c9d6669f7 Merge pull request #928 from danielyxie/dev
Hotfix Mission.jsx fake unused import
2021-05-03 17:25:19 -04:00
Olivier Gagnon
c6f0551709 Hotfix Mission.jsx fake unused import 2021-05-03 17:24:39 -04:00
hydroflame
f57eed4de1 Merge pull request #926 from danielyxie/dev
Hotfix
2021-05-03 16:03:12 -04:00
Olivier Gagnon
b99711788f Hotfix negative money, n00dles metadata and guide 2021-05-03 16:02:26 -04:00
Olivier Gagnon
08aac8e35d change noodles metadata. 2021-05-03 12:56:27 -04:00
hydroflame
e3579b7229 Merge pull request #925 from danielyxie/dev
did I forget the build again?
2021-05-03 12:27:21 -04:00
Olivier Gagnon
662d0dd5fb did I forget the build again 2021-05-03 12:26:37 -04:00
hydroflame
77c40b5d67 Merge pull request #924 from danielyxie/dev
Forgot to push the build
2021-05-03 12:21:28 -04:00
Olivier Gagnon
ee759a8dd6 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-05-03 12:20:54 -04:00
hydroflame
ad9c7ec696 Merge pull request #923 from danielyxie/dev
0.51.7
2021-05-03 12:18:18 -04:00
Olivier Gagnon
c9b5aaa2f7 v0.51.7 2021-05-03 12:17:05 -04:00
hydroflame
b554328a77 Merge pull request #915 from danielyxie/noodles
Noodles
2021-05-03 12:01:39 -04:00
Olivier Gagnon
c421c57e56 address comments. 2021-05-03 11:58:11 -04:00
hydroflame
fb42d5cd79 Merge pull request #918 from Pimvgd/patch-4
typo fixes for blackops
2021-05-03 02:26:47 -04:00
hydroflame
6203d8d6f4 Merge pull request #919 from Daniferrito/patch-2
Update ps documentation
2021-05-03 02:21:22 -04:00
Olivier Gagnon
d422028737 analyze and ServerProfiler.exe handle hacknet servers better. 2021-05-03 02:20:31 -04:00
Olivier Gagnon
136d769d55 Change faction invitation Yes,No to say Join and Decide later 2021-05-03 02:01:45 -04:00
Olivier Gagnon
daaab1d6f1 Fix forgotten text for Source-File 12 2021-05-03 01:55:04 -04:00
Olivier Gagnon
4f7befb639 Fix miscalculation of source file flags on the bitverse screen. 2021-05-03 01:50:09 -04:00
Olivier Gagnon
9976ed136c fix money formatting for amount under 1000 2021-05-03 01:44:02 -04:00
Olivier Gagnon
8c2e661e08 Remove console.log 2021-05-03 01:41:16 -04:00
Olivier Gagnon
e6e598eeb4 moved augmentations between city faction to be more even. 2021-05-03 01:40:22 -04:00
Olivier Gagnon
4d9439a007 Added getServerMaxRam and getServerUsedRam, deprecated getServerRam 2021-05-03 01:07:46 -04:00
Olivier Gagnon
9951c8b18f Fix mistake in hacknet API example 2021-05-03 00:51:12 -04:00
Olivier Gagnon
800c673839 Fix character-overview-text being nested twice. 2021-05-03 00:47:56 -04:00
Olivier Gagnon
065544909b thread count formatted with commas every thousands. 2021-05-03 00:45:21 -04:00
Olivier Gagnon
4eaf68c940 Donation is always visible but locked before favor requirements are fulfilled. 2021-05-03 00:37:53 -04:00
Olivier Gagnon
a14a694df3 Fix sleeves not being to work out at volhaven 2021-05-03 00:27:12 -04:00
Dani
3ab61cbaf3 Update ps documentation 2021-05-02 23:48:20 +02:00
Pimvgd
f49aff05d7 typo fixes for blackops 2021-05-02 23:44:59 +02:00
hydroflame
e2371a0ef6 Merge pull request #917 from Daniferrito/patch-1
Fixed #916
2021-05-02 17:38:47 -04:00
Dani
6a2b3ee52e Fixed #916 2021-05-02 23:37:09 +02:00
Olivier Gagnon
5a45e3584d Formatted time in netscript hgw display in human time, milliFormat now displays milli sometimes 2021-05-02 01:04:49 -04:00
Olivier Gagnon
56ce83cce5 Fix cashroot not displaying properly 2021-05-02 00:07:04 -04:00
Olivier Gagnon
d126b6d8c5 Fix sf minus 1 bad constant 2021-05-01 23:44:23 -04:00
Olivier Gagnon
7172ef6dae SF12 now lets player start with Neuroflux 2021-05-01 23:42:52 -04:00
Olivier Gagnon
a8d0b6e13d Tail now accepts PID 2021-05-01 23:33:44 -04:00
Olivier Gagnon
d2d6453a78 quick b1tflum3 2021-05-01 23:23:04 -04:00
Olivier Gagnon
89cdecb05f getBitnodeMultipliers is available inside BN5 2021-05-01 23:08:51 -04:00
Olivier Gagnon
81fdff9068 Revert tutorial servers and add the n00dles server. 2021-05-01 23:08:51 -04:00
hydroflame
34a20802c9 Merge pull request #910 from danielyxie/lint-fix
The mega linting patch
2021-05-01 23:08:10 -04:00
hydroflame
6d53ff109b Merge pull request #914 from Pimvgd/patch-3
Typo fixes
2021-05-01 21:50:08 -04:00
Pimvgd
8eab9f3b59 Update Bladeburner.jsx 2021-05-02 00:09:13 +02:00
Pimvgd
f40faadcc4 Update augmentations.rst 2021-05-01 18:04:27 +02:00
Pimvgd
fb129198a6 Update AugmentationHelpers.jsx
more typos
2021-05-01 17:43:13 +02:00
Pimvgd
3eecff1de6 Update netscriptbladeburnerapi.rst
fix typos
2021-05-01 17:34:55 +02:00
Olivier Gagnon
d745150c45 all the lints 2021-05-01 03:17:31 -04:00
Olivier Gagnon
abe0330dc3 css --fix 2021-04-29 23:59:43 -04:00
Olivier Gagnon
3fad505096 run auto fix lint 2021-04-29 23:52:56 -04:00
hydroflame
b2ac383b69 Merge pull request #909 from danielyxie/dev
When you hotfix you need to build
2021-04-29 13:41:48 -04:00
Olivier Gagnon
77cb63e36a When you hotfix you need to build 2021-04-29 13:41:13 -04:00
hydroflame
7df4aac8e6 Merge pull request #908 from danielyxie/dev
hotfix netscript access to formulas and getServer
2021-04-29 13:39:35 -04:00
Olivier Gagnon
50b490ba8d fix netscript access 2021-04-29 13:39:03 -04:00
hydroflame
15bd8a6233 Merge pull request #907 from danielyxie/dev
update patch notes
2021-04-28 20:26:38 -04:00
Olivier Gagnon
20c593b236 update patch notes 2021-04-28 20:25:51 -04:00
hydroflame
52a80ad236 v0.51.6 (#905)
* Make command `cd` without arguments an alias for `cd /` (#853)

In most shells `cd` without arguments takes you to the home directory
of the current user. I keep trying to do this due to muscle memory
from working in terminals, so I figured I'd make it do something useful.

There is no home directory in the game, but going to / is the closest
thing we have, since that is the starting point for the user in the
game.

* Add new `backdoor` terminal command (#852)

* Add the backdoor command to the terminal

This command will perform a manual hack without rewarding money. It will be used for the story, mainly for faction hacking tests

* Add tab completion for backdoor command

* Add help text for backdoor command

* Change condition syntax to be more consistent with others

* Extract reused code block so it is always called after actions

* Update documentation for new backdoor command

Modified references to manual hack as it isn't for factions anymore

* Remove extra parenthesis

* Rename manuallyHacked to backdoorInstalled

* Fix typo

* Change faction test messages to use backdoor instad of hack

* Rename more instances of manuallyHacked

* fixed typo in helptext of darkweb buy (#858)

* Fix typos and unify descriptions of augmentations (#859)

Made an attempt to...
- give all "+rep% company/faction" the same text
- make all augmentations with a single effect use a single line to describe the effect
- make all effects end with a period

* Made Cashroot starter kit display its tooltip with the money formatted properly and in gold

* fix typo in docs (#860)

* Initial code for Casino Card Deck implementation

* Casino Blackjack Implementation

* Update some tools (eslint, typescript)

* Blackjack code cleanup

* Update README_contribution

* Update ScriptHelpers.js (#861)

expand error message

* More augmentation typo fixes (#862)

* Add Netscript function getCurrentScript (#856)

Add netscript function that returns the current script.

* Added milestones menu to guide new players. (#865)

Milestone menu

* fix typos in milestones (#866)

Co-authored-by: sschmidTU <s.schmid@phonicscore.com>

* Corrupt location title when backdoor is installed (#864)

* Add corruptableText component

* Corrupt location title if backdoor is installed

* Formatting

* Add helper to check value of backdoorInstalled

Helper could be oneline but it would make it less readable

* Fix some formatting

* Add settings option to disable text effects

* Import useState

* getRunningScript (#867)

* Replaced getCurrentScript with getRunningScript

* Bunch of smaller fixes (#904)

Fix #884
Fix #879
Fix #878
Fix #876
Fix #874
Fix #873
Fix #887
Fix #891
Fix #895

* rework the early servers to be more noob friendly (#903)

* v0.51.6

Co-authored-by: Andreas Eriksson <2691182+AndreasTPC@users.noreply.github.com>
Co-authored-by: Jack <jackdewinter1@gmail.com>
Co-authored-by: Teun Pronk <5228255+Crownie88@users.noreply.github.com>
Co-authored-by: Pimvgd <Pimvgd@gmail.com>
Co-authored-by: Daniel Xie <daniel.xie@flockfreight.com>
Co-authored-by: Simon <33069673+sschmidTU@users.noreply.github.com>
Co-authored-by: sschmidTU <s.schmid@phonicscore.com>
2021-04-28 20:07:26 -04:00
hydroflame
b2aafea656 v0.51.5 (#848) 2021-04-21 08:20:26 -04:00
hydroflame
135df8703c V0.51.4 (#847)
* BladeBurner
    * nerfed int exp gained.

    Documentation
    * purchaseServer specifies what happens on failure.
    * Fixed typo in recommended bitnode page.
    * Removed misleading ram requirements for hacking factions.

    Netscript
    * growthAnalyze handles Infinity correctly.

    Misc.
    * Faction Augmentation will list how much reputation is required even after
      that goal has been reached.
    * Removed dollar sign in travel agency confirmation.
    * Fixed typo in alpha-omega.lit

* the game save text no longer obstruct the save game and options button

* the text editors now remember where your cursor was and restores it when loading the same script again.

* v0.51.4
2021-04-19 21:26:51 -04:00
hydroflame
4743801e86 hotfix (#846) 2021-04-18 11:33:46 -04:00
hydroflame
4e5ebcfe6f V0.51.3 (#845)
v0.51.3 - 2021-04-16 Y'all broke it on the first day (hydroflame)
-------

Passive faction reputation
* Reworked, from 1 rep / 2 minute. Now is a complicated percentage of the
  reputation you'd gain working for them. It's not op but it feels a bit
  more useful.

Netscript
* print/tprint now take any number of arguments.
* print/tprint will now print object as json.
* print/tprint now handle passing in an undefined argument properly.

Casino
* Cannot bet negative money anymore.
* Roulette max bet is a bit higher.
* Coin Flip has a small cooldown.
* All buttons reject unstrusted mouse events.

Documentation
* Changed a message that said nsjs only works on Chrome.

Bugfix
* hacknet.maxNumNodes now works for both nodes and servers.
* Fixed a bug where the popup boxes would contain data from previous popup boxes.
* .js files will also have the export async function boilerplate.

Misc.
* turned off autocomplete for the terminal text input.
* Fixed an issue on Windows+Firefox where pressing up on the terminal would
  bring the cursor to the begining of the line. (Issue #836)
* Hacknet node names is easier to handle for screen readers.
* Money spent on classes is now tracked independently of work money.
* running coding contract from the terminal will display its name.
2021-04-18 11:18:56 -04:00
hydroflame
80b703639e Small hotfix (#840)
* yesno box now correctly clean up before new content is loaded in.

* formatHp doesnt display decimal, duh

* character overview uses numeralWrapper formatHp

* minor formatting stuff

* Class spending is tracked indepedently of work money

* Made an augmentation named after myself.

* hotfix a bunch of small stuff
2021-04-12 20:03:32 -04:00
hydroflame
0afdba8f38 fixed ns imports requiring semicolon (#839) 2021-04-10 02:26:13 -04:00
376 changed files with 15064 additions and 10032 deletions

View File

@@ -2,3 +2,7 @@ node_modules/
doc/build/
dist/
tests/*.bundle.*
src/ThirdParty/*
src/ScriptEditor/CodeMirrorNetscriptMode.js
src/ScriptEditor/CodeMirrorNetscriptLint.js
src/JSInterpreter.js

File diff suppressed because it is too large Load Diff

View File

@@ -7,4 +7,17 @@ Update the following
- `doc/source/conf.py` `version` and `release`
- `doc/source/changelog.rst`
- post to discord
- post to reddit.com/r/Bitburner
- post to reddit.com/r/Bitburner
Deploying `dev` to the Beta Branch
----------------------------------
TODO
Development Workflow Best Practices
-----------------------------------
- Work in a new branch forked from the `dev` branch to isolate your new code
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`

24
css/casino.scss Normal file
View File

@@ -0,0 +1,24 @@
.casino-card {
padding: 10px;
border: solid 1px #808080;
background-color: white;
display: inline-block;
border-radius: 10px;
font-size: 14pt;
text-align: center;
margin: 3px;
font-weight: bold;
}
.casino-card .value {
font-size:15pt;
font-family: sans-serif;
}
.casino-card.red {
color: red;
}
.casino-card.black {
color: black;
}

View File

@@ -43,9 +43,9 @@
background-color: #444;
}
.character-stat-cell {
text-align: right;
}
.character-stat-cell {
text-align: right;
}
#character-hack-wrapper td,
#character-agi-wrapper td {

View File

@@ -6,7 +6,7 @@
#codemirror-form-wrapper {
height: 80%;
margin: 10px 0px 0px 6px;
margin: 10px 0 0 6px;
}
.CodeMirror {
@@ -22,11 +22,11 @@
* Highlight matches
*/
.cm-matchhighlight {
background-color: #8F908A;
background-color: #8f908a;
}
.CodeMirror-selection-highlight-scrollbar {
background-color: #8F908A;
background-color: #8f908a;
}
/**
@@ -35,7 +35,7 @@
.cm-whitespace::before {
position: absolute;
pointer-events: none;
color: #404F7D;
color: #404f7d;
}
/**

View File

@@ -1,36 +1,36 @@
.add-exp-button {
margin-right: 0px;
margin-right: 0;
}
.remove-exp-button {
margin-left:0px;
margin-left:0;
}
.exp-input {
margin-right: 0px;
margin-left:0px;
margin-right: 0;
margin-left:0;
margin-top: 5px;
margin-bottom: 5px;
margin-top: 5px;
margin-bottom: 5px;
padding: 2px 5px;
padding: 2px 5px;
}
.text-center {
margin: auto;
text-align: center;
vertical-align: middle;
margin: auto;
text-align: center;
vertical-align: middle;
}
.touch-right {
margin-right: 0px;
margin-right: 0;
}
.touch-left {
margin-left: 0px;
margin-left: 0;
}
.touch-sides {
margin-left: 0px;
margin-right: 0px;
}
margin-left: 0;
margin-right: 0;
}

2
css/grid.min.css vendored

File diff suppressed because one or more lines are too long

5
css/milestones.scss Normal file
View File

@@ -0,0 +1,5 @@
#milestones-container {
position: fixed;
padding: 6px;
width: 60%;
}

View File

@@ -17,7 +17,7 @@
}
&.level-2 {
color: #48D1CC;
color: #48d1cc;
}
&.level-3 {

View File

@@ -1,4 +1,4 @@
/**
/**
* Styling for the Re-Sleeving Page
*/
@import "theme";
@@ -15,7 +15,7 @@
.resleeve-panel {
display: inline-block;
margin: 0px;
margin: 0;
padding: 2px;
}

View File

@@ -20,7 +20,7 @@
.sleeve-panel {
display: inline-block;
margin: 0px;
margin: 0;
padding: 2px;
select {

View File

@@ -228,14 +228,15 @@ a:visited {
}
.status-text {
display: inline-block;
position: fixed;
z-index: 2;
-webkit-animation: status-text 3s 1;
}
#status-text-container {
background-color: transparent;
position:absolute;
top:0;
left:50%;
}
#status-text {
@@ -374,7 +375,7 @@ a:visited {
}
.noscrollbar::-webkit-scrollbar {
display: none;
display: none;
}
input[type=checkbox] {
@@ -382,42 +383,42 @@ input[type=checkbox] {
}
.optionCheckbox {
margin: 5px;
float: right;
margin: 5px;
float: right;
}
.optionRange {
-webkit-appearance: none;
background: #777;
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: .2s;
transition: opacity .2s;
margin: 3px;
-webkit-appearance: none;
background: #777;
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: 0.2s;
transition: opacity 0.2s;
margin: 3px;
}
.optionRange::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
}
.optionRange::-moz-range-thumb {
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
}
.noselect {
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}

View File

@@ -35,7 +35,7 @@
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
@@ -126,4 +126,4 @@
visibility: visible;
opacity: 1;
transition: opacity 0.3s;
}
}

View File

@@ -7,16 +7,16 @@
.Treant.Treant-loaded .pseudo { visibility: visible; }
.Treant > .pseudo { width: 0; height: 0; border: none; padding: 0; }
.Treant .collapse-switch { width: 3px; height: 3px; display: block; border: 1px solid black; position: absolute; top: 1px; right: 1px; cursor: pointer; }
.Treant .collapsed .collapse-switch { background-color: #868DEE; }
.Treant .collapsed .collapse-switch { background-color: #868dee; }
.Treant > .node img { border: none; float: left; }
.Treant > .node {
cursor: pointer;
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #E8E8E3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0,0,0,.5);
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #e8e8e3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0,0,0,0.5);
font-size: 12px;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([398,0]),o()}({341:function(n,t,o){},343:function(n,t,o){},345:function(n,t,o){},347:function(n,t,o){},349:function(n,t,o){},351:function(n,t,o){},353:function(n,t,o){},355:function(n,t,o){},357:function(n,t,o){},359:function(n,t,o){},361:function(n,t,o){},363:function(n,t,o){},365:function(n,t,o){},367:function(n,t,o){},369:function(n,t,o){},371:function(n,t,o){},373:function(n,t,o){},375:function(n,t,o){},377:function(n,t,o){},379:function(n,t,o){},381:function(n,t,o){},383:function(n,t,o){},385:function(n,t,o){},387:function(n,t,o){},389:function(n,t,o){},391:function(n,t,o){},393:function(n,t,o){},395:function(n,t,o){},398:function(n,t,o){"use strict";o.r(t);o(397),o(395),o(393),o(391),o(389),o(387),o(385),o(383),o(381),o(379),o(377),o(375),o(373),o(371),o(369),o(367),o(365),o(363),o(361),o(359),o(357),o(355),o(353),o(351),o(349),o(347),o(345),o(343),o(341)}});
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([841,0]),o()}({780:function(n,t,o){},782:function(n,t,o){},784:function(n,t,o){},786:function(n,t,o){},788:function(n,t,o){},790:function(n,t,o){},792:function(n,t,o){},794:function(n,t,o){},796:function(n,t,o){},798:function(n,t,o){},800:function(n,t,o){},802:function(n,t,o){},804:function(n,t,o){},806:function(n,t,o){},808:function(n,t,o){},810:function(n,t,o){},812:function(n,t,o){},814:function(n,t,o){},816:function(n,t,o){},818:function(n,t,o){},820:function(n,t,o){},822:function(n,t,o){},824:function(n,t,o){},826:function(n,t,o){},828:function(n,t,o){},830:function(n,t,o){},832:function(n,t,o){},834:function(n,t,o){},836:function(n,t,o){},838:function(n,t,o){},841:function(n,t,o){"use strict";o.r(t);o(840),o(838),o(836),o(834),o(832),o(830),o(828),o(826),o(824),o(822),o(820),o(818),o(816),o(814),o(812),o(810),o(808),o(806),o(804),o(802),o(800),o(798),o(796),o(794),o(792),o(790),o(788),o(786),o(784),o(782),o(780)}});
//# sourceMappingURL=engineStyle.bundle.js.map

271
dist/engineStyle.css vendored
View File

@@ -250,13 +250,14 @@ a:visited {
opacity: 0; } }
.status-text {
display: inline-block;
position: fixed;
z-index: 2;
-webkit-animation: status-text 3s 1; }
#status-text-container {
background-color: transparent; }
background-color: transparent;
position: absolute;
top: 0;
left: 50%; }
#status-text {
background-color: transparent;
@@ -384,8 +385,8 @@ input[type=checkbox] {
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: .2s;
transition: opacity .2s;
-webkit-transition: 0.2s;
transition: opacity 0.2s;
margin: 3px; }
.optionRange::-webkit-slider-thumb {
@@ -1026,7 +1027,7 @@ button {
*/
#codemirror-form-wrapper {
height: 80%;
margin: 10px 0px 0px 6px; }
margin: 10px 0 0 6px; }
.CodeMirror {
height: 100%;
@@ -1040,10 +1041,10 @@ button {
* Highlight matches
*/
.cm-matchhighlight {
background-color: #8F908A; }
background-color: #8f908a; }
.CodeMirror-selection-highlight-scrollbar {
background-color: #8F908A; }
background-color: #8f908a; }
/**
* Show Invisibles
@@ -1051,7 +1052,7 @@ button {
.cm-whitespace::before {
position: absolute;
pointer-events: none;
color: #404F7D; }
color: #404f7d; }
/**
* Vim command display
@@ -1414,7 +1415,7 @@ button {
color: yellow; }
.bitnode.level-2 {
color: #48D1CC; }
color: #48d1cc; }
.bitnode.level-3 {
color: blue; }
@@ -2416,7 +2417,7 @@ button {
.sleeve-panel {
display: inline-block;
margin: 0px;
margin: 0;
padding: 2px; }
.sleeve-panel select {
display: block; }
@@ -2435,7 +2436,7 @@ button {
.resleeve-panel {
display: inline-block;
margin: 0px;
margin: 0;
padding: 2px; }
.resleeve-aug-selector {
@@ -2477,7 +2478,7 @@ button {
cursor: pointer; }
.Treant .collapsed .collapse-switch {
background-color: #868DEE; }
background-color: #868dee; }
.Treant > .node img {
border: none;
@@ -2488,7 +2489,7 @@ button {
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #E8E8E3;
border: 2px solid #e8e8e3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
font-size: 12px; }
@@ -4265,34 +4266,34 @@ html {
margin-left: 0 !important; }
.m-1 {
margin: .25rem !important; }
margin: 0.25rem !important; }
.mt-1, .my-1 {
margin-top: .25rem !important; }
margin-top: 0.25rem !important; }
.mr-1, .mx-1 {
margin-right: .25rem !important; }
margin-right: 0.25rem !important; }
.mb-1, .my-1 {
margin-bottom: .25rem !important; }
margin-bottom: 0.25rem !important; }
.ml-1, .mx-1 {
margin-left: .25rem !important; }
margin-left: 0.25rem !important; }
.m-2 {
margin: .5rem !important; }
margin: 0.5rem !important; }
.mt-2, .my-2 {
margin-top: .5rem !important; }
margin-top: 0.5rem !important; }
.mr-2, .mx-2 {
margin-right: .5rem !important; }
margin-right: 0.5rem !important; }
.mb-2, .my-2 {
margin-bottom: .5rem !important; }
margin-bottom: 0.5rem !important; }
.ml-2, .mx-2 {
margin-left: .5rem !important; }
margin-left: 0.5rem !important; }
.m-3 {
margin: 1rem !important; }
@@ -4355,34 +4356,34 @@ html {
padding-left: 0 !important; }
.p-1 {
padding: .25rem !important; }
padding: 0.25rem !important; }
.pt-1, .py-1 {
padding-top: .25rem !important; }
padding-top: 0.25rem !important; }
.pr-1, .px-1 {
padding-right: .25rem !important; }
padding-right: 0.25rem !important; }
.pb-1, .py-1 {
padding-bottom: .25rem !important; }
padding-bottom: 0.25rem !important; }
.pl-1, .px-1 {
padding-left: .25rem !important; }
padding-left: 0.25rem !important; }
.p-2 {
padding: .5rem !important; }
padding: 0.5rem !important; }
.pt-2, .py-2 {
padding-top: .5rem !important; }
padding-top: 0.5rem !important; }
.pr-2, .px-2 {
padding-right: .5rem !important; }
padding-right: 0.5rem !important; }
.pb-2, .py-2 {
padding-bottom: .5rem !important; }
padding-bottom: 0.5rem !important; }
.pl-2, .px-2 {
padding-left: .5rem !important; }
padding-left: 0.5rem !important; }
.p-3 {
padding: 1rem !important; }
@@ -4456,25 +4457,25 @@ html {
.ml-sm-0, .mx-sm-0 {
margin-left: 0 !important; }
.m-sm-1 {
margin: .25rem !important; }
margin: 0.25rem !important; }
.mt-sm-1, .my-sm-1 {
margin-top: .25rem !important; }
margin-top: 0.25rem !important; }
.mr-sm-1, .mx-sm-1 {
margin-right: .25rem !important; }
margin-right: 0.25rem !important; }
.mb-sm-1, .my-sm-1 {
margin-bottom: .25rem !important; }
margin-bottom: 0.25rem !important; }
.ml-sm-1, .mx-sm-1 {
margin-left: .25rem !important; }
margin-left: 0.25rem !important; }
.m-sm-2 {
margin: .5rem !important; }
margin: 0.5rem !important; }
.mt-sm-2, .my-sm-2 {
margin-top: .5rem !important; }
margin-top: 0.5rem !important; }
.mr-sm-2, .mx-sm-2 {
margin-right: .5rem !important; }
margin-right: 0.5rem !important; }
.mb-sm-2, .my-sm-2 {
margin-bottom: .5rem !important; }
margin-bottom: 0.5rem !important; }
.ml-sm-2, .mx-sm-2 {
margin-left: .5rem !important; }
margin-left: 0.5rem !important; }
.m-sm-3 {
margin: 1rem !important; }
.mt-sm-3, .my-sm-3 {
@@ -4516,25 +4517,25 @@ html {
.pl-sm-0, .px-sm-0 {
padding-left: 0 !important; }
.p-sm-1 {
padding: .25rem !important; }
padding: 0.25rem !important; }
.pt-sm-1, .py-sm-1 {
padding-top: .25rem !important; }
padding-top: 0.25rem !important; }
.pr-sm-1, .px-sm-1 {
padding-right: .25rem !important; }
padding-right: 0.25rem !important; }
.pb-sm-1, .py-sm-1 {
padding-bottom: .25rem !important; }
padding-bottom: 0.25rem !important; }
.pl-sm-1, .px-sm-1 {
padding-left: .25rem !important; }
padding-left: 0.25rem !important; }
.p-sm-2 {
padding: .5rem !important; }
padding: 0.5rem !important; }
.pt-sm-2, .py-sm-2 {
padding-top: .5rem !important; }
padding-top: 0.5rem !important; }
.pr-sm-2, .px-sm-2 {
padding-right: .5rem !important; }
padding-right: 0.5rem !important; }
.pb-sm-2, .py-sm-2 {
padding-bottom: .5rem !important; }
padding-bottom: 0.5rem !important; }
.pl-sm-2, .px-sm-2 {
padding-left: .5rem !important; }
padding-left: 0.5rem !important; }
.p-sm-3 {
padding: 1rem !important; }
.pt-sm-3, .py-sm-3 {
@@ -4588,25 +4589,25 @@ html {
.ml-md-0, .mx-md-0 {
margin-left: 0 !important; }
.m-md-1 {
margin: .25rem !important; }
margin: 0.25rem !important; }
.mt-md-1, .my-md-1 {
margin-top: .25rem !important; }
margin-top: 0.25rem !important; }
.mr-md-1, .mx-md-1 {
margin-right: .25rem !important; }
margin-right: 0.25rem !important; }
.mb-md-1, .my-md-1 {
margin-bottom: .25rem !important; }
margin-bottom: 0.25rem !important; }
.ml-md-1, .mx-md-1 {
margin-left: .25rem !important; }
margin-left: 0.25rem !important; }
.m-md-2 {
margin: .5rem !important; }
margin: 0.5rem !important; }
.mt-md-2, .my-md-2 {
margin-top: .5rem !important; }
margin-top: 0.5rem !important; }
.mr-md-2, .mx-md-2 {
margin-right: .5rem !important; }
margin-right: 0.5rem !important; }
.mb-md-2, .my-md-2 {
margin-bottom: .5rem !important; }
margin-bottom: 0.5rem !important; }
.ml-md-2, .mx-md-2 {
margin-left: .5rem !important; }
margin-left: 0.5rem !important; }
.m-md-3 {
margin: 1rem !important; }
.mt-md-3, .my-md-3 {
@@ -4648,25 +4649,25 @@ html {
.pl-md-0, .px-md-0 {
padding-left: 0 !important; }
.p-md-1 {
padding: .25rem !important; }
padding: 0.25rem !important; }
.pt-md-1, .py-md-1 {
padding-top: .25rem !important; }
padding-top: 0.25rem !important; }
.pr-md-1, .px-md-1 {
padding-right: .25rem !important; }
padding-right: 0.25rem !important; }
.pb-md-1, .py-md-1 {
padding-bottom: .25rem !important; }
padding-bottom: 0.25rem !important; }
.pl-md-1, .px-md-1 {
padding-left: .25rem !important; }
padding-left: 0.25rem !important; }
.p-md-2 {
padding: .5rem !important; }
padding: 0.5rem !important; }
.pt-md-2, .py-md-2 {
padding-top: .5rem !important; }
padding-top: 0.5rem !important; }
.pr-md-2, .px-md-2 {
padding-right: .5rem !important; }
padding-right: 0.5rem !important; }
.pb-md-2, .py-md-2 {
padding-bottom: .5rem !important; }
padding-bottom: 0.5rem !important; }
.pl-md-2, .px-md-2 {
padding-left: .5rem !important; }
padding-left: 0.5rem !important; }
.p-md-3 {
padding: 1rem !important; }
.pt-md-3, .py-md-3 {
@@ -4720,25 +4721,25 @@ html {
.ml-lg-0, .mx-lg-0 {
margin-left: 0 !important; }
.m-lg-1 {
margin: .25rem !important; }
margin: 0.25rem !important; }
.mt-lg-1, .my-lg-1 {
margin-top: .25rem !important; }
margin-top: 0.25rem !important; }
.mr-lg-1, .mx-lg-1 {
margin-right: .25rem !important; }
margin-right: 0.25rem !important; }
.mb-lg-1, .my-lg-1 {
margin-bottom: .25rem !important; }
margin-bottom: 0.25rem !important; }
.ml-lg-1, .mx-lg-1 {
margin-left: .25rem !important; }
margin-left: 0.25rem !important; }
.m-lg-2 {
margin: .5rem !important; }
margin: 0.5rem !important; }
.mt-lg-2, .my-lg-2 {
margin-top: .5rem !important; }
margin-top: 0.5rem !important; }
.mr-lg-2, .mx-lg-2 {
margin-right: .5rem !important; }
margin-right: 0.5rem !important; }
.mb-lg-2, .my-lg-2 {
margin-bottom: .5rem !important; }
margin-bottom: 0.5rem !important; }
.ml-lg-2, .mx-lg-2 {
margin-left: .5rem !important; }
margin-left: 0.5rem !important; }
.m-lg-3 {
margin: 1rem !important; }
.mt-lg-3, .my-lg-3 {
@@ -4780,25 +4781,25 @@ html {
.pl-lg-0, .px-lg-0 {
padding-left: 0 !important; }
.p-lg-1 {
padding: .25rem !important; }
padding: 0.25rem !important; }
.pt-lg-1, .py-lg-1 {
padding-top: .25rem !important; }
padding-top: 0.25rem !important; }
.pr-lg-1, .px-lg-1 {
padding-right: .25rem !important; }
padding-right: 0.25rem !important; }
.pb-lg-1, .py-lg-1 {
padding-bottom: .25rem !important; }
padding-bottom: 0.25rem !important; }
.pl-lg-1, .px-lg-1 {
padding-left: .25rem !important; }
padding-left: 0.25rem !important; }
.p-lg-2 {
padding: .5rem !important; }
padding: 0.5rem !important; }
.pt-lg-2, .py-lg-2 {
padding-top: .5rem !important; }
padding-top: 0.5rem !important; }
.pr-lg-2, .px-lg-2 {
padding-right: .5rem !important; }
padding-right: 0.5rem !important; }
.pb-lg-2, .py-lg-2 {
padding-bottom: .5rem !important; }
padding-bottom: 0.5rem !important; }
.pl-lg-2, .px-lg-2 {
padding-left: .5rem !important; }
padding-left: 0.5rem !important; }
.p-lg-3 {
padding: 1rem !important; }
.pt-lg-3, .py-lg-3 {
@@ -4852,25 +4853,25 @@ html {
.ml-xl-0, .mx-xl-0 {
margin-left: 0 !important; }
.m-xl-1 {
margin: .25rem !important; }
margin: 0.25rem !important; }
.mt-xl-1, .my-xl-1 {
margin-top: .25rem !important; }
margin-top: 0.25rem !important; }
.mr-xl-1, .mx-xl-1 {
margin-right: .25rem !important; }
margin-right: 0.25rem !important; }
.mb-xl-1, .my-xl-1 {
margin-bottom: .25rem !important; }
margin-bottom: 0.25rem !important; }
.ml-xl-1, .mx-xl-1 {
margin-left: .25rem !important; }
margin-left: 0.25rem !important; }
.m-xl-2 {
margin: .5rem !important; }
margin: 0.5rem !important; }
.mt-xl-2, .my-xl-2 {
margin-top: .5rem !important; }
margin-top: 0.5rem !important; }
.mr-xl-2, .mx-xl-2 {
margin-right: .5rem !important; }
margin-right: 0.5rem !important; }
.mb-xl-2, .my-xl-2 {
margin-bottom: .5rem !important; }
margin-bottom: 0.5rem !important; }
.ml-xl-2, .mx-xl-2 {
margin-left: .5rem !important; }
margin-left: 0.5rem !important; }
.m-xl-3 {
margin: 1rem !important; }
.mt-xl-3, .my-xl-3 {
@@ -4912,25 +4913,25 @@ html {
.pl-xl-0, .px-xl-0 {
padding-left: 0 !important; }
.p-xl-1 {
padding: .25rem !important; }
padding: 0.25rem !important; }
.pt-xl-1, .py-xl-1 {
padding-top: .25rem !important; }
padding-top: 0.25rem !important; }
.pr-xl-1, .px-xl-1 {
padding-right: .25rem !important; }
padding-right: 0.25rem !important; }
.pb-xl-1, .py-xl-1 {
padding-bottom: .25rem !important; }
padding-bottom: 0.25rem !important; }
.pl-xl-1, .px-xl-1 {
padding-left: .25rem !important; }
padding-left: 0.25rem !important; }
.p-xl-2 {
padding: .5rem !important; }
padding: 0.5rem !important; }
.pt-xl-2, .py-xl-2 {
padding-top: .5rem !important; }
padding-top: 0.5rem !important; }
.pr-xl-2, .px-xl-2 {
padding-right: .5rem !important; }
padding-right: 0.5rem !important; }
.pb-xl-2, .py-xl-2 {
padding-bottom: .5rem !important; }
padding-bottom: 0.5rem !important; }
.pl-xl-2, .px-xl-2 {
padding-left: .5rem !important; }
padding-left: 0.5rem !important; }
.p-xl-3 {
padding: 1rem !important; }
.pt-xl-3, .py-xl-3 {
@@ -4979,14 +4980,14 @@ html {
visibility: hidden !important; }
.add-exp-button {
margin-right: 0px; }
margin-right: 0; }
.remove-exp-button {
margin-left: 0px; }
margin-left: 0; }
.exp-input {
margin-right: 0px;
margin-left: 0px;
margin-right: 0;
margin-left: 0;
margin-top: 5px;
margin-bottom: 5px;
padding: 2px 5px; }
@@ -4997,14 +4998,40 @@ html {
vertical-align: middle; }
.touch-right {
margin-right: 0px; }
margin-right: 0; }
.touch-left {
margin-left: 0px; }
margin-left: 0; }
.touch-sides {
margin-left: 0px;
margin-right: 0px; }
margin-left: 0;
margin-right: 0; }
.casino-card {
padding: 10px;
border: solid 1px #808080;
background-color: white;
display: inline-block;
border-radius: 10px;
font-size: 14pt;
text-align: center;
margin: 3px;
font-weight: bold; }
.casino-card .value {
font-size: 15pt;
font-family: sans-serif; }
.casino-card.red {
color: red; }
.casino-card.black {
color: black; }
#milestones-container {
position: fixed;
padding: 6px;
width: 60%; }
/*# sourceMappingURL=engineStyle.css.map*/

78
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -56,8 +56,3 @@ through destroying BitNodes is:
* Source-Files
* Scripts on the home computer
BitNode Details
^^^^^^^^^^^^^^^
TODO

View File

@@ -47,7 +47,7 @@ List of all Source-Files
+------------------------------------+-------------------------------------------------------------------------------------+
| BitNode-9: Coming Soon | |
+------------------------------------+-------------------------------------------------------------------------------------+
| BitNode-10: Digital Carbon | * Each level of this grants a Duplicate Sleeve |
| BitNode-10: Digital Carbon | * Each level of this grants a Duplicate Sleeve. |
| | * Allows the player to access the :ref:`netscript_sleeveapi` in other BitNodes |
+------------------------------------+-------------------------------------------------------------------------------------+
| BitNode-11: The Big Crash | * Company favor increases both the player's salary and reputation gain at that |

View File

@@ -11,7 +11,7 @@ user's physical and mental faculties.
Augmentations provide persistent upgrades in the form of multipliers.
These multipliers apply to a wide variety of things such as stats,
experience gain, and hacking, just to name a few. Your multipliers
can be viewed in the 'Character' page (:ref:`keyboard shortcut <shortcuts>` Alt + c)
can be viewed in the 'Character' page (:ref:`keyboard shortcut <shortcuts>` Alt + c).
How to acquire Augmentations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -35,7 +35,7 @@ List of Factions and their Requirements
| Early Game | Faction Name | Requirements | Joining this Faction prevents |
| Factions | | | you from joining: |
+ +----------------+-----------------------------------------+-------------------------------+
| | CyberSec | * Hack CSEC Manually | |
| | CyberSec | * Install a backdoor on the CSEC server | |
+ +----------------+-----------------------------------------+-------------------------------+
| | Tian Di Hui | * $1m | |
| | | * Hacking Level 50 | |
@@ -74,13 +74,16 @@ List of Factions and their Requirements
| | | | * New Tokyo |
| | | | * Ishima |
+---------------------+----------------+-----------------------------------------+-------------------------------+
| Hacking | NiteSec | * Hack avmnite-02h manually | |
| Groups | | * Home Computer RAM of at least 32GB | |
| Hacking | NiteSec | * Install a backdoor on the avmnite-02h | |
| Groups | | server | |
| | | * Home Computer RAM of at least 32GB | |
+ +----------------+-----------------------------------------+-------------------------------+
| | The Black Hand | * Hack I.I.I.I manually | |
| | The Black Hand | * Install a backdoor on the I.I.I.I | |
| | | server | |
| | | * Home Computer RAM of at least 64GB | |
+ +----------------+-----------------------------------------+-------------------------------+
| | Bitrunners | * Hack run4theh111z manually | |
| | Bitrunners | * Install a backdoor on the run4theh111z| |
| | | server | |
| | | * Home Computer RAM of at least 128GB | |
+---------------------+----------------+-----------------------------------------+-------------------------------+
| Megacorporations | ECorp | * Have 200k reputation with | |
@@ -112,7 +115,8 @@ List of Factions and their Requirements
+ +----------------+-----------------------------------------+-------------------------------+
| | Fulcrum Secret | * Have 250k reputation with | |
| | Technologies | the Corporation | |
| | | * Hack fulcrumassets manually | |
| | | * Install a backdoor on the | |
| | | fulcrumassets server | |
+---------------------+----------------+-----------------------------------------+-------------------------------+
| Criminal | Slum Snakes | * All Combat Stats of 30 | |
| Organizations | | * -9 Karma | |

View File

@@ -148,6 +148,14 @@ has root access, what ports are opened/closed, and also hacking-related informat
such as an estimated chance to successfully hack, an estimate of how much money is
available on the server, etc.
backdoor
^^^^^^^^
Installs a backdoor on the current server. Root access is required to do this.
Servers will give different bonuses when you install a backdoor.
This can pass faction tests or give bonsues such as discounts from companies.
buy
^^^

View File

@@ -3,6 +3,270 @@
Changelog
=========
v0.51.8 - 2021-05-07 It was there all along (hydroflame)
--------------------------------------------------------
**Servers**
* Update n00dles metadata
**Netscript**
* 'hashGainRate' use the correct 'usedRam' and 'maxRam'
* Fix 'setActionAutolevel' logging.
* Fix 'setActionLevel' not working at all.
* Add 'installBackdoor' singularity function.
**Hacknet**
* Fix Hacknet Servers total production always displaying 0
**Documentation**
* Updated guide to no longer recommend BN12.
* Fix documentation for maxNumNodes (@ModdedGamers)
* Fix typo in 'sourcefiles.rst'
* Fix typo in 'recommendedbitnodeorder.rst'
* Fix 'getServer' documentation missing 'server' argument.
* Fix missing ram cost in 'getData.rst'
* Fix basic formulas examples.
* Fix typo in BN11 description.
* Fix formatting issue in Bladeburner (@Pimgd)
**Misc.**
* Fix negative money being displayed in full.
* Fix Hacking Missions not working.
* Fix Corporation tree not rendering.
* Fix script being needlessly recompiled. This should save real ram (not game ram)
* w0r1d_d43m0n can be backdoored
* Coding Contracts title is click-to-copy (@Rodeth)
* Covenant memory upgrade works better.
* Fix Neuroflux not being correctly calculated when entering BN with SF12.
* Delete Active Script now delete all active scripts, not just home.
* Now you can 'cd' in directories that only contain '.txt' files.
* Fix 'analyze' always saying players had root access
* Passive faction rep no longer builds for special factions.
* Donation option no longer appears for special factions.
* Rephrased some milestones.
* donation textbox now accepts money in the format '1b' and the like (@Dawe)
* Fix being able to join hated factions simultaneously. (@Dawe)
* 'ls' now displays files in multiple column. (Helps players with many files)
* Bladeburner multiplers now appear under Character>Stats and
Character>Augmentation when they are relevant.
* Fix missing functions syntax highlight in codemirror.
* Fix infiltration number formatting.
* script income transfers to parent on death. This helps keep track of
income for scripts that spawn short lived scripts.
v0.51.7 - 2021-04-28 n00dles
----------------------------
**Tutorial servers**
* All the tutorial servers have been reverted to their original value
* The new server n00dles has been added as tutorial server.
**Terminal**
* 'tail' now accepts Pid.
* 'analyze' now handles Hacknet Servers correctly.
* 'ServerProfiler.exe' now handles Hacknet Servers correctly.
**SF12**
* Now makes you start with Neuroflux Governor equal to the level of the SF.
**Netscript**
* Deprecated 'getServerRam'.
* 'getServerMaxRam' added to replace 'getServerRam'
* 'getServerUsedRam' added to replace 'getServerRam'
* 'getBitnodeMultipliers' is available inside BN5
* Time logged by hack/grow/weaken now displays in human time.
* thread count logged by hack/grow/weaken now displays with commas every
thousands place.
**Donation**
* Always visible but locked until favor requirements are reached.
**Augmentations**
* City factions has been rebalanced to give a reason to visit them all.
**Sleeves**
* Fix sleeves not being able to work at Volhavens gym.
**Lint**
* This shouldn't change anything but was like 10h of work. So I'm logging it.
**Misc.**
* Plethora of typo fixed (@Pimgd)
* ps documentation fix (@Dawe)
* The dev menu now has a quick bitflume option.
* Fix SF -1 not being as powerful as intended.
* Fix cashroot starter kit not displaying correctly.
* Fix DOM element 'character-overview-text' being nested twice.
* Hacknet documentation example fix.
* Money amount under 1000 dont display 3 decimal anymore.
* Fix nextSourceFile flag miscalculation on the bitverse (for Bn12)
* Faction invite text says "Decide later"/"Join!" instead of "No"/"Yes"
v0.51.6 - 2021-04-28 Backdoor! (Community)
------------------------------------------
**Backdoor**
* a new terminal command, backdoor, has been added to help differentiate
between the terminal hack command and the netscript hack function. (@dewint)
**Servers**
* foodnstuff, sigma-cosmetics, and joesguns have been rebalanced to help new players.
**Milestones**
* A new tab under the Help menu has been added to guide players through the
game.
**Casino**
* Blackjack has been added (@BigD)
**Netscript**
* 'prompt' now converts input to JSON.
* 'getRunningScript' is a new netscript function that returns a bunch of
data related to a running script.
**Coding contracts**
* trivial puzzles should no longer appear.
**Infiltration**
* All numbers are formatted like the rest of the game.
**Misc.**
* Server security is capped at 100.
* Added option to quit a job.
* 'cd' no longer works on unexistent folders.
* cd with no arguments brings you back to top level folder (@Andreas)
* 'softReset' documentation udpated.
* Money tracker now accounts for going to the hospital manually.
* codemirror is now the default editor (for new save files)
* fix typo in dark web help text (@Rodeth)
* so many documentation and typos fixes (@Pimgd)
* A corruption visual effect has been added to location with servers that
have backdoor installed. (@dewint)
v0.51.5 - 2021-04-20 Flags! (hydroflame)
----------------------------------------
**Netscript**
* 'flags' is a new function that helps script handle flags.
This is subject to change if it doesn't meet the need of the players.
* 'ps' now returns the pid.
* 'tail' now works with pid as first argument.
* 'tail' hostname defaults to current server. (like the documentation says)
* 'isRunning' hostname defaults to current server.
* 'isRunning' now works with pid as first argument.
**Gang**
* Nerfed ascension mechanic once again :(
**Misc.**
* Souce-File typo fix
* Fix 'while you were away' screen.
* Bladeburner team size can no longer be set to negative amounts.
v0.51.4 - 2021-04-19 Manual hacking is fun (hydroflame)
-------------------------------------------------------
**Manual hacking**
* These bonus require an install or a soft reset to take effect.
* Manual hacking gyms and university gives you a 10% discount.
* Manual hacking a corporation server decreases the penalty for leaving work
early.
**BladeBurner**
* nerfed int exp gained.
**Documentation**
* purchaseServer specifies what happens on failure.
* Fixed typo in recommended bitnode page.
* Removed misleading ram requirements for hacking factions.
**Netscript**
* growthAnalyze handles Infinity correctly.
**Misc.**
* Faction Augmentation will list how much reputation is required even after
that goal has been reached.
* Removed dollar sign in travel agency confirmation dialog box.
* Fixed typo in alpha-omega.lit
* the 'Game saved!' text no longer blocks the save game/options button.
* The text editor now remembers the location of your cursor and restores it.
* skills are recalculated instantly.
* Fix typo in Operation Zero description.
v0.51.3 - 2021-04-16 Y'all broke it on the first day (hydroflame)
-----------------------------------------------------------------
**Passive faction reputation**
* Reworked, from 1 rep / 2 minute. Now is a complicated percentage of the
reputation you'd gain working for them. It's not op but it feels a bit
more useful.
**Netscript**
* print/tprint now take any number of arguments.
* print/tprint will now print object as json.
* print/tprint now handle passing in an undefined argument properly.
**Casino**
* Cannot bet negative money anymore.
* Roulette max bet is a bit higher.
* Coin Flip has a small cooldown.
* All buttons reject unstrusted mouse events.
**Documentation**
* Changed a message that said nsjs only works on Chrome.
**Bugfix**
* hacknet.maxNumNodes now works for both nodes and servers.
* Fixed a bug where the popup boxes would contain data from previous popup boxes.
* .js files will also have the 'export async function' boilerplate.
**Misc.**
* turned off web form autocomplete for the terminal text input.
* Fixed an issue on Windows+Firefox where pressing up on the terminal would
bring the cursor to the begining of the line. (Issue #836)
* Hacknet node names is easier to handle for screen readers.
* Money spent on classes is now tracked independently of work money.
* running coding contract from the terminal will display its name.
v0.51.2 - 2021-04-09 Vegas, Baby! (hydroflame)
----------------------------------------------

View File

@@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
# The short X.Y version.
version = '0.51'
# The full version, including alpha/beta/rc tags.
release = '0.51.2'
release = '0.51.8'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -634,7 +634,7 @@ This tells me that I can reach :code:`CSEC` by going through :code:`iron-gym`::
Make sure you notice the required hacking skill for the :code:`CSEC` server.
This is a random value between 51 and 60. Although you receive the message
from CSEC once you hit 50 hacking, you cannot actually pass their test
until your hacking is high enough to hack their server.
until your hacking is high enough to install a backdoor on their server.
After you are connected to the :code:`CSEC` server, you can hack it. Note that this
server requires one open port in order to gain root access. We can open the SSH port
@@ -642,10 +642,10 @@ using the :code:`BruteSSH.exe` program we created earlier. In |Terminal|::
$ run BruteSSH.exe
$ run NUKE.exe
$ hack
$ backdoor
Keep hacking the server until you are successful. After you successfully hack it, you should
receive a faction invitation from |CyberSec| shortly afterwards. Accept it. If you accidentally
After you successfully install the backdoor, you should receive a faction
invitation from |CyberSec| shortly afterwards. Accept it. If you accidentally
reject the invitation, that's okay. Just go to the :code:`Factions` tab
(|Keyboard shortcut| Alt + f) and you should see an option that lets you
accept the invitation.

View File

@@ -278,6 +278,7 @@ Description
hashes, which can be spent on a variety of different upgrades.
In this BitNode:
* Your stats are significantly decreased
* You cannnot purchase additional servers
* Hacking is significantly less profitable
@@ -292,7 +293,7 @@ Source-File
* Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode
(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT
when installing Augmentation
when installing Augmentations.)
Difficulty
Hard
@@ -312,6 +313,7 @@ Description
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
In this BitNode:
* Your stats are significantly decreased
* All methods of gaining money are half as profitable (except Stock Market)
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit
@@ -321,7 +323,7 @@ Source-File
:Max Level: 3
This Source-File unlocks Sleeve technology in other BitNodes.
Each level of this Source-File also grants you a Duplicate Sleeve
Each level of this Source-File also grants you a Duplicate Sleeve.
Difficulty
Hard
@@ -371,9 +373,10 @@ Description
Source-File
:Max Level: Infinity
Each level of Source-File 12 will increase all of your multipliers by 1%. This effect
is multiplicative with itself. In other words, level N of this Source-File will result
in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)
Each level of Source-File 12 will let you start with Neuroflux Governor
equal to the level of this Source-File.
This BitNode is meant to be done passively or when waiting for new content.
Difficulty
Initially very easy, but then it (obviously) becomes harder as you continue to do it.
@@ -394,27 +397,22 @@ For fast progression
1. Repeat **BitNode-1: Source Genesis** until you max out its Source-File. Its Source-File
is extremely powerful, as it raises all multipliers by a significant amount.
2. Repeat **BitNode-12: The Recursion** several times. This BitNode will be extremely easy the
first few times you tackle it, and its Source-File raises all multipliers. Furthermore,
its effect stacks multiplicatively with itself and other Source-Files/Augmentations,
which gets better as time goes on
3. Do **BitNode-5: Artificial Intelligence** once or twice. The intelligence stat it unlocks
2. Do **BitNode-5: Artificial Intelligence** once or twice. The intelligence stat it unlocks
will gradually build up as you continue to play the game, and will be helpful
in the future. The Source-File also provides hacking multipliers, which are
strong because hacking is typically one of the best ways of earning money.
4. (Optional) Consider doing **BitNode-4: The Singularity**. Its Source-File does not directly make you
3. (Optional) Consider doing **BitNode-4: The Singularity**. Its Source-File does not directly make you
more powerful in any way, but it does unlock :ref:`netscript_singularityfunctions` which
let you automate significantly more aspects of the game.
5. Do **BitNode-3: Corporatocracy** once to unlock the Corporation mechanic. This mechanic
4. Do **BitNode-3: Corporatocracy** once to unlock the Corporation mechanic. This mechanic
has high profit potential.
6. Do **BitNode-6: Bladeburners** once to unlock the Bladeburners mechanic. The Bladeburner
5. Do **BitNode-6: Bladeburners** once to unlock the Bladeburners mechanic. The Bladeburner
mechanic is useful for some of the future BitNodes (such as 9 and 10).
7. Do **BitNode-9: Hacktocracy** to unlock the Hacknet Server mechanic. You can
6. Do **BitNode-9: Hacktocracy** to unlock the Hacknet Server mechanic. You can
consider repeating it as well, as its Level 2 and 3 effects are pretty helpful as well.
.. todo:: To be continued as more BitNodes get added

View File

@@ -1,9 +1,10 @@
getServer() Netscript Function
==========================================
.. js:function:: getServer()
.. js:function:: getServer([hostname])
:RAM cost: 4 GB
:param string hostname: Hostname of the server, defaults to host server.
If you are not in BitNode-5, then you must have Source-File 5-1 in order to run this function.
@@ -27,7 +28,7 @@ getServer() Netscript Function
sshPortOpen
baseDifficulty
hackDifficulty
manuallyHacked
backdoorInstalled
minDifficulty
moneyAvailable
moneyMax

View File

@@ -0,0 +1,40 @@
flags() Netscript Function
============================
.. js:function:: flags(data)
:RAM cost: 0 GB
:param data array of pairs of strings: Flags definition.
:returns: Object containing all the flags that were parsed or default.
The flag definition is an array of pairs of values, the first value is the
name of the flag, the 2nd value is the default value for that flag.
The return object is a map containing flag names to the value. It also
contains the special field '_' which contains all arguments that were not flags.
Example:
.. code-block:: javascript
/* example.script
var data = flags([
['delay', 0], // a default number means this flag is a number
['server', 'foodnstuff'], // a default string means this flag is a string
['exclude', []], // a default array means this flag is a default array of string
['help', false], // a default boolean means this flag is a boolean
]);
tprint(data);
*/
[home ~/]> run example.script
{"_":[],"delay":0,"server":"foodnstuff"}
[home ~/]> run example.script --delay 3000
{"_":[],"server":"foodnstuff","delay":3000}
[home ~/]> run example.script --delay 3000 --server harakiri-sushi
{"_":[],"delay":3000,"server":"harakiri-sushi"}
[home ~/]> run example.script --delay 3000 --server harakiri-sushi hello world
{"_":["hello","world"],"delay":3000,"server":"harakiri-sushi"}
[home ~/]> run example.script --delay 3000 --server harakiri-sushi hello world --exclude a --exclude b
{"_":["hello","world"],"delay":3000,"server":"harakiri-sushi","exclude":["a","b"]}
[home ~/]> run example.script --help
{"_":[],"delay":0,"server":"foodnstuff","exclude":[],"help":true}

View File

@@ -0,0 +1,88 @@
getRunningScript() Netscript Function
=====================================
.. js:function:: getRunningScript()
:RAM cost: 0.3 GB
:returns: Script object or null if not found
The object has the following properties:
.. code-block:: javascript
{
// Script arguments
args
// Script filename
filename
// This script's logs. An array of log entries
logs
// Flag indicating whether the logs have been updated since
// the last time the UI was updated
logUpd
// Total amount of hacking experience earned from this script when offline
offlineExpGained
// Total amount of money made by this script when offline
offlineMoneyMade
// Number of seconds that the script has been running offline
offlineRunningTime
// Total amount of hacking experience earned from this script when online
onlineExpGained
// Total amount of money made by this script when online
onlineMoneyMade
// Number of seconds that this script has been running online
onlineRunningTime
// Process ID.
pid
// How much RAM this script uses for ONE thread
ramUsage
// IP of the server on which this script is running
server
// Number of threads that this script is running with
threads
}
Examples:
.. code-block:: javascript
getRunningScript(); // get the current script.
.. js:function:: getRunningScript(pid)
:RAM cost: 0.3 GB
:param number pid: PID of the script
:returns: Script object or null if not found
Examples:
.. code-block:: javascript
getRunningScript(42); // get the script with pid 42.
.. js:function:: getRunningScript(fn, hostname[, args])
:RAM cost: 0.3 GB
:param number fn: filename of the target script
:param number hostname: hostname of the server running the script
:param number args: arguments to the script.
:returns: Script object or null if not found
Examples:
.. code-block:: javascript
getRunningScript("example.script", "home", "foodnstuff"); // get the script called "example.script" on "home" with argument "foodnstuff"

View File

@@ -0,0 +1,15 @@
getServerMaxRam() Netscript Function
====================================
.. js:function:: getServerMaxRam(hostname)
:RAM cost: 0.05 GB
:param string hostname: Hostname of target server.
:returns: Total ram available on that server. In GB.
Example:
.. code-block:: javascript
maxRam = getServerMaxRam("helios"); // returns: 16
print("helios has "+maxRam + "GB");

View File

@@ -3,6 +3,8 @@ getServerRam() Netscript Function
.. js:function:: getServerRam(hostname)
.. warning:: This function is deprecated.
:RAM cost: 0.1 GB
:param string hostname: Hostname of target server.
:returns: An array of 2 number, first number is the total RAM, second the

View File

@@ -0,0 +1,15 @@
getServerUsedRam() Netscript Function
=====================================
.. js:function:: getServerUsedRam(hostname)
:RAM cost: 0.05 GB
:param string hostname: Hostname of target server.
:returns: Used ram on that server. In GB.
Example:
.. code-block:: javascript
usedRam = getServerUsedRam("harakiri-sushi"); // returns: 5.6
print("harakiri-sushi uses "+usedRam + "GB");

View File

@@ -1,11 +1,11 @@
isRunning() Netscript Function
==============================
.. js:function:: isRunning(filename, hostname, [args...])
.. js:function:: isRunning(filename[, hostname=current hostname[, args...]])
:RAM cost: 0.1 GB
:param string filename: Filename of script to check. case-sensitive.
:param string hostname: Hostname of target server.
:param string hostname: Hostname of target server. Defaults to current server
:param args...: Arguments to specify/identify which scripts to search for
:returns: ``true`` if that script with those args is running on that server.
@@ -38,3 +38,17 @@ isRunning() Netscript Function
.. code-block:: javascript
isRunning("foo.script", "joesguns", 1, 5, "test");
.. js:function:: isRunning(scriptPid)
:RAM cost: 0.1 GB
:param number scriptPid: PID of the script to check.
Same as the above version but with pid.
Example:
.. code-block:: javascript
isRunning(39);

View File

@@ -1,15 +1,16 @@
print() Netscript Function
===========================
.. js:function:: print(x)
.. js:function:: print(args...)
:RAM cost: 0 GB
:param x: Value to be printed.
:param args: Values to be printed.
Prints a value or a variable to the script's logs.
Prints any number of values to the script's logs.
Example:
.. code-block:: javascript
print("Hello world!"); // Prints "Hello world!" in the logs.
print("Hello world!"); // Prints "Hello world!" in the logs.
print({a:5}); // Prints '{"a":5}' in the logs.

View File

@@ -15,7 +15,8 @@ ps() Netscript Function
{
filename: Script name,
threads: Number of threads script is running with,
args: Script's arguments
args: Script's arguments,
pid: Script's pid
}
Example:
@@ -23,7 +24,8 @@ ps() Netscript Function
.. code-block:: javascript
processes = ps("home");
for (let i = 0; i < ps.length; ++i) {
tprint(ps[i].filename + ' ' + ps[i].threads);
tprint(ps[i].args);
for (let i = 0; i < processes.length; ++i) {
tprint(processes[i].filename + ' ' + processes[i].threads);
tprint(processes[i].args);
tprint(processes[i].pid);
}

View File

@@ -7,7 +7,7 @@ purchaseServer() Netscript Function
:param string hostname: Hostname of the purchased server.
:param number ram: Amount of RAM of the purchased server. Must be a power of
2. Maximum value of :doc:`getPurchasedServerMaxRam<getPurchasedServerMaxRam>`
:returns: The hostname of the newly purchased server.
:returns: The hostname of the newly purchased server. Empty string on failure.
Purchased a server with the specified hostname and amount of RAM.

View File

@@ -1,7 +1,7 @@
tail() Netscript Function
==================================
.. js:function:: tail([fn[, hostname=current hostname[, [...args]]])
.. js:function:: tail([fn[, hostname=current hostname[, ...args]])
:RAM cost: 0 GB
:param string fn: Optional. Filename of script to get logs from.
@@ -29,3 +29,33 @@ tail() Netscript Function
// Open logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"]
tail("foo.script", "foodnstuff", 1, "test");
.. js:function:: tail(scriptPid)
:RAM cost: 0 GB
:param number scriptPid: PID of the script to tail.
Opens a script's logs by pid
Example:
.. code-block:: javascript
// Open logs from process with id 42
tail(42);
// Open logs from process with id 42 on the foodnstuff server
tail(42, "foodnstuff");
.. js:function:: tail()
:RAM cost: 0 GB
Opens the current script logs.
Example:
.. code-block:: javascript
// Open the current script logs.
tail();

View File

@@ -1,15 +1,16 @@
tprint() Netscript Function
===========================
.. js:function:: tprint(x)
.. js:function:: tprint(args...)
:RAM cost: 0 GB
:param x: Value to be printed
:param args: Values to be printed
Prints a value or a variable to the Terminal.
Prints any number of values to the Terminal.
Example:
.. code-block:: javascript
tprint("Hello world!"); // Prints "Hello world!" to the terminal.
tprint("Hello world!"); // Prints "Hello world!" to the terminal.
tprint({a:5}); // Prints '{"a":5}' to the terminal.

View File

@@ -3,6 +3,7 @@ getData() Netscript Function
.. js:function:: getData(filename[, hostname=current hostname])
:RAM cost: 5 GB
:param string filename: Filename of the contract
:param string hostname: Hostname of the server containing the contract.
Optional. Defaults to current server if not provided

View File

@@ -20,4 +20,4 @@ growPercent() Netscript Function
.. code-block:: javascript
tprint(growPercent(getServer(), 50, getPlayer()))
tprint(formulas.basic.growPercent(getServer(), 50, getPlayer()))

View File

@@ -21,4 +21,4 @@ growTime() Netscript Function
server = getServer();
server.hackDifficulty = server.minDifficulty;
tprint(growTime(server, getPlayer()));
tprint(formulas.basic.growTime(server, getPlayer()));

View File

@@ -21,4 +21,4 @@ hackChance() Netscript Function
server = getServer();
server.hackDifficulty = server.minDifficulty;
tprint(hackChance(server, getPlayer()));
tprint(formulas.basic.hackChance(server, getPlayer()));

View File

@@ -21,4 +21,4 @@ hackExp() Netscript Function
server = getServer();
server.hackDifficulty = 99.9;
tprint(hackExp(server, getPlayer()));
tprint(formulas.basic.hackExp(server, getPlayer()));

View File

@@ -22,4 +22,4 @@ hackPercent() Netscript Function
server = getServer();
server.hackDifficulty = server.minDifficulty;
tprint(hackPercent(server, getPlayer()));
tprint(formulas.basic.hackPercent(server, getPlayer()));

View File

@@ -21,4 +21,4 @@ hackTime() Netscript Function
server = getServer();
server.hackDifficulty = server.minDifficulty;
tprint(hackTime(server, getPlayer()));
tprint(formulas.basic.hackTime(server, getPlayer()));

View File

@@ -21,4 +21,4 @@ weakenTime() Netscript Function
server = getServer();
server.hackDifficulty = server.minDifficulty;
tprint(weakenTime(server, getPlayer()));
tprint(formulas.basic.weakenTime(server, getPlayer()));

View File

@@ -1,11 +1,12 @@
hashGainRate() Netscript Function
==========================================
.. js:function:: hashGainRate(level, ram, core[, mult])
.. js:function:: hashGainRate(level, ramUsed, maxRam, core[, mult])
:RAM cost: 0 GB
:param number level: level of the server.
:param number ram: ram of the server.
:param number ramUsed: ram used on the server.
:param number maxRam: max ram of the server.
:param number core: cores of the server.
:returns: Money per second that a server with those stats would gain per second.
@@ -18,7 +19,7 @@ hashGainRate() Netscript Function
.. code-block:: javascript
server = hacknet.getNodeStats(1);
currentRate = formulas.hacknetNodes.hashGainRate(server.level, server.ram, server.cores);
levelRate = formulas.hacknetNodes.hashGainRate(server.level+1, server.ram, server.cores);
ramRate = formulas.hacknetNodes.hashGainRate(server.level, server.ram*2, server.cores);
coresRate = formulas.hacknetNodes.hashGainRate(server.level, server.ram, server.cores+1);
currentRate = formulas.hacknetNodes.hashGainRate(server.level, 0, server.ram, server.cores);
levelRate = formulas.hacknetNodes.hashGainRate(server.level+1, 0, server.ram, server.cores);
ramRate = formulas.hacknetNodes.hashGainRate(server.level, 0, server.ram*2, server.cores);
coresRate = formulas.hacknetNodes.hashGainRate(server.level, 0, server.ram, server.cores+1);

View File

@@ -4,4 +4,4 @@ maxNumNodes() Netscript Function
.. js:function:: maxNumNodes()
:RAM cost: 0 GB
:returns: Maximum number of Hacknet Nodes you can own.
:returns: Maximum number of Hacknet Nodes you can own, unless you have not unlocked HackNet servers. Then, it returns Infinity.

View File

@@ -5,13 +5,13 @@ Netscript Bladeburner API
Netscript provides the following API for interacting with the game's Bladeburner mechanic.
The Bladeburner API is **not** immediately available to the player and must be unlocked
later in the game
later in the game.
.. warning:: This page contains spoilers for the game
The Bladeburner API is unlocked in BitNode-7. If you are in BitNode-7, you will
automatically gain access to this API. Otherwise, you must have Source-File 7 in
order to use this API in other BitNodes
order to use this API in other BitNodes.
**Bladeburner API functions must be accessed through the 'bladeburner' namespace**
@@ -157,7 +157,7 @@ identifier by attaching the Bladeburner API functions to an object::
}
BladeburnerHandler.prototype.handle = function() {
//If we're doing something else manually (without Simlacrum),
//If we're doing something else manually (without Simulacrum),
//it overrides Bladeburner stuff
if (!this.hasSimulacrum() && this.ns.isBusy()) {
this.ns.print("Idling bc player is busy with some other action");

View File

@@ -54,7 +54,8 @@ This includes information such as function signatures, what they do, and their r
getServerMinSecurityLevel() <basicfunctions/getServerMinSecurityLevel>
getServerRequiredHackingLevel() <basicfunctions/getServerRequiredHackingLevel>
getServerNumPortsRequired() <basicfunctions/getServerNumPortsRequired>
getServerRam() <basicfunctions/getServerRam>
getServerMaxRam() <basicfunctions/getServerMaxRam>
getServerUsedRam() <basicfunctions/getServerUsedRam>
serverExists() <basicfunctions/serverExists>
fileExists() <basicfunctions/fileExists>
isRunning() <basicfunctions/isRunning>
@@ -75,6 +76,7 @@ This includes information such as function signatures, what they do, and their r
scriptKill() <basicfunctions/scriptKill>
getScriptName() <basicfunctions/getScriptName>
getScriptRam() <basicfunctions/getScriptRam>
getRunningScript() <basicfunctions/getRunningScript>
getHackTime() <basicfunctions/getHackTime>
getGrowTime() <basicfunctions/getGrowTime>
getWeakenTime() <basicfunctions/getWeakenTime>
@@ -88,3 +90,9 @@ This includes information such as function signatures, what they do, and their r
prompt() <basicfunctions/prompt>
wget() <basicfunctions/wget>
getFavorToDonate() <basicfunctions/getFavorToDonate>
flags() <basicfunctions/flags>
.. toctree::
:caption: Deprecated:
getServerRam() <basicfunctions/getServerRam>

View File

@@ -86,7 +86,7 @@ The following is an example of one way a script can be used to automate the
purchasing and upgrading of Hacknet Nodes.
This script attempts to purchase Hacknet Nodes until the player has a total of 8. Then
it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 cores
it gradually upgrades those Node's to a minimum of level 80, 16 GB RAM, and 8 cores
.. code:: javascript
@@ -129,3 +129,16 @@ it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 c
};
print("All nodes upgraded to 16GB RAM");
for (var i = 0; i < cnt; i++) {
while (hacknet.getNodeStats(i).cores < 8) {
var cost = hacknet.getCoreUpgradeCost(i, 1);
while (myMoney() < cost) {
print("Need $" + cost + " . Have $" + myMoney());
sleep(3000);
}
res = hacknet.upgradeCore(i, 1);
};
};
print("All nodes upgraded to 8 cores");

View File

@@ -65,6 +65,6 @@ Here is a short summary of the differences between Netscript 1.0 and Netscript 2
* Supports (almost) all features of modern JavaScript
* Extremely fast - code is executed as an Async Function
* Currently only works with Google Chrome browser
* Works on most modern browsers.
* Each script becomes a module and therefore all instances of that script can easily
share data between each other (essentially global/static variables)

View File

@@ -27,6 +27,7 @@ level 3, then you will be able to access all of the Singularity Functions.
getCurrentServer() <singularityfunctions/getCurrentServer>
connect() <singularityfunctions/connect>
manualHack() <singularityfunctions/manualHack>
installBackdoor() <singularityfunctions/installBackdoor>
getPlayer() <singularityfunctions/getPlayer>
hospitalize() <singularityfunctions/hospitalize>
isBusy() <singularityfunctions/isBusy>

View File

@@ -0,0 +1,22 @@
installBackdoor() Netscript Function
====================================
.. js:function:: installBackdoor()
:RAM cost: 2 GB
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
This function will install a backdoor on the server you are currently connected to.
Examples:
.. code-block:: javascript
connect("foodnstuff");
installBackdoor();
.. warning::
For NS2 users:
This function is async.

View File

@@ -9,13 +9,12 @@ manualHack() Netscript Function
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
This function will perform a manual hack on the server you are currently connected to.
This is typically required to join factions.
Examples:
.. code-block:: javascript
connect("CSEC");
connect("foodnstuff");
manualHack();
.. warning::

View File

@@ -1,9 +1,13 @@
softReset() Netscript Function
===================================
.. js:function:: softReset()
.. js:function:: softReset([callbackScript])
:RAM cost: 5 GB
:param string cbScript:
Optional callback script. This is a script that will automatically be
run after the soft reset. This script will be run with no arguments and
1 thread. It must be located on your home computer.
If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.

View File

@@ -100,9 +100,12 @@
<li id="help-menu-header-li">
<button id="help-menu-header" class="mainmenu-accordion-header"> Help </button>
</li>
<li id="tutorial-tab" class="mainmenu-accordion-panel">
<button id="tutorial-menu-link"> Tutorial </button>
</li>
<li id="milestones-tab" class="mainmenu-accordion-panel">
<button id="milestones-menu-link"> Milestones </button>
</li>
<li id="tutorial-tab" class="mainmenu-accordion-panel">
<button id="tutorial-menu-link"> Tutorial </button>
</li>
<li id="options-tab" class="mainmenu-accordion-panel">
<button id="options-menu-link"> Options </button>
</li>
@@ -177,7 +180,7 @@
<table id="terminal">
<tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off"/>
</td>
</tr>
</table>
@@ -226,6 +229,10 @@
<!-- Augmentations -->
<div id="augmentations-container" class="generic-menupage-container"></div>
<!-- Milestones content -->
<div id="milestones-container" class="generic-menupage-container">
</div>
<!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container">
<h1> Tutorial (AKA Links to Documentation) </h1>
@@ -320,8 +327,8 @@
Would you like to join? <br/> <br/>
Warning: Joining this faction may prevent you from joining other factions during this run!
</p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
<button id="faction-invitation-box-no" class="popup-box-button"> No </button>
<button id="faction-invitation-box-yes" class="popup-box-button"> Join! </button>
<button id="faction-invitation-box-no" class="popup-box-button"> Decide later </button>
</div>
</div>
@@ -381,7 +388,7 @@
<!-- Status text -->
<div id="status-text-container">
<p id="status-text"> </p>
<p id="status-text"></p>
</div>
<!-- Game Options -->
@@ -521,6 +528,16 @@
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
</fieldset>
<!-- Disable text effects such as corruption. -->
<fieldset>
<label for="settingsDisableTextEffects" class="tooltip">Disable Text Effects:
<span class="tooltiptexthigh">
If this is set, text effects will not be displayed. This can help if text is difficult to read in certain areas.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableTextEffects" id="settingsDisableTextEffects">
</fieldset>
<!-- Locale for displaying numbers -->
<fieldset>
<label for="settingsLocale" class="tooltip">Locale:
@@ -570,14 +587,14 @@
Copy Save data to Clipboard
</button>
<button id="debug-delete-scripts-link" class="a-link-button tooltip">
(DEBUG) Delete Active Scripts
Delete all active scripts
<span class="tooltiptextleft">
Debug option used to forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After
using this, save the game and then reload the page.
</span>
</button>
<button id="debug-soft-reset" class="a-link-button tooltip">
(DEBUG) Soft Reset
Soft Reset
<span class="tooltiptextleft">
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
</span>

13764
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
"url": "https://github.com/danielyxie/bitburner/issues"
},
"dependencies": {
"@material-ui/core": "^4.11.3",
"@types/numeral": "0.0.25",
"@types/react": "^16.8.6",
"@types/react-dom": "^16.8.2",
@@ -13,6 +14,7 @@
"acorn-walk": "^6.2.0",
"ajv": "^5.1.5",
"ajv-keywords": "^2.0.0",
"arg": "^5.0.0",
"async": "^2.6.1",
"autosize": "^4.0.2",
"brace": "^0.11.1",
@@ -46,7 +48,10 @@
"@babel/core": "^7.3.4",
"@babel/preset-react": "^7.0.0",
"@types/chai": "^4.1.7",
"@types/lodash": "^4.14.168",
"@types/mocha": "^5.2.7",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"babel-loader": "^8.0.5",
"beautify-lint": "^1.0.3",
"benchmark": "^2.1.1",
@@ -54,8 +59,8 @@
"chai": "^4.2.0",
"css-loader": "^0.28.11",
"es6-promise-polyfill": "^1.1.1",
"eslint": "^4.19.1",
"eslint-plugin-node": "^6.0.1",
"eslint": "^7.24.0",
"eslint-plugin-node": "^11.1.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"i18n-webpack-plugin": "^1.0.0",
@@ -85,8 +90,7 @@
"stylelint-declaration-use-variable": "^1.6.1",
"stylelint-order": "^0.8.1",
"ts-loader": "^4.5.0",
"tslint": "^5.10.0",
"typescript": "^2.9.2",
"typescript": "^4.2.4",
"uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^1.3.0",
"url-loader": "^1.0.1",
@@ -112,14 +116,13 @@
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"build:test": "webpack --config webpack.config-test.js",
"lint": "npm run lint:typescript & npm run lint:javascript & npm run lint:style",
"lint:javascript": "eslint *.js ./src/**/*.js ./tests/**/*.js ./utils/**/*.js",
"lint:style": "stylelint ./css/*",
"lint:typescript": "tslint --project . --exclude **/*.d.ts --format stylish src/**/*.ts utils/**/*.ts",
"lint": "npm run lint:jsts & npm run lint:style",
"lint:jsts": "eslint --fix '*.{js,jsx,ts,tsx}' './src/**/*.{js,jsx,ts,tsx}' './test/**/*.{js,jsx,ts,tsx}' './utils/**/*.{js,jsx,ts,tsx}'",
"lint:style": "stylelint --fix ./css/*",
"preinstall": "node ./scripts/engines-check.js",
"test": "mochapack --webpack-config webpack.config-test.js -r jsdom-global/register ./test/index.js",
"watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development"
},
"version": "0.51.1"
"version": "0.51.8"
}

View File

@@ -22,12 +22,12 @@ export function loadGlobalAliases(saveString: string): void {
// Prints all aliases to terminal
export function printAliases(): void {
for (var name in Aliases) {
for (const name in Aliases) {
if (Aliases.hasOwnProperty(name)) {
post("alias " + name + "=" + Aliases[name]);
}
}
for (var name in GlobalAliases) {
for (const name in GlobalAliases) {
if (GlobalAliases.hasOwnProperty(name)) {
post("global alias " + name + "=" + GlobalAliases[name]);
}
@@ -35,9 +35,9 @@ export function printAliases(): void {
}
// Returns true if successful, false otherwise
export function parseAliasDeclaration(dec: string, global: boolean=false) {
var re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
var matches = dec.match(re);
export function parseAliasDeclaration(dec: string, global = false): boolean {
const re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
const matches = dec.match(re);
if (matches == null || matches.length != 3) {return false;}
if (global){
addGlobalAlias(matches[1],matches[2]);
@@ -100,17 +100,17 @@ export function substituteAliases(origCommand: string): string {
// For the unalias command, dont substite
if (commandArray[0] === "unalias") { return commandArray.join(" "); }
var alias = getAlias(commandArray[0]);
const alias = getAlias(commandArray[0]);
if (alias != null) {
commandArray[0] = alias;
} else {
var alias = getGlobalAlias(commandArray[0]);
const alias = getGlobalAlias(commandArray[0]);
if (alias != null) {
commandArray[0] = alias;
}
}
for (var i = 0; i < commandArray.length; ++i) {
var alias = getGlobalAlias(commandArray[i]);
for (let i = 0; i < commandArray.length; ++i) {
const alias = getGlobalAlias(commandArray[i]);
if (alias != null) {
commandArray[i] = alias;
}

View File

@@ -9,7 +9,7 @@ import { Factions } from "../Faction/Factions";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
interface IConstructorParams {
info: string;
info: string | JSX.Element;
isSpecial?: boolean;
moneyCost: number;
name: string;
@@ -49,31 +49,27 @@ interface IConstructorParams {
}
export class Augmentation {
// Initiatizes a Augmentation object from a JSON save state.
static fromJSON(value: any): Augmentation {
return Generic_fromJSON(Augmentation, value.data);
}
// How much money this costs to buy
baseCost: number = 0;
baseCost = 0;
// How much faction reputation is required to unlock this
baseRepRequirement: number = 0;
baseRepRequirement = 0;
// Description of what this Aug is and what it does
info: string = "";
info: string | JSX.Element;
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
isSpecial: boolean = false;
isSpecial = false;
// Augmentation level - for repeatable Augs like NeuroFlux Governor
level: number = 0;
level = 0;
// Name of Augmentation
name: string = "";
name = "";
// Whether the player owns this Augmentation
owned: boolean = false;
owned = false;
// Array of names of all prerequisites
prereqs: string[] = [];
@@ -83,7 +79,7 @@ export class Augmentation {
mults: IMap<number> = {}
// Initial cost. Doesn't change when you purchase multiple Augmentation
startingCost: number = 0;
startingCost = 0;
constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) {
this.name = params.name;
@@ -141,7 +137,7 @@ export class Augmentation {
console.warn(`In Augmentation.addToFactions(), could not find faction with this name: ${factionList[i]}`);
continue;
}
faction!.augmentations.push(this.name);
faction.augmentations.push(this.name);
}
}
@@ -154,7 +150,7 @@ export class Augmentation {
console.warn(`Invalid Faction object in addToAllFactions(). Key value: ${fac}`);
continue;
}
facObj!.augmentations.push(this.name);
facObj.augmentations.push(this.name);
}
}
}
@@ -163,6 +159,12 @@ export class Augmentation {
toJSON(): any {
return Generic_toJSON("Augmentation", this);
}
// Initiatizes a Augmentation object from a JSON save state.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Augmentation {
return Generic_fromJSON(Augmentation, value.data);
}
}
Reviver.constructors.Augmentation = Augmentation;

View File

@@ -8,29 +8,14 @@ import { AugmentationsRoot } from "./ui/Root";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { Factions, factionExists } from "../Faction/Factions";
import { startWorkerScript } from "../NetscriptWorker";
import { Player } from "../Player";
import { prestigeAugmentation } from "../Prestige";
import { saveObject } from "../SaveObject";
import { RunningScript } from "../Script/RunningScript";
import { Script } from "../Script/Script";
import { Server } from "../Server/Server";
import { OwnedAugmentationsOrderSetting } from "../Settings/SettingEnums";
import { Settings } from "../Settings/Settings";
import { Page, routing } from "../ui/navigationTracking";
import { dialogBoxCreate } from "../../utils/DialogBox";
import { createAccordionElement } from "../../utils/uiHelpers/createAccordionElement";
import {
Reviver,
Generic_toJSON,
Generic_fromJSON
} from "../../utils/JSONReviver";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { clearObject } from "../../utils/helpers/clearObject";
import { createElement } from "../../utils/uiHelpers/createElement";
import { isString } from "../../utils/helpers/isString";
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
import { Money } from "../ui/React/Money";
import React from "react";
import ReactDOM from "react-dom";
@@ -75,7 +60,7 @@ function initAugmentations() {
"This augmentation increases the player's dexterity by 10%.",
dexterity_mult: 1.1,
});
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Ishima",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting1)) {
delete Augmentations[AugmentationNames.Targeting1];
@@ -90,7 +75,7 @@ function initAugmentations() {
prereqs:[AugmentationNames.Targeting1],
dexterity_mult: 1.2,
});
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting2)) {
delete Augmentations[AugmentationNames.Targeting2];
@@ -151,7 +136,7 @@ function initAugmentations() {
strength_mult: 1.1,
defense_mult: 1.1,
});
CombatRib1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
CombatRib1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Volhaven", "Ishima",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.CombatRib1)) {
delete Augmentations[AugmentationNames.CombatRib1];
@@ -167,7 +152,7 @@ function initAugmentations() {
strength_mult: 1.14,
defense_mult: 1.14,
});
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Volhaven",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.CombatRib2)) {
delete Augmentations[AugmentationNames.CombatRib2];
@@ -177,7 +162,7 @@ function initAugmentations() {
const CombatRib3 = new Augmentation({
name:AugmentationNames.CombatRib3, repCost:14e3, moneyCost:24e6,
info:"This is an upgrade to the Combat Rib II augmentation, and is capable of releasing even more potent combat-enhancing " +
"drugs into the bloodstream<br><br>." +
"drugs into the bloodstream.<br><br>" +
"This augmentation increases the player's strength and defense by 18%.",
prereqs:[AugmentationNames.CombatRib2],
strength_mult: 1.18,
@@ -403,7 +388,7 @@ function initAugmentations() {
info:"The body is injected with a chemical that artificially induces synaptic potentiation, " +
"otherwise known as the strengthening of synapses. This results in a enhanced cognitive abilities.<br><br>" +
"This augmentation:<br>" +
"Increases the player's hacking speed by 2% <br>" +
"Increases the player's hacking speed by 2%.<br>" +
"Increases the player's hacking chance by 5%.<br>" +
"Increases the player's hacking experience gain rate by 5%.",
hacking_speed_mult: 1.02,
@@ -443,7 +428,7 @@ function initAugmentations() {
"This augmentation increases the player's hacking speed by 3%.",
hacking_speed_mult: 1.03,
});
SynapticEnhancement.addToFactions(["CyberSec"]);
SynapticEnhancement.addToFactions(["CyberSec", "Aevum"]);
if (augmentationExists(AugmentationNames.SynapticEnhancement)) {
delete Augmentations[AugmentationNames.SynapticEnhancement];
}
@@ -771,7 +756,7 @@ function initAugmentations() {
"when working for a company by 20%.",
company_rep_mult: 1.2,
});
NuoptimalInjectorImplant.addToFactions(["Tian Di Hui", "Volhaven", "New Tokyo", "Chongqing", "Ishima",
NuoptimalInjectorImplant.addToFactions(["Tian Di Hui", "Volhaven", "New Tokyo", "Chongqing",
"Clarke Incorporated", "Four Sigma", "Bachman & Associates"]);
if (augmentationExists(AugmentationNames.NuoptimalInjectorImplant)) {
delete Augmentations[AugmentationNames.NuoptimalInjectorImplant];
@@ -880,9 +865,7 @@ function initAugmentations() {
info:"The body is genetically re-engineered so that it produces the ADR-V1 pheromone, " +
"an artificial pheromone discovered by scientists. The ADR-V1 pheromone, when excreted, " +
"triggers feelings of admiration and approval in other people.<br><br>" +
"This augmentation:<br>" +
"Increases the amount of reputation the player gains when working for a company by 10% <br>" +
"Increases the amount of reputation the player gains for a faction by 10%.",
"This augmentation increases the amount of reputation the player gains when working for a faction or company by 10%.",
company_rep_mult: 1.1,
faction_rep_mult: 1.1,
});
@@ -897,8 +880,7 @@ function initAugmentations() {
info:"The body is genetically re-engineered so that it produces the ADR-V2 pheromone, " +
"which is similar to but more potent than ADR-V1. This pheromone, when excreted, " +
"triggers feelings of admiration, approval, and respect in others.<br><br>" +
"This augmentation:<br>" +
"Increases the amount of reputation the player gains for a faction and company by 20%.",
"This augmentation increases the amount of reputation the player gains when working for a faction or company by 20%.",
company_rep_mult: 1.2,
faction_rep_mult: 1.2,
});
@@ -915,8 +897,7 @@ function initAugmentations() {
"criminal organizations and allows the user to project and control holographic " +
"simulacrums within a large radius. These simulacrums are commonly used for " +
"espionage and surveillance work.<br><br>" +
"This augmentation:<br>" +
"Increases the amount of reputation the player gains when working for a faction or company by 15%.",
"This augmentation increases the amount of reputation the player gains when working for a faction or company by 15%.",
company_rep_mult: 1.15,
faction_rep_mult: 1.15,
});
@@ -1083,7 +1064,7 @@ function initAugmentations() {
agility_exp_mult: 1.1,
charisma_exp_mult: 1.1,
});
Neurotrainer1.addToFactions(["CyberSec"]);
Neurotrainer1.addToFactions(["CyberSec", "Aevum"]);
if (augmentationExists(AugmentationNames.Neurotrainer1)) {
delete Augmentations[AugmentationNames.Neurotrainer1];
}
@@ -1152,7 +1133,7 @@ function initAugmentations() {
"cells, when powered, have a negative refractive index. As a result, they bend light " +
"around the skin, making the user much harder to see from the naked eye.<br><br>" +
"This augmentation:<br>" +
"Increases the player's agility by 5% <br>" +
"Increases the player's agility by 5%.<br>" +
"Increases the amount of money the player gains from crimes by 10%.",
agility_mult: 1.05,
crime_money_mult: 1.1,
@@ -1170,8 +1151,8 @@ function initAugmentations() {
"cells, when powered, are capable of not only bending light but also of bending heat, " +
"making the user more resilient as well as stealthy.<br><br>" +
"This augmentation:<br>" +
"Increases the player's agility by 10% <br>" +
"Increases the player's defense by 10% <br>" +
"Increases the player's agility by 10%.<br>" +
"Increases the player's defense by 10%.<br>" +
"Increases the amount of money the player gains from crimes by 25%.",
prereqs:[AugmentationNames.LuminCloaking1],
agility_mult: 1.1,
@@ -1259,7 +1240,7 @@ function initAugmentations() {
// Daedalus
const RedPill = new Augmentation({
name:AugmentationNames.TheRedPill, repCost:1e6, moneyCost:0,
info:"It's time to leave the cave."
info:"It's time to leave the cave.",
});
RedPill.addToFactions(["Daedalus"]);
if (augmentationExists(AugmentationNames.TheRedPill)) {
@@ -1335,7 +1316,7 @@ function initAugmentations() {
"capable of psychoanalyzing and profiling the personality of " +
"others using optical imaging software.<br><br>" +
"This augmentation:<br>" +
"Increases the player's charisma by 50%. <br>" +
"Increases the player's charisma by 50%.<br>" +
"Increases the player's charisma experience gain rate by 50%.<br>" +
"Increases the amount of reputation the player gains for a company by 25%.<br>" +
"Increases the amount of reputation the player gains for a faction by 25%.",
@@ -1372,7 +1353,7 @@ function initAugmentations() {
name:AugmentationNames.Xanipher, repCost:350e3, moneyCost:850e6,
info:"A concoction of advanced nanobots that is orally ingested into the " +
"body. These nanobots induce physiological change and significantly " +
"improve the body's functionining in all aspects.<br><br>" +
"improve the body's functioning in all aspects.<br><br>" +
"This augmentation:<br>" +
"Increases all of the player's stats by 20%.<br>" +
"Increases the player's experience gain rate for all stats by 15%.",
@@ -1395,6 +1376,23 @@ function initAugmentations() {
}
AddToAugmentations(Xanipher);
const HydroflameLeftArm = new Augmentation({
name:AugmentationNames.HydroflameLeftArm, repCost:500e3, moneyCost:500e9,
info:"The left arm of a legendary BitRunner who ascended beyond this world. " +
"It projects a light blue energy shield that protects the exposed inner parts. " +
"Even though it contains no weapons, the advance tungsten titanium " +
"alloy increases the users strength to unbelievable levels.<br><br>" +
"This augmentation increases the player's strength by 300%.",
strength_mult: 3,
});
HydroflameLeftArm.addToFactions(["NWO"]);
if (augmentationExists(AugmentationNames.HydroflameLeftArm)) {
delete Augmentations[AugmentationNames.HydroflameLeftArm];
}
AddToAugmentations(HydroflameLeftArm);
// ClarkeIncorporated
const nextSENS = new Augmentation({
name:AugmentationNames.nextSENS, repCost:175e3, moneyCost:385e6,
@@ -1537,12 +1535,12 @@ function initAugmentations() {
// Sector12
const CashRoot = new Augmentation({
name:AugmentationNames.CashRoot, repCost:5e3, moneyCost:25e6,
info:"A collection of digital assets saved on a small chip. The chip is implanted " +
"into your wrist. A small jack in the chip allows you to connect it to a computer " +
"and upload the assets.<br><br>" +
"This augmentation:<br>" +
"Lets the player start with $1,000,000 after a reset.<br>" +
"Lets the player start with the BruteSSH.exe program after a reset."
info:<>A collection of digital assets saved on a small chip. The chip is implanted
into your wrist. A small jack in the chip allows you to connect it to a computer
and upload the assets.<br /><br />
This augmentation:<br />
Lets the player start with {Money(1e6)} after a reset.<br />
Lets the player start with the BruteSSH.exe program after a reset.</>,
});
CashRoot.addToFactions(["Sector-12"]);
if (augmentationExists(AugmentationNames.CashRoot)) {
@@ -1557,8 +1555,7 @@ function initAugmentations() {
"synthesizes glucose, amino acids, and vitamins and redistributes them " +
"across the body. The device is powered by the body's naturally wasted " +
"energy in the form of heat.<br><br>" +
"This augmentation:<br>" +
"Increases the player's experience gain rate for all combat stats by 20%.",
"This augmentation increases the player's experience gain rate for all combat stats by 20%.",
strength_exp_mult: 1.2,
defense_exp_mult: 1.2,
dexterity_exp_mult: 1.2,
@@ -1730,7 +1727,7 @@ function initAugmentations() {
"to induce wakefulness and concentration, suppress fear, reduce empathy, and " +
"improve reflexes and memory-recall among other things.<br><br>" +
"This augmentation:<br>" +
"Increases the player's sucess chance in Bladeburner contracts/operations by 3%.<br>" +
"Increases the player's success chance in Bladeburner contracts/operations by 3%.<br>" +
"Increases the player's effectiveness in Bladeburner Field Analysis by 5%.<br>" +
"Increases the player's Bladeburner stamina gain rate by 2%.",
bladeburner_success_chance_mult: 1.03,
@@ -1768,8 +1765,7 @@ function initAugmentations() {
"nature of the plasma disrupts the electrical systems of Augmentations. However, " +
"it can also be effective against non-augmented enemies due to its high temperature " +
"and concussive force.<br><br>" +
"This augmentation:<br>" +
"Increases the player's success chance in Bladeburner contracts/operations by 6%.",
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 6%.",
bladeburner_success_chance_mult: 1.06,
isSpecial: true,
});
@@ -1782,8 +1778,7 @@ function initAugmentations() {
"is more advanced and powerful than the original V1 model. This V2 model is " +
"more power-efficiency, more accurate, and can fire plasma bolts at a much " +
"higher velocity than the V1 model.<br><br>" +
"This augmentation:<br>" +
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 8%.",
prereqs:[AugmentationNames.HyperionV1],
bladeburner_success_chance_mult: 1.08,
isSpecial: true,
@@ -1941,8 +1936,7 @@ function initAugmentations() {
info:"Upgrades the BLADE-51b Tesla Armor with a concentrated deuterium-fluoride laser " +
"weapon. It's precision an accuracy makes it useful for quickly neutralizing " +
"threats while keeping casualties to a minimum.<br><br>" +
"This augmentation:<br>" +
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 8%.",
prereqs:[AugmentationNames.BladeArmor],
bladeburner_success_chance_mult: 1.08,
isSpecial: true,
@@ -1956,8 +1950,7 @@ function initAugmentations() {
"multiple-fiber system. The upgraded weapon uses multiple fiber laser " +
"modules that combine together to form a single, more powerful beam of up to " +
"2000MW.<br><br>" +
"This augmentation:<br>" +
"Increases the player's success chance in Bladeburner contracts/operations by 10%.",
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 10%.",
prereqs:[AugmentationNames.BladeArmorUnibeam],
bladeburner_success_chance_mult: 1.1,
isSpecial: true,
@@ -2089,7 +2082,7 @@ export function displayAugmentationsContent(contentEl) {
exportGameFn={saveObject.exportGame.bind(saveObject)}
installAugmentationsFn={installAugmentations}
/>,
contentEl
contentEl,
);
}

View File

@@ -1,4 +1,4 @@
import { Augmentation } from "./Augmentation";
import { IMap } from "../types";
export let Augmentations: IMap<Augmentation> = {};
export const Augmentations: IMap<Augmentation> = {};

View File

@@ -1,8 +1,8 @@
export class PlayerOwnedAugmentation {
level: number = 1;
name: string = "";
level = 1;
name = "";
constructor(name: string = "") {
constructor(name = "") {
this.name = name;
}
}

View File

@@ -1,6 +1,6 @@
import { IMap } from "../../types";
export let AugmentationNames: IMap<string> = {
export const AugmentationNames: IMap<string> = {
Targeting1: "Augmented Targeting I",
Targeting2: "Augmented Targeting II",
Targeting3: "Augmented Targeting III",
@@ -89,6 +89,7 @@ export let AugmentationNames: IMap<string> = {
BrachiBlades: "BrachiBlades",
BionicArms: "Bionic Arms",
SNA: "Social Negotiation Assistant (S.N.A)",
HydroflameLeftArm: "Hydroflame Left Arm",
EsperEyewear: "EsperTech Bladeburner Eyewear",
EMS4Recombination: "EMS-4 Recombination",
OrionShoulder: "ORION-MKIV Shoulder",

View File

@@ -15,7 +15,9 @@ import { SourceFileMinus1 } from "./SourceFileMinus1";
import { Settings } from "../../Settings/Settings";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
type IProps = {}
type IProps = {
// nothing special.
}
type IState = {
rerenderFlag: boolean;
@@ -39,7 +41,7 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps
this.listRef = React.createRef();
}
collapseAllHeaders() {
collapseAllHeaders(): void {
const ul = this.listRef.current;
if (ul == null) { return; }
const tickers = ul.getElementsByClassName("accordion-header");
@@ -55,7 +57,7 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps
}
}
expandAllHeaders() {
expandAllHeaders(): void {
const ul = this.listRef.current;
if (ul == null) { return; }
const tickers = ul.getElementsByClassName("accordion-header");
@@ -71,7 +73,7 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps
}
}
rerender() {
rerender(): void {
this.setState((prevState) => {
return {
rerenderFlag: !prevState.rerenderFlag,
@@ -79,17 +81,17 @@ export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps
});
}
sortByAcquirementTime() {
sortByAcquirementTime(): void {
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime;
this.rerender();
}
sortInOrder() {
sortInOrder(): void {
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically
this.rerender();
}
render() {
render(): React.ReactNode {
return (
<>
<ListConfiguration

View File

@@ -7,7 +7,7 @@ import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Augmentations} from "../Augmentations";
function calculateAugmentedStats() {
function calculateAugmentedStats(): any {
const augP: any = {};
for(const aug of Player.queuedAugmentations) {
const augObj = Augmentations[aug.name];
@@ -22,12 +22,12 @@ function calculateAugmentedStats() {
export function PlayerMultipliers(): React.ReactElement {
const mults = calculateAugmentedStats();
function MultiplierTable(rows: any[]): React.ReactElement {
function improvements(r: number) {
let elems: any[] = [];
function improvements(r: number): JSX.Element[] {
let elems: JSX.Element[] = [];
if(r) {
elems = [
<td key='2'>&nbsp;=>&nbsp;</td>,
<td key='3'>{numeralWrapper.formatPercentage(r)}</td>
<td key="2">&nbsp;{"=>"}&nbsp;</td>,
<td key="3">{numeralWrapper.formatPercentage(r)}</td>,
];
}
return elems;
@@ -36,14 +36,26 @@ export function PlayerMultipliers(): React.ReactElement {
return <table>
<tbody>
{rows.map((r: any) => <tr key={r[0]}>
<td key='0'><span>{r[0]} multiplier:&nbsp;</span></td>
<td key='1' style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
<td key="0"><span>{r[0]} multiplier:&nbsp;</span></td>
<td key="1" style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
{improvements(r[2])}
</tr>)}
</tbody>
</table>
}
function BladeburnerMults(): React.ReactElement {
if(!Player.canAccessBladeburner()) return (<></>);
return (<>
{MultiplierTable([
['Bladeburner Success Chance', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
['Bladeburner Max Stamina', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
['Bladeburner Stamina Gain', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
['Bladeburner Field Analysis', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
])}<br />
</>);
}
return (
<>
<p><strong><u>Multipliers:</u></strong></p><br />
@@ -51,38 +63,38 @@ export function PlayerMultipliers(): React.ReactElement {
['Hacking Chance ', Player.hacking_chance_mult, Player.hacking_chance_mult*mults.hacking_chance_mult],
['Hacking Speed ', Player.hacking_speed_mult, Player.hacking_speed_mult*mults.hacking_speed_mult],
['Hacking Money ', Player.hacking_money_mult, Player.hacking_money_mult*mults.hacking_money_mult],
['Hacking Growth ', Player.hacking_grow_mult, Player.hacking_grow_mult*mults.hacking_grow_mult]
['Hacking Growth ', Player.hacking_grow_mult, Player.hacking_grow_mult*mults.hacking_grow_mult],
])}<br />
{MultiplierTable([
['Hacking Level ', Player.hacking_mult, Player.hacking_mult*mults.hacking_mult],
['Hacking Experience ', Player.hacking_exp_mult, Player.hacking_exp_mult*mults.hacking_exp_mult]
['Hacking Experience ', Player.hacking_exp_mult, Player.hacking_exp_mult*mults.hacking_exp_mult],
])}<br />
{MultiplierTable([
['Strength Level ', Player.strength_mult, Player.strength_mult*mults.strength_mult],
['Strength Experience ', Player.strength_exp_mult, Player.strength_exp_mult*mults.strength_exp_mult]
['Strength Experience ', Player.strength_exp_mult, Player.strength_exp_mult*mults.strength_exp_mult],
])}<br />
{MultiplierTable([
['Defense Level ', Player.defense_mult, Player.defense_mult*mults.defense_mult],
['Defense Experience ', Player.defense_exp_mult, Player.defense_exp_mult*mults.defense_exp_mult]
['Defense Experience ', Player.defense_exp_mult, Player.defense_exp_mult*mults.defense_exp_mult],
])}<br />
{MultiplierTable([
['Dexterity Level ', Player.dexterity_mult, Player.dexterity_mult*mults.dexterity_mult],
['Dexterity Experience ', Player.dexterity_exp_mult, Player.dexterity_exp_mult*mults.dexterity_exp_mult]
['Dexterity Experience ', Player.dexterity_exp_mult, Player.dexterity_exp_mult*mults.dexterity_exp_mult],
])}<br />
{MultiplierTable([
['Agility Level ', Player.agility_mult, Player.agility_mult*mults.agility_mult],
['Agility Experience ', Player.agility_exp_mult, Player.agility_exp_mult*mults.agility_exp_mult]
['Agility Experience ', Player.agility_exp_mult, Player.agility_exp_mult*mults.agility_exp_mult],
])}<br />
{MultiplierTable([
['Charisma Level ', Player.charisma_mult, Player.charisma_mult*mults.charisma_mult],
['Charisma Experience ', Player.charisma_exp_mult, Player.charisma_exp_mult*mults.charisma_exp_mult]
['Charisma Experience ', Player.charisma_exp_mult, Player.charisma_exp_mult*mults.charisma_exp_mult],
])}<br />
{MultiplierTable([
@@ -90,19 +102,21 @@ export function PlayerMultipliers(): React.ReactElement {
['Hacknet Node purchase cost ', Player.hacknet_node_purchase_cost_mult, Player.hacknet_node_purchase_cost_mult*mults.hacknet_node_purchase_cost_mult],
['Hacknet Node RAM upgrade cost ', Player.hacknet_node_ram_cost_mult, Player.hacknet_node_ram_cost_mult*mults.hacknet_node_ram_cost_mult],
['Hacknet Node Core purchase cost ', Player.hacknet_node_core_cost_mult, Player.hacknet_node_core_cost_mult*mults.hacknet_node_core_cost_mult],
['Hacknet Node level upgrade cost ', Player.hacknet_node_level_cost_mult, Player.hacknet_node_level_cost_mult*mults.hacknet_node_level_cost_mult]
['Hacknet Node level upgrade cost ', Player.hacknet_node_level_cost_mult, Player.hacknet_node_level_cost_mult*mults.hacknet_node_level_cost_mult],
])}<br />
{MultiplierTable([
['Company reputation gain ', Player.company_rep_mult, Player.company_rep_mult*mults.company_rep_mult],
['Faction reputation gain ', Player.faction_rep_mult, Player.faction_rep_mult*mults.faction_rep_mult],
['Salary ', Player.work_money_mult, Player.work_money_mult*mults.work_money_mult]
['Salary ', Player.work_money_mult, Player.work_money_mult*mults.work_money_mult],
])}<br />
{MultiplierTable([
['Crime success ', Player.crime_success_mult, Player.crime_success_mult*mults.crime_success_mult],
['Crime money ', Player.crime_money_mult, Player.crime_money_mult*mults.crime_money_mult],
])}<br />
<BladeburnerMults />
</>
)
}

View File

@@ -22,7 +22,7 @@ export function PurchasedAugmentations(): React.ReactElement {
augs.push(
<li key={`${ownedAug.name}${ownedAug.level}`}>
<AugmentationAccordion aug={aug} level={level} />
</li>
</li>,
)
}

View File

@@ -25,7 +25,7 @@ export class AugmentationsRoot extends React.Component<IProps, IState> {
super(props);
}
render() {
render(): React.ReactNode {
return (
<div id="augmentations-content">
<h1>Purchased Augmentations</h1>

View File

@@ -5,15 +5,12 @@
import * as React from "react";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { SourceFiles } from "../../SourceFile/SourceFiles";
import { Exploit, ExploitName } from "../../Exploits/Exploit";
import { Accordion } from "../../ui/React/Accordion";
export function SourceFileMinus1(): React.ReactElement {
let exploits = Player.exploits;
const exploits = Player.exploits;
if(exploits.length === 0) {
return <></>

View File

@@ -16,7 +16,7 @@ class BitNode {
number: number;
constructor(n: number, name: string, desc: string="", info: string="") {
constructor(n: number, name: string, desc="", info="") {
this.number = n;
this.name = name;
this.desc = desc;
@@ -221,7 +221,7 @@ BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
"The growth rate of servers is significantly reduced<br>" +
"Weakening a server is twice as effective<br>" +
"Company wages are decreased by 50%<br>" +
"Corporation valuations are 99% lower and are therefore significantly less profitable<br>" +
"Corporation valuations are 90% lower and are therefore significantly less profitable<br>" +
"Hacknet Node production is significantly decreased<br>" +
"Crime and Infiltration are more lucrative<br>" +
"Augmentations are twice as expensive<br><br>" +
@@ -234,10 +234,9 @@ BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
"Level 3: 56%");
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
"To iterate is human, to recurse divine.<br><br>" +
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you Souce-File 12, or " +
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you Source-File 12, or " +
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
"of Source-File 12 lets you start any BitNodes with NeuroFlux Governor equal to the level of this source file.");
// Books: Frontera, Shiner
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
@@ -252,11 +251,11 @@ BitNodes["BitNode22"] = new BitNode(22, "", "COMING SOON");
BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON");
BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON");
export function initBitNodeMultipliers(p: IPlayer) {
export function initBitNodeMultipliers(p: IPlayer): void {
if (p.bitNodeN == null) {
p.bitNodeN = 1;
}
for (var mult in BitNodeMultipliers) {
for (const mult in BitNodeMultipliers) {
if (BitNodeMultipliers.hasOwnProperty(mult)) {
BitNodeMultipliers[mult] = 1;
}
@@ -433,15 +432,15 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.FourSigmaMarketDataCost = 4;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
break;
case 12: //The Recursion
var sf12Lvl = 0;
for (var i = 0; i < p.sourceFiles.length; i++) {
case 12: { //The Recursion
let sf12Lvl = 0;
for (let i = 0; i < p.sourceFiles.length; i++) {
if (p.sourceFiles[i].n === 12) {
sf12Lvl = p.sourceFiles[i].lvl;
}
}
var inc = Math.pow(1.02, sf12Lvl);
var dec = 1/inc;
const inc = Math.pow(1.02, sf12Lvl);
const dec = 1/inc;
// Multiplier for number of augs needed for Daedalus increases
// up to a maximum of 1.34, which results in 40 Augs required
@@ -499,6 +498,7 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.BladeburnerRank = dec;
BitNodeMultipliers.BladeburnerSkillCost = inc;
break;
}
default:
console.warn("Player.bitNodeN invalid");
break;

View File

@@ -1,7 +1,6 @@
import { Augmentations } from "./Augmentation/Augmentations";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import { CONSTANTS } from "./Constants";
import { Engine } from "./engine";
import { Faction } from "./Faction/Faction";
import { Factions, factionExists } from "./Faction/Factions";
@@ -17,17 +16,19 @@ import { dialogBoxCreate } from "../utils/DialogBox";
import {
Reviver,
Generic_toJSON,
Generic_fromJSON
Generic_fromJSON,
} from "../utils/JSONReviver";
import { setTimeoutRef } from "./utils/SetTimeoutRef";
import { formatNumber } from "../utils/StringHelperFunctions";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../utils/StringHelperFunctions";
import { ConsoleHelpText } from "./Bladeburner/data/Help";
import { City } from "./Bladeburner/City";
import { BladeburnerConstants } from "./Bladeburner/data/Constants";
import { Skill } from "./Bladeburner/Skill";
import { Skills } from "./Bladeburner/Skills";
import { SkillNames } from "./Bladeburner/data/SkillNames";
import { Operation } from "./Bladeburner/Operation";
import { BlackOperation } from "./Bladeburner/BlackOperation";
import { BlackOperations } from "./Bladeburner/BlackOperations";
@@ -45,7 +46,6 @@ import { KEY } from "../utils/helpers/keyCodes";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
import { appendLineBreaks } from "../utils/uiHelpers/appendLineBreaks";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElement } from "../utils/uiHelpers/removeElement";
@@ -236,7 +236,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(25, 150), countGrowth:getRandomInt(5, 75)/10,
weights:{hack:0,str:0.05,def:0.05,dex:0.35,agi:0.35,cha:0.1, int:0.05},
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.9, int:1},
isStealth:true
isStealth:true,
});
this.contracts["Bounty Hunter"] = new Contract({
name:"Bounty Hunter",
@@ -248,7 +248,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10,
weights:{hack:0,str:0.15,def:0.15,dex:0.25,agi:0.25,cha:0.1, int:0.1},
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
isKill:true
isKill:true,
});
this.contracts["Retirement"] = new Contract({
name:"Retirement",
@@ -260,7 +260,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10,
weights:{hack:0,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0.1, int:0.1},
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
isKill:true
isKill:true,
});
this.operations["Investigation"] = new Operation({
@@ -275,7 +275,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10,
weights:{hack:0.25,str:0.05,def:0.05,dex:0.2,agi:0.1,cha:0.25, int:0.1},
decays:{hack:0.85,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
isStealth:true
isStealth:true,
});
this.operations["Undercover Operation"] = new Operation({
name:"Undercover Operation",
@@ -288,7 +288,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10,
weights:{hack:0.2,str:0.05,def:0.05,dex:0.2,agi:0.2,cha:0.2, int:0.1},
decays:{hack:0.8,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
isStealth:true
isStealth:true,
});
this.operations["Sting Operation"] = new Operation({
name:"Sting Operation",
@@ -299,19 +299,19 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 150), countGrowth:getRandomInt(3, 40)/10,
weights:{hack:0.25,str:0.05,def:0.05,dex:0.25,agi:0.1,cha:0.2, int:0.1},
decays:{hack:0.8,str:0.85,def:0.85,dex:0.85,agi:0.85,cha:0.7, int:0.9},
isStealth:true
isStealth:true,
});
this.operations["Raid"] = new Operation({
name:"Raid",
desc:"Lead an assault on a known Synthoid community. Note that " +
"there must be an existing Synthoid community in your current city " +
"in order for this Operation to be successful",
"in order for this Operation to be successful.",
baseDifficulty:800, difficultyFac:1.045, rewardFac:1.1, reqdRank:3000,
rankGain:55,rankLoss:2.5,hpLoss:50,
count:getRandomInt(1, 150), countGrowth:getRandomInt(2, 40)/10,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
isKill:true
isKill:true,
});
this.operations["Stealth Retirement Operation"] = new Operation({
name:"Stealth Retirement Operation",
@@ -323,7 +323,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10,
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
isStealth:true, isKill:true
isStealth:true, isKill:true,
});
this.operations["Assassination"] = new Operation({
name:"Assassination",
@@ -335,7 +335,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10,
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.8},
isStealth:true, isKill:true
isStealth:true, isKill:true,
});
}
@@ -736,7 +736,7 @@ Bladeburner.prototype.completeAction = function() {
}
}
var logLossText = "";
if (loss > 0) {logLossText += "Lost " + formatNumber(loss, 3) + " rank.";}
if (loss > 0) {logLossText += "Lost " + formatNumber(loss, 3) + " rank. ";}
if (damage > 0) {logLossText += "Took " + formatNumber(damage, 0) + " damage.";}
if (isOperation && this.logging.ops) {
this.log(action.name + " failed! " + logLossText);
@@ -1069,7 +1069,11 @@ Bladeburner.prototype.gainActionStats = function(action, success) {
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
Player.gainIntelligenceExp(unweightedIntGain * action.weights.int * skillMult);
let intExp = unweightedIntGain * action.weights.int * skillMult;
if (intExp > 1) {
intExp = Math.pow(intExp, 0.8);
}
Player.gainIntelligenceExp(intExp);
}
Bladeburner.prototype.randomEvent = function() {
@@ -1267,7 +1271,7 @@ Bladeburner.prototype.createContent = function() {
DomElems.consoleInput.focus();
}
return false;
}
},
});
DomElems.consoleTable = createElement("table", {class:"bladeburner-console-table"});
DomElems.consoleInputRow = createElement("tr", {class:"bladeburner-console-input-row", id:"bladeburner-console-input-row"});
@@ -1275,7 +1279,7 @@ Bladeburner.prototype.createContent = function() {
DomElems.consoleInputHeader = createElement("pre", {innerText:"> "});
DomElems.consoleInput = createElement("input", {
type:"text", class:"bladeburner-console-input", tabIndex:1,
onfocus:() => {DomElems.consoleInput.value = DomElems.consoleInput.value}
onfocus:() => {DomElems.consoleInput.value = DomElems.consoleInput.value},
});
DomElems.consoleInputCell.appendChild(DomElems.consoleInputHeader);
@@ -1359,7 +1363,7 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText:"Est. Synthoid Population: ",
display:"inline-block",
tooltip:"This is your Bladeburner division's estimate of how many Synthoids exist " +
"in your current city."
"in your current city.",
});
DomElems.overviewEstPopHelpTip = createElement("div", {
@@ -1377,7 +1381,7 @@ Bladeburner.prototype.createOverviewContent = function() {
"The Synthoid populations of cities can change due to your " +
"actions or random events. If random events occur, they will " +
"be logged in the Bladeburner Console.");
}
},
});
DomElems.overviewEstComms = createElement("p", {
@@ -1391,14 +1395,14 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText:"City Chaos: ",
display:"inline-block",
tooltip:"The city's chaos level due to tensions and conflicts between humans and Synthoids. " +
"Having too high of a chaos level can make contracts and operations harder."
"Having too high of a chaos level can make contracts and operations harder.",
});
DomElems.overviewBonusTime = createElement("p", {
innerText: "Bonus time: ",
display: "inline-block",
tooltip: "You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by browser). " +
"Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed."
"Bonus time makes the Bladeburner mechanic progress faster, up to 5x the normal speed.",
});
DomElems.overviewSkillPoints = createElement("p", {display:"block"});
@@ -1434,7 +1438,7 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText:"Cancel", class:"a-link-button",
clickListener:() => {
removeElementById(popupId); return false;
}
},
}))
popupArguments.push(createElement("p", { // Info Text
innerText:"Travel to a different city for your Bladeburner " +
@@ -1456,12 +1460,12 @@ Bladeburner.prototype.createOverviewContent = function() {
removeElementById(popupId);
inst.updateOverviewContent();
return false;
}
},
}));
})(this, i);
}
createPopup(popupId, popupArguments);
}
},
}));
// Faction button
@@ -1489,7 +1493,7 @@ Bladeburner.prototype.createOverviewContent = function() {
}
}
return false;
}
},
}));
}
@@ -1522,14 +1526,14 @@ Bladeburner.prototype.createActionAndSkillsContent = function() {
DomElems.currentTab = buttons[i].toLowerCase();
inst.createActionAndSkillsContent();
return false;
}
},
}));
}) (buttons, i, this, currTab);
}
// General info/description for each action
DomElems.actionsAndSkillsDesc = createElement("p", {
display:"block", margin:"4px", padding:"4px"
display:"block", margin:"4px", padding:"4px",
});
// List for actions/skills
@@ -1574,7 +1578,7 @@ Bladeburner.prototype.createGeneralActionsContent = function() {
for (var actionName in GeneralActions) {
if (GeneralActions.hasOwnProperty(actionName)) {
DomElems.generalActions[actionName] = createElement("div", {
class:"bladeburner-action", name:actionName
class:"bladeburner-action", name:actionName,
});
DomElems.actionsAndSkillsList.appendChild(DomElems.generalActions[actionName]);
}
@@ -1596,7 +1600,7 @@ Bladeburner.prototype.createContractsContent = function() {
for (var contractName in this.contracts) {
if (this.contracts.hasOwnProperty(contractName)) {
DomElems.contracts[contractName] = createElement("div", {
class:"bladeburner-action", name:contractName
class:"bladeburner-action", name:contractName,
});
DomElems.actionsAndSkillsList.appendChild(DomElems.contracts[contractName]);
}
@@ -1625,7 +1629,7 @@ Bladeburner.prototype.createOperationsContent = function() {
for (var operationName in this.operations) {
if (this.operations.hasOwnProperty(operationName)) {
DomElems.operations[operationName] = createElement("div", {
class:"bladeburner-action", name:operationName
class:"bladeburner-action", name:operationName,
});
DomElems.actionsAndSkillsList.appendChild(DomElems.operations[operationName]);
}
@@ -1663,7 +1667,7 @@ Bladeburner.prototype.createBlackOpsContent = function() {
for (var i = blackops.length-1; i >= 0 ; --i) {
if (this.blackops[[blackops[i].name]] == null && i !== 0 && this.blackops[[blackops[i-1].name]] == null) {continue;} // If this one nor the next are completed then this isn't unlocked yet.
DomElems.blackops[blackops[i].name] = createElement("div", {
class:"bladeburner-action", name:blackops[i].name
class:"bladeburner-action", name:blackops[i].name,
});
DomElems.actionsAndSkillsList.appendChild(DomElems.blackops[blackops[i].name]);
}
@@ -1746,7 +1750,7 @@ Bladeburner.prototype.createSkillsContent = function() {
// Skill Points
DomElems.skillPointsDisplay = createElement("p", {
innerHTML:"<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>"
innerHTML:"<br><strong>Skill Points: " + formatNumber(this.skillPoints, 0) + "</strong>",
});
DomElems.actionAndSkillsDiv.appendChild(DomElems.skillPointsDisplay);
@@ -1754,7 +1758,7 @@ Bladeburner.prototype.createSkillsContent = function() {
for (var skillName in Skills) {
if (Skills.hasOwnProperty(skillName)) {
DomElems.skills[skillName] = createElement("div", {
class:"bladeburner-action", name:skillName
class:"bladeburner-action", name:skillName,
});
DomElems.actionsAndSkillsList.appendChild(DomElems.skills[skillName]);
}
@@ -1898,7 +1902,7 @@ Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", {
display:"block",
innerText:createProgressBarText({progress:progress})
innerText:createProgressBarText({progress:progress}),
}));
} else {
// Start button
@@ -1911,13 +1915,13 @@ Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
this.startAction(this.action);
this.updateActionAndSkillsContent();
return false;
}
},
}));
}
appendLineBreaks(el, 2);
el.appendChild(createElement("pre", { // Info
innerHTML:action.desc, display:"inline-block"
innerHTML:action.desc, display:"inline-block",
}));
@@ -1933,14 +1937,14 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
formatNumber(this.actionTimeCurrent, 0) + " / " +
formatNumber(this.actionTimeToComplete, 0) + ")"
: action.name,
display:"inline-block"
display:"inline-block",
}));
if (isActive) { // Progress bar if its active
var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", {
display:"block",
innerText:createProgressBarText({progress:progress})
innerText:createProgressBarText({progress:progress}),
}));
} else { // Start button
el.appendChild(createElement("a", {
@@ -1952,7 +1956,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
this.startAction(this.action);
this.updateActionAndSkillsContent();
return false;
}
},
}));
}
@@ -1963,7 +1967,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
display:"inline-block",
innerText:"Level: " + action.level + " / " + action.maxLevel,
tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel) + " successes " +
"needed for next level"
"needed for next level",
}));
el.appendChild(createElement("a", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@@ -1975,7 +1979,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action
this.updateContractsUIElement(el, action);
return false;
}
},
}));
el.appendChild(createElement("a", {
class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"&darr;",
@@ -1987,7 +1991,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action
this.updateContractsUIElement(el, action);
return false;
}
},
}));
var actionTime = action.getActionTime(this);
@@ -2007,7 +2011,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox";
el.appendChild(createElement("label", {
for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white",
tooltip:"Automatically increase contract level when possible"
tooltip:"Automatically increase contract level when possible",
}));
const checkboxInput = createElement("input", {
@@ -2031,14 +2035,14 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
formatNumber(this.actionTimeCurrent, 0) + " / " +
formatNumber(this.actionTimeToComplete, 0) + ")"
: action.name,
display:"inline-block"
display:"inline-block",
}));
if (isActive) { // Progress bar if its active
var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", {
display:"block",
innerText:createProgressBarText({progress:progress})
innerText:createProgressBarText({progress:progress}),
}));
} else { // Start button and set Team Size button
el.appendChild(createElement("a", {
@@ -2050,7 +2054,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
this.startAction(this.action);
this.updateActionAndSkillsContent();
return false;
}
},
}));
el.appendChild(createElement("a", {
innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button",
@@ -2061,7 +2065,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
innerText:"Enter the amount of team members you would like to take on these " +
"operations. If you do not have the specified number of team members, " +
"then as many as possible will be used. Note that team members may " +
"be lost during operations."
"be lost during operations.",
});
var input = createElement("input", {
@@ -2071,25 +2075,25 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
innerText:"Confirm", class:"a-link-button",
clickListener:() => {
var num = Math.round(parseFloat(input.value));
if (isNaN(num)) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric)")
if (isNaN(num) || num < 0) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
} else {
action.teamCount = num;
this.updateOperationsUIElement(el, action);
}
removeElementById(popupId);
return false;
}
},
});
var cancelBtn = createElement("a", {
innerText:"Cancel", class:"a-link-button",
clickListener:() => {
removeElementById(popupId);
return false;
}
},
});
createPopup(popupId, [txt, input, setBtn, cancelBtn]);
}
},
}));
}
@@ -2100,7 +2104,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
display:"inline-block",
innerText:"Level: " + action.level + " / " + action.maxLevel,
tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel) + " successes " +
"needed for next level"
"needed for next level",
}));
el.appendChild(createElement("a", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@@ -2112,7 +2116,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action
this.updateOperationsUIElement(el, action);
return false;
}
},
}));
el.appendChild(createElement("a", {
class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"&darr;",
@@ -2124,11 +2128,10 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action
this.updateOperationsUIElement(el, action);
return false;
}
},
}));
// General Info
var difficulty = action.getDifficulty();
var actionTime = action.getActionTime(this);
appendLineBreaks(el, 2);
el.appendChild(createElement("pre", {
@@ -2146,7 +2149,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox";
el.appendChild(createElement("label", {
for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white",
tooltip:"Automatically increase operation level when possible"
tooltip:"Automatically increase operation level when possible",
}));
const checkboxInput = createElement("input", {
@@ -2166,7 +2169,6 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
var isActive = el.classList.contains(ActiveActionCssClass);
var isCompleted = (this.blackops[action.name] != null);
var estimatedSuccessChance = action.getSuccessChance(this, {est:true});
var difficulty = action.getDifficulty();
var actionTime = action.getActionTime(this);
var hasReqdRank = this.rank >= action.reqdRank;
@@ -2190,7 +2192,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", {
display:"block",
innerText:createProgressBarText({progress:progress})
innerText:createProgressBarText({progress:progress}),
}));
} else {
el.appendChild(createElement("a", { // Start button
@@ -2202,7 +2204,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
this.startAction(this.action);
this.updateActionAndSkillsContent();
return false;
}
},
}));
el.appendChild(createElement("a", { // Set Team Size Button
innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button",
@@ -2213,7 +2215,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
innerText:"Enter the amount of team members you would like to take on this " +
"BlackOp. If you do not have the specified number of team members, " +
"then as many as possible will be used. Note that team members may " +
"be lost during operations."
"be lost during operations.",
});
var input = createElement("input", {
@@ -2223,25 +2225,25 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
innerText:"Confirm", class:"a-link-button",
clickListener:() => {
var num = Math.round(parseFloat(input.value));
if (isNaN(num)) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric)")
if (isNaN(num) || num < 0) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
} else {
action.teamCount = num;
this.updateBlackOpsUIElement(el, action);
}
removeElementById(popupId);
return false;
}
},
});
var cancelBtn = createElement("a", {
innerText:"Cancel", class:"a-link-button",
clickListener:() => {
removeElementById(popupId);
return false;
}
},
});
createPopup(popupId, [txt, input, setBtn, cancelBtn]);
}
},
}));
}
@@ -2253,7 +2255,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
}));
el.appendChild(createElement("p", {
display:"block", color:hasReqdRank ? "white" : "red",
innerHTML:"Required Rank: " + formatNumber(action.reqdRank, 0) + "<br>"
innerHTML:"Required Rank: " + formatNumber(action.reqdRank, 0) + "<br>",
}));
el.appendChild(createElement("p", {
display:"inline-block",
@@ -2293,7 +2295,7 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
this.upgradeSkill(skill);
this.createActionAndSkillsContent();
return false;
}
},
}));
appendLineBreaks(el, 2);
el.appendChild(createElement("p", {
@@ -2303,7 +2305,7 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
if (maxLvl) {
el.appendChild(createElement("p", {
color:"red", display:"block",
innerText:"MAX LEVEL"
innerText:"MAX LEVEL",
}));
} else {
el.appendChild(createElement("p", {
@@ -2504,7 +2506,7 @@ Bladeburner.prototype.executeAutomateConsoleCommand = function(args) {
case "gen":
if (GeneralActions[val] != null) {
var action = new ActionIdentifier({
type:ActionTypes[val], name:val
type:ActionTypes[val], name:val,
});
if (highLow) {
this.automateActionHigh = action;
@@ -2520,7 +2522,7 @@ Bladeburner.prototype.executeAutomateConsoleCommand = function(args) {
case "contracts":
if (this.contracts[val] != null) {
var action = new ActionIdentifier({
type:ActionTypes.Contract, name:val
type:ActionTypes.Contract, name:val,
});
if (highLow) {
this.automateActionHigh = action;
@@ -2538,7 +2540,7 @@ Bladeburner.prototype.executeAutomateConsoleCommand = function(args) {
case "operation":
if (this.operations[val] != null) {
var action = new ActionIdentifier({
type:ActionTypes.Operation, name:val
type:ActionTypes.Operation, name:val,
});
if (highLow) {
this.automateActionHigh = action;
@@ -3206,8 +3208,8 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
return -1;
}
const sanitizedSize = Math.round(size);
if (isNaN(sanitizedSize)) {
let sanitizedSize = Math.round(size);
if (isNaN(sanitizedSize) || sanitizedSize < 0) {
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`);
return -1;
}

View File

@@ -3,21 +3,20 @@ import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { addOffset } from "../../utils/helpers/addOffset";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { BladeburnerConstants } from "./data/Constants";
// import { Contract } from "./Contract";
// import { Operation } from "./Operation";
// import { BlackOperation } from "./BlackOperation";
import { IBladeburner } from "./IBladeburner";
import { IAction, ISuccessChanceParams } from "./IAction";
class StatsMultiplier {
hack: number = 0;
str: number = 0;
def: number = 0;
dex: number = 0;
agi: number = 0;
cha: number = 0;
int: number = 0;
[key: string]: number;
};
hack = 0;
str = 0;
def = 0;
dex = 0;
agi = 0;
cha = 0;
int = 0;
}
export interface IActionParams {
name?: string;
@@ -43,32 +42,32 @@ export interface IActionParams {
teamCount?: number;
}
export class Action {
name: string = "";
desc: string = "";
export class Action implements IAction {
name = "";
desc = "";
// Difficulty scales with level. See getDifficulty() method
level: number = 1;
maxLevel: number = 1;
autoLevel: boolean = true;
baseDifficulty: number = 100;
difficultyFac: number = 1.01;
level = 1;
maxLevel = 1;
autoLevel = true;
baseDifficulty = 100;
difficultyFac = 1.01;
// Rank increase/decrease is affected by this exponent
rewardFac: number = 1.02;
rewardFac = 1.02;
successes: number = 0;
failures: number = 0;
successes = 0;
failures = 0;
// All of these scale with level/difficulty
rankGain: number = 0;
rankLoss: number = 0;
hpLoss: number = 0;
hpLost: number = 0;
rankGain = 0;
rankLoss = 0;
hpLoss = 0;
hpLost = 0;
// Action Category. Current categories are stealth and kill
isStealth: boolean = false;
isKill: boolean = false;
isStealth = false;
isKill = false;
/**
* Number of this contract remaining, and its growth rate
@@ -81,7 +80,7 @@ export class Action {
weights: StatsMultiplier = {hack:1/7,str:1/7,def:1/7,dex:1/7,agi:1/7,cha:1/7,int:1/7};
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
decays: StatsMultiplier = { hack: 0.9, str: 0.9, def: 0.9, dex: 0.9, agi: 0.9, cha: 0.9, int: 0.9 };
teamCount: number = 0;
teamCount = 0;
// Base Class for Contracts, Operations, and BlackOps
constructor(params: IActionParams| null = null) { // | null = null
@@ -138,7 +137,7 @@ export class Action {
* Tests for success. Should be called when an action has completed
* @param inst {Bladeburner} - Bladeburner instance
*/
attempt(inst: any): boolean {
attempt(inst: IBladeburner): boolean {
return (Math.random() < this.getSuccessChance(inst));
}
@@ -147,7 +146,7 @@ export class Action {
return 1;
}
getActionTime(inst: any): number {
getActionTime(inst: IBladeburner): number {
const difficulty = this.getDifficulty();
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
const skillFac = inst.skillMultipliers.actionTime; // Always < 1
@@ -165,15 +164,15 @@ export class Action {
}
// For actions that have teams. To be implemented by subtypes.
getTeamSuccessBonus(inst: any): number {
getTeamSuccessBonus(inst: IBladeburner): number {
return 1;
}
getActionTypeSkillSuccessBonus(inst: any): number {
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return 1;
}
getChaosCompetencePenalty(inst: any, params: any): number {
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number {
const city = inst.getCurrentCity();
if (params.est) {
return Math.pow((city.popEst / BladeburnerConstants.PopulationThreshold), BladeburnerConstants.PopulationExponent);
@@ -182,7 +181,7 @@ export class Action {
}
}
getChaosDifficultyBonus(inst: any, params: any): number {
getChaosDifficultyBonus(inst: IBladeburner/*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
@@ -198,14 +197,14 @@ export class Action {
* @params - options:
* est (bool): Get success chance estimate instead of real success chance
*/
getSuccessChance(inst: any, params: any={}) {
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams={est: false}): number {
if (inst == null) {throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");}
let difficulty = this.getDifficulty();
let competence = 0;
for (let stat in this.weights) {
for (const stat in this.weights) {
if (this.weights.hasOwnProperty(stat)) {
let playerStatLvl = Player.queryStatFromString(stat);
let key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
const playerStatLvl = Player.queryStatFromString(stat);
const key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
let effMultiplier = inst.skillMultipliers[key];
if (effMultiplier == null) {
console.error(`Failed to find Bladeburner Skill multiplier for: ${stat}`);
@@ -220,7 +219,7 @@ export class Action {
competence *= this.getTeamSuccessBonus(inst);
competence *= this.getChaosCompetencePenalty(inst, params);
difficulty *= this.getChaosDifficultyBonus(inst, params);
difficulty *= this.getChaosDifficultyBonus(inst);
if(this.name == "Raid" && inst.getCurrentCity().comms <= 0) {
return 0;
@@ -253,18 +252,14 @@ export class Action {
}
}
static fromJSON(value: any): Action {
return Generic_fromJSON(Action, value.data);
}
toJSON(): any {
return Generic_toJSON("Action", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Action {
return Generic_fromJSON(Action, value.data);
}
}
Reviver.constructors.Action = Action;

View File

@@ -13,21 +13,22 @@ export class BlackOperation extends Operation {
return 1.5;
}
getChaosCompetencePenalty(inst: any, params: any): number {
getChaosCompetencePenalty(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1;
}
getChaosDifficultyBonus(inst: any, params: any): number {
getChaosDifficultyBonus(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1;
}
static fromJSON(value: any): Operation {
return Generic_fromJSON(BlackOperation, value.data);
}
toJSON(): any {
return Generic_toJSON("BlackOperation", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Operation {
return Generic_fromJSON(BlackOperation, value.data);
}
}
Reviver.constructors.BlackOperation = BlackOperation;

View File

@@ -16,12 +16,12 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:50, rankLoss:10, hpLoss:100,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Zero"] = new BlackOperation({
name:"Operation Zero",
desc:"AeroCorp is one of the world's largest defense contractors. " +
"It's leader, Steve Watataki, is thought to be a supporter of " +
"Its leader, Steve Watataki, is thought to be a supporter of " +
"Synthoid rights. He must be removed.<br><br>" +
"The goal of Operation Zero is to covertly infiltrate AeroCorp and " +
"uncover any incriminating evidence or " +
@@ -33,7 +33,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:60, rankLoss:15, hpLoss:50,
weights:{hack:0.2,str:0.15,def:0.15,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true
isStealth:true,
});
BlackOperations["Operation X"] = new BlackOperation({
name:"Operation X",
@@ -52,7 +52,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:75, rankLoss:15, hpLoss:100,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Titan"] = new BlackOperation({
name:"Operation Titan",
@@ -70,7 +70,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:100, rankLoss:20, hpLoss:100,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Ares"] = new BlackOperation({
name:"Operation Ares",
@@ -84,7 +84,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:125, rankLoss:20, hpLoss:200,
weights:{hack:0,str:0.25,def:0.25,dex:0.25,agi:0.25,cha:0, int:0},
decays:{hack:0,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Archangel"] = new BlackOperation({
name:"Operation Archangel",
@@ -152,7 +152,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:750, rankLoss:60, hpLoss:1000,
weights:{hack:0.05,str:0.2,def:0.2,dex:0.25,agi:0.25,cha:0, int:0.05},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Deckard"] = new BlackOperation({
name:"Operation Deckard",
@@ -160,7 +160,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
"technology in Operation K, we've discovered that a small group of " +
"MK-VI Synthoids were able to make off with the schematics and design " +
"of the technology before the Operation. It is almost a certainty that " +
"these Synthoids are some of the rogue MK-VI ones from the Synthoid Uprising." +
"these Synthoids are some of the rogue MK-VI ones from the Synthoid Uprising.<br><br>" +
"The goal of Operation Deckard is to hunt down these Synthoids and retire " +
"them. I don't need to tell you how critical this mission is.",
baseDifficulty:20e3, reqdRank:40e3,
@@ -202,7 +202,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:2e3, rankLoss:150, hpLoss:1500,
weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Shoulder of Orion"] = new BlackOperation({
name:"Operation Shoulder of Orion",
@@ -218,7 +218,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:2.5e3, rankLoss:500, hpLoss:1500,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true
isStealth:true,
});
BlackOperations["Operation Hyron"] = new BlackOperation({
name:"Operation Hyron",
@@ -231,7 +231,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
"means that the supercomputer may be able to reason abstractly " +
"and become self-aware.<br><br>" +
"I do not need to remind you why sentient-level AIs pose a serious " +
"thread to all of mankind.<br><br>" +
"threat to all of mankind.<br><br>" +
"The research for this project is being conducted at one of Fulcrum " +
"Technologies secret facilities in Aevum, codenamed 'Alpha Ranch'. " +
"Infiltrate the compound, delete and destroy the work, and then find and kill the " +
@@ -240,7 +240,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:3e3, rankLoss:1e3, hpLoss:500,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Morpheus"] = new BlackOperation({
name:"Operation Morpheus",
@@ -257,7 +257,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:4e3, rankLoss:1e3, hpLoss:100,
weights:{hack:0.05,str:0.15,def:0.15,dex:0.3,agi:0.3,cha:0, int:0.05},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isStealth:true
isStealth:true,
});
BlackOperations["Operation Ion Storm"] = new BlackOperation({
name:"Operation Ion Storm",
@@ -272,7 +272,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:5e3, rankLoss:1e3, hpLoss:5000,
weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Annihilus"] = new BlackOperation({
name:"Operation Annihilus",
@@ -286,7 +286,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:7.5e3, rankLoss:1e3, hpLoss:10e3,
weights:{hack:0,str:0.24,def:0.24,dex:0.24,agi:0.24,cha:0, int:0.04},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Ultron"] = new BlackOperation({
name:"Operation Ultron",
@@ -306,7 +306,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:10e3, rankLoss:2e3, hpLoss:10e3,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
isKill:true
isKill:true,
});
BlackOperations["Operation Centurion"] = new BlackOperation({
name:"Operation Centurion",
@@ -342,4 +342,4 @@ export const BlackOperations: IMap<BlackOperation> = {};
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.75},
});
})()
})()

View File

@@ -5,13 +5,13 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviv
import { addOffset } from "../../utils/helpers/addOffset";
export class ChangePopulationByCountParams {
estChange: number = 0;
estOffset: number = 0;
estChange = 0;
estOffset = 0;
}
export class ChangePopulationByPercentageParams {
nonZero: boolean = false;
changeEstEqually: boolean = false;
nonZero = false;
changeEstEqually = false;
}
export class City {
@@ -19,32 +19,32 @@ export class City {
/**
* Name of the city.
*/
name: string = "";
name = "";
/**
* Population of the city.
*/
pop: number = 0;
pop = 0;
/**
* Population estimation of the city.
*/
popEst: number = 0;
popEst = 0;
/**
* Number of communities in the city.
*/
comms: number = 0;
comms = 0;
/**
* Estimated number of communities in the city.
*/
commsEst: number = 0;
commsEst = 0;
/**
* Chaos level of the city.
*/
chaos: number = 0;
chaos = 0;
constructor(name: string = BladeburnerConstants.CityNames[2]) {
this.name = name;
@@ -84,7 +84,7 @@ export class City {
/**
* p is the percentage, not the multiplier (e.g. pass in p = 5 for 5%)
*/
improvePopulationEstimateByPercentage(p: number, skillMult: number=1): void {
improvePopulationEstimateByPercentage(p: number, skillMult=1): void {
p = p*skillMult;
if (isNaN(p)) {throw new Error("NaN passed into City.improvePopulationEstimateByPercentage()");}
if (this.popEst < this.pop) {
@@ -97,7 +97,7 @@ export class City {
}
}
improveCommunityEstimate(n: number=1): void {
improveCommunityEstimate(n=1): void {
if (isNaN(n)) {throw new Error("NaN passed into City.improveCommunityEstimate()");}
if (this.commsEst < this.comms) {
this.commsEst += n;
@@ -154,19 +154,20 @@ export class City {
if (this.chaos < 0) {this.chaos = 0;}
}
/**
* Initiatizes a City object from a JSON save state.
*/
static fromJSON(value: any): City {
return Generic_fromJSON(City, value.data);
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("City", this);
}
/**
* Initiatizes a City object from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): City {
return Generic_fromJSON(City, value.data);
}
}
Reviver.constructors.City = City;

View File

@@ -1,4 +1,4 @@
// import { BladeburnerConstants } from "./data/Constants";
import { IBladeburner } from "./IBladeburner";
import { Action, IActionParams } from "./Action";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
@@ -8,17 +8,18 @@ export class Contract extends Action {
super(params);
}
getActionTypeSkillSuccessBonus(inst: any): number {
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceContract;
}
static fromJSON(value: any): Contract {
return Generic_fromJSON(Contract, value.data);
}
toJSON(): any {
return Generic_toJSON("Contract", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Contract {
return Generic_fromJSON(Contract, value.data);
}
}
Reviver.constructors.Contract = Contract;

View File

@@ -11,7 +11,7 @@ export const GeneralActions: IMap<Action> = {};
name:actionName,
desc:"Improve your abilities at the Bladeburner unit's specialized training " +
"center. Doing this gives experience for all combat stats and also " +
"increases your max stamina."
"increases your max stamina.",
});
actionName = "Field Analysis";
@@ -21,7 +21,7 @@ export const GeneralActions: IMap<Action> = {};
"Bladeburner's unit intelligence on Synthoid locations and " +
"activities. Completing this action will improve the accuracy " +
"of your Synthoid population estimated in the current city.<br><br>" +
"Does NOT require stamina."
"Does NOT require stamina.",
});
actionName = "Recruitment";
@@ -29,7 +29,7 @@ export const GeneralActions: IMap<Action> = {};
name:actionName,
desc:"Attempt to recruit members for your Bladeburner team. These members " +
"can help you conduct operations.<br><br>" +
"Does NOT require stamina."
"Does NOT require stamina.",
});
actionName = "Diplomacy";
@@ -37,7 +37,7 @@ export const GeneralActions: IMap<Action> = {};
name: actionName,
desc: "Improve diplomatic relations with the Synthoid population. " +
"Completing this action will reduce the Chaos level in your current city.<br><br>" +
"Does NOT require stamina."
"Does NOT require stamina.",
});
actionName = "Hyperbolic Regeneration Chamber";

View File

@@ -0,0 +1,71 @@
import { IBladeburner } from "./IBladeburner";
export interface IStatsMultiplier {
[key: string]: number;
hack: number;
str: number;
def: number;
dex: number;
agi: number;
cha: number;
int: number;
}
export interface ISuccessChanceParams {
est: boolean;
}
export interface IAction {
name: string;
desc: string;
// Difficulty scales with level. See getDifficulty() method
level: number;
maxLevel: number;
autoLevel: boolean;
baseDifficulty: number;
difficultyFac: number;
// Rank increase/decrease is affected by this exponent
rewardFac: number;
successes: number;
failures: number;
// All of these scale with level/difficulty
rankGain: number;
rankLoss: number;
hpLoss: number;
hpLost: number;
// Action Category. Current categories are stealth and kill
isStealth: boolean;
isKill: boolean;
/**
* Number of this contract remaining, and its growth rate
* Growth rate is an integer and the count will increase by that integer every "cycle"
*/
count: number;
countGrowth: number;
// Weighting of each stat in determining action success rate
weights: IStatsMultiplier;
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
decays: IStatsMultiplier;
teamCount: number;
getDifficulty(): number;
attempt(inst: IBladeburner): boolean;
getActionTimePenalty(): number;
getActionTime(inst: IBladeburner): number;
getTeamSuccessBonus(inst: IBladeburner): number;
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
getChaosDifficultyBonus(inst: IBladeburner): number;
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams): number;
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
setMaxLevel(baseSuccessesPerLevel: number): void;
toJSON(): any;
}

View File

@@ -0,0 +1,4 @@
export interface IActionIdentifier {
name: string;
type: string;
}

View File

@@ -0,0 +1,39 @@
import { IActionIdentifier } from "./IActionIdentifier";
import { City } from "./City";
export interface IBladeburner {
numHosp: number;
moneyLost: number;
rank: number;
maxRank: number;
skillPoints: number;
totalSkillPoints: number;
teamSize: number;
teamLost: number;
storedCycles: number;
randomEventCounter: number;
actionTimeToComplete: number;
actionTimeCurrent: number;
action: IActionIdentifier;
cities: any;
city: string;
skills: any;
skillMultipliers: any;
staminaBonus: number;
maxStamina: number;
stamina: number;
contracts: any;
operations: any;
blackops: any;
logging: any;
automateEnabled: boolean;
automateActionHigh: number;
automateThreshHigh: number;
automateActionLow: number;
automateThreshLow: number;
consoleHistory: string[];
consoleLogs: string[];
getCurrentCity(): City;
calculateStaminaPenalty(): number;
}

View File

@@ -1,3 +1,4 @@
import { IBladeburner } from "./IBladeburner";
import { BladeburnerConstants } from "./data/Constants";
import { Action, IActionParams } from "./Action";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
@@ -8,8 +9,8 @@ export interface IOperationParams extends IActionParams {
}
export class Operation extends Action {
reqdRank: number = 100;
teamCount: number = 0;
reqdRank = 100;
teamCount = 0;
constructor(params: IOperationParams | null = null) {
super(params);
@@ -18,38 +19,39 @@ export class Operation extends Action {
}
// For actions that have teams. To be implemented by subtypes.
getTeamSuccessBonus(inst: any): number {
getTeamSuccessBonus(inst: IBladeburner): number {
if (this.teamCount && this.teamCount > 0) {
this.teamCount = Math.min(this.teamCount, inst.teamSize);
let teamMultiplier = Math.pow(this.teamCount, 0.05);
const teamMultiplier = Math.pow(this.teamCount, 0.05);
return teamMultiplier;
}
return 1;
}
getActionTypeSkillSuccessBonus(inst: any): number {
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceOperation;
}
getChaosDifficultyBonus(inst: any, params: any): number {
getChaosDifficultyBonus(inst: IBladeburner/*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
let diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
let mult = Math.pow(diff, 0.1);
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
const mult = Math.pow(diff, 0.1);
return mult;
}
return 1;
}
static fromJSON(value: any): Operation {
return Generic_fromJSON(Operation, value.data);
}
toJSON(): any {
return Generic_toJSON("Operation", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Operation {
return Generic_fromJSON(Operation, value.data);
}
}
Reviver.constructors.Operation = Operation;

View File

@@ -33,36 +33,36 @@ export class Skill {
name: string;
desc: string;
// Cost is in Skill Points
baseCost: number = 1;
baseCost = 1;
// Additive cost increase per level
costInc: number = 1;
maxLvl: number = 0;
costInc = 1;
maxLvl = 0;
/**
* These benefits are additive. So total multiplier will be level (handled externally) times the
* effects below
*/
successChanceAll: number = 0;
successChanceStealth: number = 0;
successChanceKill: number = 0;
successChanceContract: number = 0;
successChanceOperation: number = 0;
successChanceAll = 0;
successChanceStealth = 0;
successChanceKill = 0;
successChanceContract = 0;
successChanceOperation = 0;
/**
* This multiplier affects everything that increases synthoid population/community estimate
* e.g. Field analysis, Investigation Op, Undercover Op
*/
successChanceEstimate: number = 0;
actionTime: number = 0;
effHack: number = 0;
effStr: number = 0;
effDef: number = 0;
effDex: number = 0;
effAgi: number = 0;
effCha: number = 0;
stamina: number = 0;
money: number = 0;
expGain: number = 0;
successChanceEstimate = 0;
actionTime = 0;
effHack = 0;
effStr = 0;
effDef = 0;
effDex = 0;
effAgi = 0;
effCha = 0;
stamina = 0;
money = 0;
expGain = 0;
constructor(params: ISkillParams={name:"foo", desc:"foo"}) {
if (!params.name) {

View File

@@ -10,55 +10,55 @@ export const Skills: IMap<Skill> = {};
desc:"Each level of this skill increases your success chance " +
"for all Contracts, Operations, and BlackOps by 3%",
baseCost: 3, costInc: 2.1,
successChanceAll:3
successChanceAll:3,
});
Skills[SkillNames.Cloak] = new Skill({
name:SkillNames.Cloak,
desc:"Each level of this skill increases your " +
"success chance in stealth-related Contracts, Operations, and BlackOps by 5.5%",
baseCost: 2, costInc: 1.1,
successChanceStealth:5.5
successChanceStealth:5.5,
});
Skills[SkillNames.ShortCircuit] = new Skill({
name:SkillNames.ShortCircuit,
desc:"Each level of this skill increases your success chance " +
"in Contracts, Operations, and BlackOps that involve retirement by 5.5%",
baseCost: 2, costInc: 2.1,
successChanceKill:5.5
successChanceKill:5.5,
});
Skills[SkillNames.DigitalObserver] = new Skill({
name:SkillNames.DigitalObserver,
desc:"Each level of this skill increases your success chance in " +
"all Operations and BlackOps by 4%",
baseCost: 2, costInc: 2.1,
successChanceOperation:4
successChanceOperation:4,
});
Skills[SkillNames.Tracer] = new Skill({
name:SkillNames.Tracer,
desc:"Each level of this skill increases your success chance in " +
"all Contracts by 4%",
baseCost: 2, costInc: 2.1,
successChanceContract:4
successChanceContract:4,
});
Skills[SkillNames.Overclock] = new Skill({
name:SkillNames.Overclock,
desc:"Each level of this skill decreases the time it takes " +
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 90)",
baseCost: 3, costInc: 1.4, maxLvl: 90,
actionTime:1
actionTime:1,
});
Skills[SkillNames.Reaper] = new Skill({
name: SkillNames.Reaper,
desc: "Each level of this skill increases your effective combat stats for Bladeburner actions by 2%",
baseCost: 2, costInc: 2.1,
effStr: 2, effDef: 2, effDex: 2, effAgi: 2
effStr: 2, effDef: 2, effDex: 2, effAgi: 2,
});
Skills[SkillNames.EvasiveSystem] = new Skill({
name:SkillNames.EvasiveSystem,
desc:"Each level of this skill increases your effective " +
"dexterity and agility for Bladeburner actions by 4%",
baseCost: 2, costInc: 2.1,
effDex: 4, effAgi: 4
effDex: 4, effAgi: 4,
});
Skills[SkillNames.Datamancer] = new Skill({
name:SkillNames.Datamancer,
@@ -67,13 +67,13 @@ export const Skills: IMap<Skill> = {};
"This affects all actions that can potentially increase " +
"the accuracy of your synthoid population/community estimates.",
baseCost:3, costInc:1,
successChanceEstimate:5
successChanceEstimate:5,
});
Skills[SkillNames.CybersEdge] = new Skill({
name:SkillNames.CybersEdge,
desc:"Each level of this skill increases your max stamina by 2%",
baseCost:1, costInc:3,
stamina:2
stamina:2,
});
Skills[SkillNames.HandsOfMidas] = new Skill({
name: SkillNames.HandsOfMidas,

View File

@@ -1,4 +1,14 @@
export const ConsoleHelpText: {} = {
export const ConsoleHelpText: {
helpList: string[];
automate: string[];
clear: string[];
cls: string[];
help: string[];
log: string[];
skill: string[];
start: string[];
stop: string[];
} = {
helpList: [
"Use 'help [command]' to get more information about a particular Bladeburner console command.",
"",
@@ -8,7 +18,7 @@ export const ConsoleHelpText: {} = {
" log [en/dis] [type] Enable or disable logging for events and actions",
" skill [action] [name] Level or display info about your Bladeburner skills",
" start [type] [name] Start a Bladeburner action/task" ,
" stop Stops your current Bladeburner action/task"
" stop Stops your current Bladeburner action/task",
],
automate: [
"automate [var] [val] [hi/low]",
@@ -30,17 +40,17 @@ export const ConsoleHelpText: {} = {
"Using the four console commands above will set the automation to perform Tracking contracts " +
"if your stamina is 100 or higher, and then switch to Field Analysis if your stamina drops below " +
"50. Note that when setting the action, the name of the action is CASE-SENSITIVE. It must " +
"exactly match whatever the name is in the UI."
"exactly match whatever the name is in the UI.",
],
clear: [
"clear",
"",
"Clears the console"
"Clears the console",
],
cls: [
"cls",
"",
"Clears the console"
"Clears the console",
],
help: [
"help [command]",
@@ -51,7 +61,7 @@ export const ConsoleHelpText: {} = {
"",
" help automate",
"",
"will display specific information about using the automate console command"
"will display specific information about using the automate console command",
],
log: [
"log [en/dis] [type]",
@@ -71,7 +81,7 @@ export const ConsoleHelpText: {} = {
"Logging can be universally enabled/disabled using the 'all' keyword:",
"",
" log dis all",
" log en all"
" log en all",
],
skill: [
"skill [action] [name]",
@@ -91,7 +101,7 @@ export const ConsoleHelpText: {} = {
"",
"This console command can also be used to level up skills:",
"",
" skill level [skill name]"
" skill level [skill name]",
],
start: [
"start [type] [name]",
@@ -106,11 +116,11 @@ export const ConsoleHelpText: {} = {
"Examples:",
"",
" start contract Tracking",
" start op 'Undercover Operation'"
" start op 'Undercover Operation'",
],
stop:[
"stop",
"",
"Stop your current action and go idle."
"Stop your current action and go idle.",
],
}

View File

@@ -38,7 +38,7 @@ for (var i = blackops.length-1; i >= 0 ; --i) {
import * as React from "react";
export function BlackOperationsPage(inst: any): React.ReactElement {
export function BlackOperationsPage(): React.ReactElement {
// Put Black Operations in sequence of required rank
const blackops = [];
for (const name in BlackOperations) {
@@ -55,9 +55,8 @@ export function BlackOperationsPage(inst: any): React.ReactElement {
Black Operations (Black Ops) are special, one-time covert operations. Each Black Op must be unlocked successively by completing the one before it.<br /><br />
<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete all of the Black Ops.</b><br /><br />
Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank losses.</p>
{blackops.map( op =>
<div className="bladeburner-action">
</div>
{blackops.map(() => <div className="bladeburner-action">
</div>,
)}
</div>)
}

424
src/Casino/Blackjack.tsx Normal file
View File

@@ -0,0 +1,424 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Money } from "../ui/React/Money";
import { Game } from "./Game";
import { Deck } from "./CardDeck/Deck";
import { Hand } from "./CardDeck/Hand";
import { InputAdornment } from "@material-ui/core";
import { ReactCard } from "./CardDeck/ReactCard";
import { MuiTextField } from "../ui/React/MuiTextField";
import { MuiButton } from "../ui/React/MuiButton";
import { MuiPaper } from "../ui/React/MuiPaper";
const MAX_BET = 100e6;
enum Result {
Pending = "",
PlayerWon = "You won!",
PlayerWonByBlackjack = "You Won! Blackjack!",
DealerWon = "You lost!",
Tie = "Push! (Tie)",
}
type Props = {
p: IPlayer;
}
type State ={
playerHand: Hand;
dealerHand: Hand;
bet: number;
betInput: string;
gameInProgress: boolean;
result: Result;
gains: number; // Track gains only for this session
wagerInvalid: boolean;
wagerInvalidHelperText: string;
}
export class Blackjack extends Game<Props, State> {
deck: Deck;
constructor(props: Props) {
super(props);
this.deck = new Deck(5); // 5-deck multideck
const initialBet = 1e6;
this.state = {
playerHand: new Hand([]),
dealerHand: new Hand([]),
bet: initialBet,
betInput: String(initialBet),
gameInProgress: false,
result: Result.Pending,
gains: 0,
wagerInvalid: false,
wagerInvalidHelperText: "",
}
}
canStartGame = (): boolean => {
const { p } = this.props;
const { bet } = this.state;
return p.canAfford(bet);
}
startGame = (): void => {
if (!this.canStartGame()) { return; }
// Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could
// always reload without saving but w.e)
this.props.p.loseMoney(this.state.bet);
const playerHand = new Hand([ this.deck.safeDrawCard(), this.deck.safeDrawCard() ]);
const dealerHand = new Hand([ this.deck.safeDrawCard(), this.deck.safeDrawCard() ]);
this.setState({
playerHand,
dealerHand,
gameInProgress: true,
result: Result.Pending,
});
// If the player is dealt a blackjack and the dealer is not, then the player
// immediately wins
if (this.getTrueHandValue(playerHand) === 21) {
if (this.getTrueHandValue(dealerHand) === 21) {
this.finishGame(Result.Tie);
} else {
this.finishGame(Result.PlayerWonByBlackjack);
}
} else if (this.getTrueHandValue(dealerHand) === 21) {
// Check if dealer won by blackjack. We know at this point that the player does not also have blackjack.
this.finishGame(Result.DealerWon);
}
}
// Returns an array of numbers representing all possible values of the given Hand. The reason it needs to be
// an array is because an Ace can count as both 1 and 11.
getHandValue = (hand: Hand): number[] => {
let result: number[] = [ 0 ];
for (let i = 0 ; i < hand.cards.length; ++i) {
const value = hand.cards[i].value;
if (value >= 10) {
result = result.map((x) => x + 10);
} else if (value === 1) {
result = result.flatMap((x) => [ x + 1, x + 11 ]);
} else {
result = result.map((x) => x + value);
}
}
return result;
}
// Returns the single hand value used for determine things like victory and whether or not
// the dealer has to hit. Essentially this uses the biggest value that's 21 or under. If no such value exists,
// then it means the hand is busted and we can just return whatever
getTrueHandValue = (hand: Hand): number => {
const handValues = this.getHandValue(hand);
const valuesUnder21 = handValues.filter((x) => (x <= 21));
if (valuesUnder21.length > 0) {
valuesUnder21.sort((a, b) => a - b);
return valuesUnder21[valuesUnder21.length - 1];
} else {
// Just return the first value. It doesnt really matter anyways since hand is buted
return handValues[0];
}
}
// Returns all hand values that are 21 or under. If no values are 21 or under, then the first value is returned.
getHandDisplayValues = (hand: Hand): number[] => {
const handValues = this.getHandValue(hand);
if (this.isHandBusted(hand)) {
// Hand is busted so just return the 1st value, doesn't really matter
return [ ...new Set([ handValues[0] ]) ];
} else {
return [ ...new Set(handValues.filter((x) => x <= 21)) ];
}
}
isHandBusted = (hand: Hand): boolean => {
return this.getTrueHandValue(hand) > 21;
}
playerHit = (event: React.MouseEvent): void => {
if (!event.isTrusted) { return; }
const newHand = this.state.playerHand.addCards(this.deck.safeDrawCard());
this.setState({
playerHand: newHand,
});
// Check if player busted, and finish the game if so
if (this.isHandBusted(newHand)) {
this.finishGame(Result.DealerWon);
}
}
playerStay = (event: React.MouseEvent): void => {
if (!event.isTrusted) { return; }
// Determine if Dealer needs to hit. A dealer must hit if they have 16 or lower.
// If the dealer has a Soft 17 (Ace + 6), then they stay.
let newDealerHand = this.state.dealerHand;
while (true) {
// The dealer's "true" hand value is the 2nd one if its 21 or less (the 2nd value is always guaranteed
// to be equal or larger). Otherwise its the 1st.
const dealerHandValue = this.getTrueHandValue(newDealerHand);
if (dealerHandValue <= 16) {
newDealerHand = newDealerHand.addCards(this.deck.safeDrawCard());
} else {
break;
}
}
this.setState({
dealerHand: newDealerHand,
})
// If dealer has busted, then player wins
if (this.isHandBusted(newDealerHand)) {
this.finishGame(Result.PlayerWon);
} else {
const dealerHandValue = this.getTrueHandValue(newDealerHand);
const playerHandValue = this.getTrueHandValue(this.state.playerHand);
console.log(`dealerHandValue: ${dealerHandValue}`);
console.log(`playerHandValue: ${playerHandValue}`);
// We expect nobody to have busted. If someone busted, there is an error
// in our game logic
if (dealerHandValue > 21 || playerHandValue > 21) {
throw new Error("Someone busted when not expected to");
}
if (playerHandValue > dealerHandValue) {
this.finishGame(Result.PlayerWon);
} else if (playerHandValue < dealerHandValue) {
this.finishGame(Result.DealerWon);
} else {
this.finishGame(Result.Tie);
}
}
}
finishGame = (result: Result): void => {
let gains = 0;
if (this.isPlayerWinResult(result)) {
gains = this.state.bet;
// We 2x the gains because we took away money at the start, so we need to give the original bet back.
this.win(this.props.p, 2 * gains);
} else if (result === Result.DealerWon) {
gains = -1 * this.state.bet;
// Dont need to take money here since we already did it at the start
} else if (result === Result.Tie) {
this.win(this.props.p, this.state.bet); // Get the original bet back
}
this.setState({
gameInProgress: false,
result,
gains: this.state.gains + gains,
});
}
isPlayerWinResult = (result: Result): boolean => {
return (result === Result.PlayerWon || result === Result.PlayerWonByBlackjack);
}
wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
const { p } = this.props;
const betInput = event.target.value;
const wager = Math.round(parseFloat(betInput));
if (isNaN(wager)) {
this.setState({
bet: 0,
betInput,
wagerInvalid: true,
wagerInvalidHelperText: "Not a valid number",
});
} else if (wager <= 0) {
this.setState({
bet: 0,
betInput,
wagerInvalid: true,
wagerInvalidHelperText: "Must bet a postive amount",
});
} else if (wager > MAX_BET) {
this.setState({
bet: 0,
betInput,
wagerInvalid: true,
wagerInvalidHelperText: "Exceeds max bet",
});
} else if (!p.canAfford(wager)) {
this.setState({
bet: 0,
betInput,
wagerInvalid: true,
wagerInvalidHelperText: "Not enough money",
});
} else {
// Valid wager
this.setState({
bet: wager,
betInput,
wagerInvalid: false,
wagerInvalidHelperText: "",
result: Result.Pending, // Reset previous game status to clear the win/lose text UI
});
}
}
// Start game button
startOnClick = (event: React.MouseEvent): void => {
// Protect against scripting...although maybe this would be fun to automate
if (!event.isTrusted) { return; }
if (!this.state.wagerInvalid) {
this.startGame();
}
}
render(): React.ReactNode {
const {
betInput,
playerHand,
dealerHand,
gameInProgress,
result,
wagerInvalid,
wagerInvalidHelperText,
gains,
} = this.state;
// Get the player totals to display.
const playerHandValues = this.getHandDisplayValues(playerHand);
const dealerHandValues = this.getHandDisplayValues(dealerHand);
return (
<div>
{/* Wager input */}
<div>
<MuiTextField
value={betInput}
label={
<>
{"Wager (Max: "}
{Money(MAX_BET)}
{")"}
</>
}
disabled={gameInProgress}
onChange={this.wagerOnChange}
error={wagerInvalid}
helperText={wagerInvalid ? wagerInvalidHelperText : ""}
type="number"
variant="filled"
style={{
width: "200px",
}}
InputProps={{
startAdornment: <InputAdornment position="start" >$</InputAdornment>,
}} />
<p>
{"Total earnings this session: "}
{Money(gains)}
</p>
</div>
{/* Buttons */}
{!gameInProgress ? (
<div>
<MuiButton
color="primary"
onClick={this.startOnClick}
disabled={wagerInvalid || !this.canStartGame()}>
Start
</MuiButton>
</div>
) : (
<div>
<MuiButton color="primary" onClick={this.playerHit} >
Hit
</MuiButton>
<MuiButton color="secondary" onClick={this.playerStay} >
Stay
</MuiButton>
</div>
)}
{/* Main game part. Displays both if the game is in progress OR if there's a result so you can see
* the cards that led to that result. */}
{(gameInProgress || result !== Result.Pending) && (
<div>
<MuiPaper variant="outlined" elevation={2}>
<pre>Player</pre>
{playerHand.cards.map((card, i) => (
<ReactCard card={card} key={i} />
))}
<pre>Value(s): </pre>
{playerHandValues.map((value, i) => (
<pre key={i}>{value}</pre>
))}
</MuiPaper>
<br />
<MuiPaper variant="outlined" elevation={2}>
<pre>Dealer</pre>
{dealerHand.cards.map((card, i) => (
// Hide every card except the first while game is in progress
<ReactCard card={card} hidden={gameInProgress && i !== 0} key={i} />
))}
{!gameInProgress && (
<>
<pre>Value(s): </pre>
{dealerHandValues.map((value, i) => (
<pre key={i}>{value}</pre>
))}
</>
)}
</MuiPaper>
</div>
)}
{/* Results from previous round */}
{result !== Result.Pending && (
<p>
{result}
{this.isPlayerWinResult(result) && (
<>
{" You gained "}
{Money(this.state.bet)}
</>
)}
{result === Result.DealerWon && (
<>
{" You lost "}
{Money(this.state.bet)}
</>
)}
</p>
)}
</div>
)
}
}

View File

@@ -0,0 +1,42 @@
// Enum values are lowercased to match css classes
export enum Suit {
Clubs = "clubs",
Diamonds = "diamonds",
Hearts = "hearts",
Spades = "spades",
}
export class Card {
constructor(readonly value: number, readonly suit: Suit) {
if (value < 1 || value > 13) {
throw new Error(`Card instantiated with improper value: ${value}`);
}
}
formatValue(): string {
switch (this.value) {
case 1:
return "A";
case 11:
return "J";
case 12:
return "Q";
case 13:
return "K";
default:
return `${this.value}`;
}
}
isRedSuit(): boolean {
return this.suit === Suit.Hearts || this.suit === Suit.Diamonds;
}
getStringRepresentation(): string {
const value = this.formatValue();
return `${value} of ${this.suit}`;
}
}

View File

@@ -0,0 +1,58 @@
import { Card, Suit } from "./Card";
import { shuffle } from "lodash";
export class Deck {
private cards: Card[] = [];
// Support multiple decks
constructor(private numDecks = 1) {
this.reset();
}
shuffle(): void {
this.cards = shuffle(this.cards); // Just use lodash
}
drawCard(): Card {
if (this.cards.length == 0) {
throw new Error("Tried to draw card from empty deck");
}
return this.cards.shift() as Card; // Guaranteed to return a Card since we throw an Error if array is empty
}
// Draws a card, resetting the deck beforehands if the Deck is empty
safeDrawCard(): Card {
if (this.cards.length === 0) {
this.reset();
}
return this.drawCard();
}
// Reset the deck back to the original 52 cards and shuffle it
reset(): void {
this.cards = [];
for (let i = 1; i <= 13; ++i) {
for (let j = 0; j < this.numDecks; ++j) {
this.cards.push(new Card(i, Suit.Clubs));
this.cards.push(new Card(i, Suit.Diamonds));
this.cards.push(new Card(i, Suit.Hearts));
this.cards.push(new Card(i, Suit.Spades));
}
}
this.shuffle();
}
size(): number {
return this.cards.length;
}
isEmpty(): boolean {
return this.cards.length === 0;
}
}

View File

@@ -0,0 +1,25 @@
/**
* Represents a Hand of cards.
*
* This class is IMMUTABLE
*/
import { Card } from "./Card";
export class Hand {
constructor(readonly cards: readonly Card[]) {}
addCards(...cards: Card[]): Hand {
return new Hand([ ...this.cards, ...cards ]);
}
removeByIndex(i: number): Hand {
if (i >= this.cards.length) {
throw new Error(`Tried to remove invalid card from Hand by index: ${i}`);
}
return new Hand([ ...this.cards.slice().splice(i, 1) ])
}
}

View File

@@ -0,0 +1,40 @@
import React, { FC } from "react";
import { Card, Suit } from "./Card";
type Props = {
card: Card;
hidden?: boolean;
}
export const ReactCard: FC<Props> = ({ card, hidden }) => {
let suit : React.ReactNode;
switch (card.suit) {
case Suit.Clubs:
suit = <span>&#9827;</span>;
break;
case Suit.Diamonds:
suit = <span>&#9830;</span>;
break;
case Suit.Hearts:
suit = <span>&#9829;</span>;
break;
case Suit.Spades:
suit = <span>&#9824;</span>;
break;
default:
throw new Error(`MissingCaseException: ${card.suit}`);
}
return (
<div className={`casino-card ${card.isRedSuit() ? "red" : "black"}`}>
<>
<div className="value">
{hidden ? " - " : card.formatValue()}
</div>
<div className={`suit`}>
{hidden ? " - " : suit}
</div>
</>
</div>
)
}

View File

@@ -5,10 +5,11 @@
*/
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { BadRNG } from "./RNG";
import { Game } from "./Game";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { BadRNG } from "./RNG";
import { Game } from "./Game";
import { trusted } from "./utils";
type IProps = {
p: IPlayer;
@@ -18,8 +19,10 @@ type IState = {
investment: number;
result: any;
status: string;
playLock: boolean;
}
const minPlay = 0;
const maxPlay = 10e3;
export class CoinFlip extends Game<IProps, IState> {
@@ -31,24 +34,28 @@ export class CoinFlip extends Game<IProps, IState> {
investment: 1000,
result: <span> </span>,
status: '',
playLock: false,
};
this.play = this.play.bind(this);
this.updateInvestment = this.updateInvestment.bind(this);
}
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
updateInvestment(e: React.FormEvent<HTMLInputElement>): void {
let investment: number = parseInt(e.currentTarget.value);
if (isNaN(investment)) {
investment = 1000;
investment = minPlay;
}
if (investment > maxPlay) {
investment = maxPlay;
}
if (investment < minPlay) {
investment = minPlay;
}
this.setState({investment: investment});
}
play(guess: string) {
play(guess: string): void {
if(this.reachedLimit(this.props.p)) return;
const v = BadRNG.random();
let letter: string;
@@ -61,7 +68,9 @@ export class CoinFlip extends Game<IProps, IState> {
this.setState({
result: <span className={correct ? "text" : "failure"}>{letter}</span>,
status: correct ? " win!" : "lose!",
playLock: true,
});
setTimeout(()=>this.setState({playLock: false}), 250);
if (correct) {
this.win(this.props.p, this.state.investment);
} else {
@@ -71,7 +80,7 @@ export class CoinFlip extends Game<IProps, IState> {
}
render() {
render(): React.ReactNode {
return <>
<pre>
++<br />
@@ -80,9 +89,9 @@ export class CoinFlip extends Game<IProps, IState> {
| | | |<br />
++<br />
</pre>
<span className="text">Play for: </span><input type="number" className='text-input' onChange={this.updateInvestment} value={this.state.investment} /><br />
<StdButton onClick={() => this.play('H')} text={"Head!"} />
<StdButton onClick={() => this.play('T')} text={"Tail!"} />
<span className="text">Play for: </span><input type="number" className="text-input" onChange={this.updateInvestment} value={this.state.investment} /><br />
<StdButton onClick={trusted(() => this.play('H'))} text={"Head!"} disabled={this.state.playLock} />
<StdButton onClick={trusted(() => this.play('T'))} text={"Tail!"} disabled={this.state.playLock} />
<h1>{this.state.status}</h1>
</>
}

View File

@@ -5,7 +5,7 @@ import { dialogBoxCreate } from "../../utils/DialogBox";
const gainLimit = 10e9;
export class Game<T,U> extends React.Component<T, U> {
win(p: IPlayer, n: number) {
win(p: IPlayer, n: number): void{
p.gainMoney(n);
p.recordMoneySource(n, "casino");
}

View File

@@ -1,6 +1,6 @@
export interface RNG {
random(): number
random(): number;
}
/*
@@ -9,16 +9,16 @@ export interface RNG {
*/
class RNG0 implements RNG {
x: number;
m: number = 1024;
a: number = 341;
c: number = 1;
m = 1024;
a = 341;
c = 1;
constructor() {
this.x = 0;
this.reset();
}
step() {
step(): void {
this.x = (this.a*this.x+this.c) % this.m;
}
@@ -27,7 +27,7 @@ class RNG0 implements RNG {
return this.x/this.m;
}
reset() {
reset(): void {
this.x = (new Date()).getTime() % this.m;
}
}
@@ -39,9 +39,9 @@ export const BadRNG: RNG0 = new RNG0();
* The period is 6e12.
*/
export class WHRNG implements RNG {
s1: number = 0;
s2: number = 0;
s3: number = 0;
s1 = 0;
s2 = 0;
s3 = 0;
constructor(totalPlaytime: number) {
// This one is seeded by the players total play time.
@@ -51,7 +51,7 @@ export class WHRNG implements RNG {
this.s3 = v;
}
step() {
step(): void {
this.s1 = (171 * this.s1) % 30269;
this.s2 = (172 * this.s2) % 30307;
this.s3 = (170 * this.s3) % 30323;

View File

@@ -1,10 +1,11 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { Money } from "../ui/React/Money";
import { Game } from "./Game";
import { WHRNG } from "./RNG";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { Money } from "../ui/React/Money";
import { Game } from "./Game";
import { WHRNG } from "./RNG";
import { trusted } from "./utils";
type IProps = {
p: IPlayer;
@@ -19,17 +20,14 @@ type IState = {
strategy: Strategy;
}
const maxPlay = 1e6;
const minPlay = 0;
const maxPlay = 1e7;
function isRed(n: number): boolean {
return [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
21, 23, 25, 27, 30, 32, 34, 36].includes(n);
}
function isBlack(n: number): boolean {
return !isRed(n);
}
type Strategy = {
match: (n: number) => boolean;
payout: number;
@@ -100,14 +98,14 @@ const strategies: {
Third2: {
match: (n: number): boolean => {
if (n === 0) return false;
return 13 <= n && n <= 24;
return n >= 13 && n <= 24;
},
payout: 2,
},
Third3: {
match: (n: number): boolean => {
if (n === 0) return false;
return 25 <= n;
return n >= 25;
},
payout: 2,
},
@@ -123,7 +121,7 @@ function Single(s: number): Strategy {
}
export class Roulette extends Game<IProps, IState> {
interval: number = -1;
interval = -1;
rng: WHRNG;
constructor(props: IProps) {
@@ -138,7 +136,7 @@ export class Roulette extends Game<IProps, IState> {
lock: true,
strategy: {
payout: 0,
match: (n: number): boolean => { return false },
match: (): boolean => { return false },
},
}
@@ -148,38 +146,41 @@ export class Roulette extends Game<IProps, IState> {
}
componentDidMount() {
componentDidMount(): void {
this.interval = setInterval(this.step, 50);
}
step() {
step(): void {
if (!this.state.lock) {
this.setState({n: Math.floor(Math.random()*37)});
}
}
componentWillUnmount() {
componentWillUnmount(): void {
clearInterval(this.interval);
}
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
updateInvestment(e: React.FormEvent<HTMLInputElement>): void {
let investment: number = parseInt(e.currentTarget.value);
if (isNaN(investment)) {
investment = 1000;
investment = minPlay;
}
if (investment > maxPlay) {
investment = maxPlay
investment = maxPlay;
}
if (investment < minPlay) {
investment = minPlay;
}
this.setState({investment: investment});
}
currentNumber() {
currentNumber(): string {
if (this.state.n === 0) return '0';
const color = isRed(this.state.n) ? 'R' : 'B';
return `${this.state.n}${color}`;
}
play(s: Strategy) {
play(s: Strategy): void {
if(this.reachedLimit(this.props.p)) return;
this.setState({
canPlay: false,
@@ -218,70 +219,70 @@ export class Roulette extends Game<IProps, IState> {
}
render() {
render(): React.ReactNode {
return <>
<h1>{this.currentNumber()}</h1>
<input type="number" className='text-input' onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
<input type="number" className="text-input" onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
<h1>{this.state.status}</h1>
<table>
<tbody>
<tr>
<td><StdButton text={"3"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(3))} /></td>
<td><StdButton text={"6"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(6))} /></td>
<td><StdButton text={"9"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(9))} /></td>
<td><StdButton text={"12"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(12))} /></td>
<td><StdButton text={"15"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(15))} /></td>
<td><StdButton text={"18"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(18))} /></td>
<td><StdButton text={"21"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(21))} /></td>
<td><StdButton text={"24"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(24))} /></td>
<td><StdButton text={"27"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(27))} /></td>
<td><StdButton text={"30"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(30))} /></td>
<td><StdButton text={"33"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(33))} /></td>
<td><StdButton text={"36"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(36))} /></td>
<td><StdButton text={"3"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(3)))} /></td>
<td><StdButton text={"6"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(6)))} /></td>
<td><StdButton text={"9"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(9)))} /></td>
<td><StdButton text={"12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(12)))} /></td>
<td><StdButton text={"15"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(15)))} /></td>
<td><StdButton text={"18"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(18)))} /></td>
<td><StdButton text={"21"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(21)))} /></td>
<td><StdButton text={"24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(24)))} /></td>
<td><StdButton text={"27"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(27)))} /></td>
<td><StdButton text={"30"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(30)))} /></td>
<td><StdButton text={"33"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(33)))} /></td>
<td><StdButton text={"36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(36)))} /></td>
</tr>
<tr>
<td><StdButton text={"2"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(2))} /></td>
<td><StdButton text={"5"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(5))} /></td>
<td><StdButton text={"8"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(8))} /></td>
<td><StdButton text={"11"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(11))} /></td>
<td><StdButton text={"14"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(14))} /></td>
<td><StdButton text={"17"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(17))} /></td>
<td><StdButton text={"20"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(20))} /></td>
<td><StdButton text={"23"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(23))} /></td>
<td><StdButton text={"26"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(26))} /></td>
<td><StdButton text={"29"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(29))} /></td>
<td><StdButton text={"32"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(32))} /></td>
<td><StdButton text={"35"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(35))} /></td>
<td><StdButton text={"2"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(2)))} /></td>
<td><StdButton text={"5"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(5)))} /></td>
<td><StdButton text={"8"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(8)))} /></td>
<td><StdButton text={"11"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(11)))} /></td>
<td><StdButton text={"14"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(14)))} /></td>
<td><StdButton text={"17"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(17)))} /></td>
<td><StdButton text={"20"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(20)))} /></td>
<td><StdButton text={"23"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(23)))} /></td>
<td><StdButton text={"26"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(26)))} /></td>
<td><StdButton text={"29"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(29)))} /></td>
<td><StdButton text={"32"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(32)))} /></td>
<td><StdButton text={"35"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(35)))} /></td>
</tr>
<tr>
<td><StdButton text={"1"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(1))} /></td>
<td><StdButton text={"4"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(4))} /></td>
<td><StdButton text={"7"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(7))} /></td>
<td><StdButton text={"10"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(10))} /></td>
<td><StdButton text={"13"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(13))} /></td>
<td><StdButton text={"16"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(16))} /></td>
<td><StdButton text={"19"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(19))} /></td>
<td><StdButton text={"22"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(22))} /></td>
<td><StdButton text={"25"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(25))} /></td>
<td><StdButton text={"28"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(28))} /></td>
<td><StdButton text={"31"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(31))} /></td>
<td><StdButton text={"34"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(34))} /></td>
<td><StdButton text={"1"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(1)))} /></td>
<td><StdButton text={"4"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(4)))} /></td>
<td><StdButton text={"7"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(7)))} /></td>
<td><StdButton text={"10"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(10)))} /></td>
<td><StdButton text={"13"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(13)))} /></td>
<td><StdButton text={"16"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(16)))} /></td>
<td><StdButton text={"19"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(19)))} /></td>
<td><StdButton text={"22"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(22)))} /></td>
<td><StdButton text={"25"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(25)))} /></td>
<td><StdButton text={"28"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(28)))} /></td>
<td><StdButton text={"31"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(31)))} /></td>
<td><StdButton text={"34"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(34)))} /></td>
</tr>
<tr>
<td colSpan={4}><StdButton text={"1 to 12"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Third1)} /></td>
<td colSpan={4}><StdButton text={"13 to 24"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Third2)} /></td>
<td colSpan={4}><StdButton text={"25 to 36"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Third3)} /></td>
<td colSpan={4}><StdButton text={"1 to 12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third1))} /></td>
<td colSpan={4}><StdButton text={"13 to 24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third2))} /></td>
<td colSpan={4}><StdButton text={"25 to 36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third3))} /></td>
</tr>
<tr>
<td colSpan={2}><StdButton text={"Red"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Red)} /></td>
<td colSpan={2}><StdButton text={"Black"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Black)} /></td>
<td colSpan={2}><StdButton text={"Odd"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Odd)} /></td>
<td colSpan={2}><StdButton text={"Even"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Even)} /></td>
<td colSpan={2}><StdButton text={"High"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.High)} /></td>
<td colSpan={2}><StdButton text={"Low"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Low)} /></td>
<td colSpan={2}><StdButton text={"Red"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Red))} /></td>
<td colSpan={2}><StdButton text={"Black"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Black))} /></td>
<td colSpan={2}><StdButton text={"Odd"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Odd))} /></td>
<td colSpan={2}><StdButton text={"Even"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Even))} /></td>
<td colSpan={2}><StdButton text={"High"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.High))} /></td>
<td colSpan={2}><StdButton text={"Low"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Low))} /></td>
</tr>
<tr>
<td><StdButton text={"0"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(0))} /></td>
<td><StdButton text={"0"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(0)))} /></td>
</tr>
</tbody>
</table>

View File

@@ -4,7 +4,8 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { Money } from "../ui/React/Money";
import { WHRNG } from "./RNG";
import { Game } from "./Game";
import { Game } from "./Game";
import { trusted } from "./utils";
type IProps = {
p: IPlayer;
@@ -19,7 +20,7 @@ type IState = {
}
// statically shuffled array of symbols.
let symbols = ["D", "C", "$", "?", "♥", "A", "C", "B", "C", "E", "B", "E", "C",
const symbols = ["D", "C", "$", "?", "♥", "A", "C", "B", "C", "E", "B", "E", "C",
"*", "D", "♥", "B", "A", "A", "A", "C", "A", "D", "B", "E", "?", "D", "*",
"@", "♥", "B", "E", "?"];
@@ -57,11 +58,12 @@ const payLines = [
[[1, 0], [2, 1], [2, 2], [2, 3], [1, 4]],
];
const minPlay = 0;
const maxPlay = 1e6;
export class SlotMachine extends Game<IProps, IState> {
rng: WHRNG;
interval: number = -1;
interval = -1;
constructor(props: IProps) {
super(props);
@@ -84,11 +86,11 @@ export class SlotMachine extends Game<IProps, IState> {
this.updateInvestment = this.updateInvestment.bind(this);
}
componentDidMount() {
componentDidMount(): void {
this.interval = setInterval(this.step, 50);
}
step() {
step(): void {
let stoppedOne = false;
const index = this.state.index.slice();
for(const i in index) {
@@ -104,7 +106,7 @@ export class SlotMachine extends Game<IProps, IState> {
}
}
componentWillUnmount() {
componentWillUnmount(): void {
clearInterval(this.interval);
}
@@ -116,7 +118,7 @@ export class SlotMachine extends Game<IProps, IState> {
];
}
play() {
play(): void {
if(this.reachedLimit(this.props.p)) return;
this.setState({status: 'playing'});
this.win(this.props.p, -this.state.investment);
@@ -125,7 +127,7 @@ export class SlotMachine extends Game<IProps, IState> {
setTimeout(this.lock, this.rng.random()*2000+1000);
}
lock() {
lock(): void {
this.setState({
locks: [
Math.floor(this.rng.random()*symbols.length),
@@ -137,10 +139,10 @@ export class SlotMachine extends Game<IProps, IState> {
})
}
checkWinnings() {
checkWinnings(): void {
const t = this.getTable();
const getPaylineData = function(payline: number[][]): string[] {
let data = [];
const data = [];
for(const point of payline) {
data.push(t[point[0]][point[1]]);
}
@@ -174,25 +176,28 @@ export class SlotMachine extends Game<IProps, IState> {
if(this.reachedLimit(this.props.p)) return;
}
unlock() {
unlock(): void {
this.setState({
locks: [-1, -1, -1, -1, -1],
canPlay: false,
})
}
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
updateInvestment(e: React.FormEvent<HTMLInputElement>): void {
let investment: number = parseInt(e.currentTarget.value);
if (isNaN(investment)) {
investment = 1000;
investment = minPlay;
}
if (investment > maxPlay) {
investment = maxPlay;
}
if (investment < minPlay) {
investment = minPlay;
}
this.setState({investment: investment});
}
render() {
render(): React.ReactNode {
const t = this.getTable();
return <>
<pre>
@@ -204,8 +209,8 @@ export class SlotMachine extends Game<IProps, IState> {
| | {symbols[(this.state.index[0]+1)%symbols.length]} | {symbols[(this.state.index[1]+1)%symbols.length]} | {symbols[(this.state.index[2]+1)%symbols.length]} | {symbols[(this.state.index[3]+1)%symbols.length]} | {symbols[(this.state.index[4]+1)%symbols.length]} | |<br />
++<br />
</pre>
<input type="number" className='text-input' onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
<StdButton onClick={this.play} text={"Spin!"} disabled={!this.state.canPlay} />
<input type="number" className="text-input" onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
<StdButton onClick={trusted(this.play)} text={"Spin!"} disabled={!this.state.canPlay} />
<h1>{this.state.status}</h1>
<h2>Pay lines</h2>
<pre>

8
src/Casino/utils.ts Normal file
View File

@@ -0,0 +1,8 @@
import * as React from "react";
export function trusted(f: () => void): (event: React.MouseEvent<HTMLElement, MouseEvent>) => any {
return function(event: React.MouseEvent<HTMLElement, MouseEvent>): any {
if(!event.isTrusted) return;
f();
};
}

View File

@@ -90,7 +90,7 @@ function cinematicTextEnd() {
var mainMenu = document.getElementById("mainmenu-container");
container.appendChild(createElement("br"));
return new Promise (function(resolve, reject) {
return new Promise (function(resolve) {
container.appendChild(createElement("a", {
class:"a-link-button", innerText:"Continue...",
clickListener:()=>{
@@ -99,7 +99,7 @@ function cinematicTextEnd() {
mainMenu.style.visibility = "visible";
cinematicTextFlag = false;
resolve();
}
},
}));
});
}

Some files were not shown because too many files have changed in this diff Show More