Compare commits

..

27 Commits

Author SHA1 Message Date
Olivier Gagnon
c9b5aaa2f7 v0.51.7 2021-05-03 12:17:05 -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
Olivier Gagnon
77cb63e36a When you hotfix you need to build 2021-04-29 13:41:13 -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
hydroflame
925e96345d v0.51.2 (#838)
* infiltration use buttons instead of a links

* minor accessibility patch

* Hospitalization will not cost more than 10% of the players money.

* Adde hospitalization netscript function

* Removed the suggestion that the combat path will lead to Daedalus, it still will. But new players should not be told that this is a viable path to completing a BitNode.

* getMemberInformation now returns everything about the member.

* New netscript function to get the players hacknet server hash capacity

* yesno dialog box will not keep older messages anymore

* v0.51.1

* Casino part 1

* Discord link in options, documentation for getMemberInformation updated, dev menu has more money options, tech vendors now handle max cores or max ram better

* Removed text under Factiosn referencing rejected factions.

* Removed html element forgotten in plain text

* Casino implementation

* v0.51.2
2021-04-09 18:12:31 -04:00
hydroflame
db2bf79e3b v0.51.1 (#835)
* infiltration use buttons instead of a links

* minor accessibility patch

* Hospitalization will not cost more than 10% of the players money.

* Adde hospitalization netscript function

* Removed the suggestion that the combat path will lead to Daedalus, it still will. But new players should not be told that this is a viable path to completing a BitNode.

* getMemberInformation now returns everything about the member.

* New netscript function to get the players hacknet server hash capacity

* yesno dialog box will not keep older messages anymore

* v0.51.1
2021-04-06 03:50:09 -04:00
hydroflame
6f330efc44 Added Disable ASCII art to options (#832)
* hotfix getPlayer missing factions

* Added ability to disable ascii art in options. ASCII art is impossible to deal with for screenreaders.
2021-04-02 20:14:35 -04:00
hydroflame
708c73fa0f hotfix getPlayer missing factions (#831) 2021-04-01 12:55:43 -04:00
hydroflame
c7febd5551 Failed crime no longer pretend you gained money. (#830) 2021-04-01 00:06:00 -04:00
hydroflame
ddbdf66d00 hotfix analyze (#828)
* hotfix analyze
2021-03-31 11:45:55 -04:00
365 changed files with 15318 additions and 9508 deletions

View File

@@ -2,3 +2,7 @@ node_modules/
doc/build/ doc/build/
dist/ dist/
tests/*.bundle.* 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

23
README_contribution.md Normal file
View File

@@ -0,0 +1,23 @@
Deploying a new version
-----------------------
Update the following
- `src/Constants.ts` `Version` and `LatestUpdate`
- `package.json` `version`
- `doc/source/conf.py` `version` and `release`
- `doc/source/changelog.rst`
- post to discord
- post to reddit.com/r/Bitburner
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; background-color: #444;
} }
.character-stat-cell { .character-stat-cell {
text-align: right; text-align: right;
} }
#character-hack-wrapper td, #character-hack-wrapper td,
#character-agi-wrapper td { #character-agi-wrapper td {

View File

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

View File

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

2
css/grid.min.css vendored

File diff suppressed because one or more lines are too long

View File

@@ -184,5 +184,4 @@
#infiltration-buttons .a-link-button { #infiltration-buttons .a-link-button {
display: inline; display: inline;
width: 25%;
} }

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 { &.level-2 {
color: #48D1CC; color: #48d1cc;
} }
&.level-3 { &.level-3 {

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,16 +7,16 @@
.Treant.Treant-loaded .pseudo { visibility: visible; } .Treant.Treant-loaded .pseudo { visibility: visible; }
.Treant > .pseudo { width: 0; height: 0; border: none; padding: 0; } .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 .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 img { border: none; float: left; }
.Treant > .node { .Treant > .node {
cursor: pointer; cursor: pointer;
padding: 4px; padding: 4px;
min-width: 60px; min-width: 60px;
text-align: center; text-align: center;
border: 2px solid #E8E8E3; border: 2px solid #e8e8e3;
border-radius: 2px; border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0,0,0,.5); box-shadow: 1px 1px 1px rgba(0,0,0,0.5);
font-size: 12px; 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([395,0]),o()}({338:function(n,t,o){},340:function(n,t,o){},342:function(n,t,o){},344:function(n,t,o){},346:function(n,t,o){},348:function(n,t,o){},350:function(n,t,o){},352:function(n,t,o){},354:function(n,t,o){},356:function(n,t,o){},358:function(n,t,o){},360:function(n,t,o){},362:function(n,t,o){},364:function(n,t,o){},366:function(n,t,o){},368:function(n,t,o){},370:function(n,t,o){},372:function(n,t,o){},374:function(n,t,o){},376:function(n,t,o){},378:function(n,t,o){},380:function(n,t,o){},382:function(n,t,o){},384:function(n,t,o){},386:function(n,t,o){},388:function(n,t,o){},390:function(n,t,o){},392:function(n,t,o){},395:function(n,t,o){"use strict";o.r(t);o(394),o(392),o(390),o(388),o(386),o(384),o(382),o(380),o(378),o(376),o(374),o(372),o(370),o(368),o(366),o(364),o(362),o(360),o(358),o(356),o(354),o(352),o(350),o(348),o(346),o(344),o(342),o(340),o(338)}}); !function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([840,0]),o()}({779:function(n,t,o){},781:function(n,t,o){},783:function(n,t,o){},785:function(n,t,o){},787:function(n,t,o){},789:function(n,t,o){},791:function(n,t,o){},793:function(n,t,o){},795:function(n,t,o){},797:function(n,t,o){},799:function(n,t,o){},801:function(n,t,o){},803:function(n,t,o){},805:function(n,t,o){},807:function(n,t,o){},809:function(n,t,o){},811:function(n,t,o){},813:function(n,t,o){},815:function(n,t,o){},817:function(n,t,o){},819:function(n,t,o){},821:function(n,t,o){},823:function(n,t,o){},825:function(n,t,o){},827:function(n,t,o){},829:function(n,t,o){},831:function(n,t,o){},833:function(n,t,o){},835:function(n,t,o){},837:function(n,t,o){},840:function(n,t,o){"use strict";o.r(t);o(839),o(837),o(835),o(833),o(831),o(829),o(827),o(825),o(823),o(821),o(819),o(817),o(815),o(813),o(811),o(809),o(807),o(805),o(803),o(801),o(799),o(797),o(795),o(793),o(791),o(789),o(787),o(785),o(783),o(781),o(779)}});
//# sourceMappingURL=engineStyle.bundle.js.map //# sourceMappingURL=engineStyle.bundle.js.map

274
dist/engineStyle.css vendored
View File

@@ -250,13 +250,14 @@ a:visited {
opacity: 0; } } opacity: 0; } }
.status-text { .status-text {
display: inline-block;
position: fixed;
z-index: 2; z-index: 2;
-webkit-animation: status-text 3s 1; } -webkit-animation: status-text 3s 1; }
#status-text-container { #status-text-container {
background-color: transparent; } background-color: transparent;
position: absolute;
top: 0;
left: 50%; }
#status-text { #status-text {
background-color: transparent; background-color: transparent;
@@ -384,8 +385,8 @@ input[type=checkbox] {
outline: none; outline: none;
opacity: 0.7; opacity: 0.7;
height: 10px; height: 10px;
-webkit-transition: .2s; -webkit-transition: 0.2s;
transition: opacity .2s; transition: opacity 0.2s;
margin: 3px; } margin: 3px; }
.optionRange::-webkit-slider-thumb { .optionRange::-webkit-slider-thumb {
@@ -1026,7 +1027,7 @@ button {
*/ */
#codemirror-form-wrapper { #codemirror-form-wrapper {
height: 80%; height: 80%;
margin: 10px 0px 0px 6px; } margin: 10px 0 0 6px; }
.CodeMirror { .CodeMirror {
height: 100%; height: 100%;
@@ -1040,10 +1041,10 @@ button {
* Highlight matches * Highlight matches
*/ */
.cm-matchhighlight { .cm-matchhighlight {
background-color: #8F908A; } background-color: #8f908a; }
.CodeMirror-selection-highlight-scrollbar { .CodeMirror-selection-highlight-scrollbar {
background-color: #8F908A; } background-color: #8f908a; }
/** /**
* Show Invisibles * Show Invisibles
@@ -1051,7 +1052,7 @@ button {
.cm-whitespace::before { .cm-whitespace::before {
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
color: #404F7D; } color: #404f7d; }
/** /**
* Vim command display * Vim command display
@@ -1374,8 +1375,7 @@ button {
margin-top: 20px; } margin-top: 20px; }
#infiltration-buttons .a-link-button { #infiltration-buttons .a-link-button {
display: inline; display: inline; }
width: 25%; }
/** /**
* Styling for the Augmentations UI. This is the page that displays all of the * Styling for the Augmentations UI. This is the page that displays all of the
@@ -1415,7 +1415,7 @@ button {
color: yellow; } color: yellow; }
.bitnode.level-2 { .bitnode.level-2 {
color: #48D1CC; } color: #48d1cc; }
.bitnode.level-3 { .bitnode.level-3 {
color: blue; } color: blue; }
@@ -2417,7 +2417,7 @@ button {
.sleeve-panel { .sleeve-panel {
display: inline-block; display: inline-block;
margin: 0px; margin: 0;
padding: 2px; } padding: 2px; }
.sleeve-panel select { .sleeve-panel select {
display: block; } display: block; }
@@ -2436,7 +2436,7 @@ button {
.resleeve-panel { .resleeve-panel {
display: inline-block; display: inline-block;
margin: 0px; margin: 0;
padding: 2px; } padding: 2px; }
.resleeve-aug-selector { .resleeve-aug-selector {
@@ -2478,7 +2478,7 @@ button {
cursor: pointer; } cursor: pointer; }
.Treant .collapsed .collapse-switch { .Treant .collapsed .collapse-switch {
background-color: #868DEE; } background-color: #868dee; }
.Treant > .node img { .Treant > .node img {
border: none; border: none;
@@ -2489,7 +2489,7 @@ button {
padding: 4px; padding: 4px;
min-width: 60px; min-width: 60px;
text-align: center; text-align: center;
border: 2px solid #E8E8E3; border: 2px solid #e8e8e3;
border-radius: 2px; border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
font-size: 12px; } font-size: 12px; }
@@ -4266,34 +4266,34 @@ html {
margin-left: 0 !important; } margin-left: 0 !important; }
.m-1 { .m-1 {
margin: .25rem !important; } margin: 0.25rem !important; }
.mt-1, .my-1 { .mt-1, .my-1 {
margin-top: .25rem !important; } margin-top: 0.25rem !important; }
.mr-1, .mx-1 { .mr-1, .mx-1 {
margin-right: .25rem !important; } margin-right: 0.25rem !important; }
.mb-1, .my-1 { .mb-1, .my-1 {
margin-bottom: .25rem !important; } margin-bottom: 0.25rem !important; }
.ml-1, .mx-1 { .ml-1, .mx-1 {
margin-left: .25rem !important; } margin-left: 0.25rem !important; }
.m-2 { .m-2 {
margin: .5rem !important; } margin: 0.5rem !important; }
.mt-2, .my-2 { .mt-2, .my-2 {
margin-top: .5rem !important; } margin-top: 0.5rem !important; }
.mr-2, .mx-2 { .mr-2, .mx-2 {
margin-right: .5rem !important; } margin-right: 0.5rem !important; }
.mb-2, .my-2 { .mb-2, .my-2 {
margin-bottom: .5rem !important; } margin-bottom: 0.5rem !important; }
.ml-2, .mx-2 { .ml-2, .mx-2 {
margin-left: .5rem !important; } margin-left: 0.5rem !important; }
.m-3 { .m-3 {
margin: 1rem !important; } margin: 1rem !important; }
@@ -4356,34 +4356,34 @@ html {
padding-left: 0 !important; } padding-left: 0 !important; }
.p-1 { .p-1 {
padding: .25rem !important; } padding: 0.25rem !important; }
.pt-1, .py-1 { .pt-1, .py-1 {
padding-top: .25rem !important; } padding-top: 0.25rem !important; }
.pr-1, .px-1 { .pr-1, .px-1 {
padding-right: .25rem !important; } padding-right: 0.25rem !important; }
.pb-1, .py-1 { .pb-1, .py-1 {
padding-bottom: .25rem !important; } padding-bottom: 0.25rem !important; }
.pl-1, .px-1 { .pl-1, .px-1 {
padding-left: .25rem !important; } padding-left: 0.25rem !important; }
.p-2 { .p-2 {
padding: .5rem !important; } padding: 0.5rem !important; }
.pt-2, .py-2 { .pt-2, .py-2 {
padding-top: .5rem !important; } padding-top: 0.5rem !important; }
.pr-2, .px-2 { .pr-2, .px-2 {
padding-right: .5rem !important; } padding-right: 0.5rem !important; }
.pb-2, .py-2 { .pb-2, .py-2 {
padding-bottom: .5rem !important; } padding-bottom: 0.5rem !important; }
.pl-2, .px-2 { .pl-2, .px-2 {
padding-left: .5rem !important; } padding-left: 0.5rem !important; }
.p-3 { .p-3 {
padding: 1rem !important; } padding: 1rem !important; }
@@ -4457,25 +4457,25 @@ html {
.ml-sm-0, .mx-sm-0 { .ml-sm-0, .mx-sm-0 {
margin-left: 0 !important; } margin-left: 0 !important; }
.m-sm-1 { .m-sm-1 {
margin: .25rem !important; } margin: 0.25rem !important; }
.mt-sm-1, .my-sm-1 { .mt-sm-1, .my-sm-1 {
margin-top: .25rem !important; } margin-top: 0.25rem !important; }
.mr-sm-1, .mx-sm-1 { .mr-sm-1, .mx-sm-1 {
margin-right: .25rem !important; } margin-right: 0.25rem !important; }
.mb-sm-1, .my-sm-1 { .mb-sm-1, .my-sm-1 {
margin-bottom: .25rem !important; } margin-bottom: 0.25rem !important; }
.ml-sm-1, .mx-sm-1 { .ml-sm-1, .mx-sm-1 {
margin-left: .25rem !important; } margin-left: 0.25rem !important; }
.m-sm-2 { .m-sm-2 {
margin: .5rem !important; } margin: 0.5rem !important; }
.mt-sm-2, .my-sm-2 { .mt-sm-2, .my-sm-2 {
margin-top: .5rem !important; } margin-top: 0.5rem !important; }
.mr-sm-2, .mx-sm-2 { .mr-sm-2, .mx-sm-2 {
margin-right: .5rem !important; } margin-right: 0.5rem !important; }
.mb-sm-2, .my-sm-2 { .mb-sm-2, .my-sm-2 {
margin-bottom: .5rem !important; } margin-bottom: 0.5rem !important; }
.ml-sm-2, .mx-sm-2 { .ml-sm-2, .mx-sm-2 {
margin-left: .5rem !important; } margin-left: 0.5rem !important; }
.m-sm-3 { .m-sm-3 {
margin: 1rem !important; } margin: 1rem !important; }
.mt-sm-3, .my-sm-3 { .mt-sm-3, .my-sm-3 {
@@ -4517,25 +4517,25 @@ html {
.pl-sm-0, .px-sm-0 { .pl-sm-0, .px-sm-0 {
padding-left: 0 !important; } padding-left: 0 !important; }
.p-sm-1 { .p-sm-1 {
padding: .25rem !important; } padding: 0.25rem !important; }
.pt-sm-1, .py-sm-1 { .pt-sm-1, .py-sm-1 {
padding-top: .25rem !important; } padding-top: 0.25rem !important; }
.pr-sm-1, .px-sm-1 { .pr-sm-1, .px-sm-1 {
padding-right: .25rem !important; } padding-right: 0.25rem !important; }
.pb-sm-1, .py-sm-1 { .pb-sm-1, .py-sm-1 {
padding-bottom: .25rem !important; } padding-bottom: 0.25rem !important; }
.pl-sm-1, .px-sm-1 { .pl-sm-1, .px-sm-1 {
padding-left: .25rem !important; } padding-left: 0.25rem !important; }
.p-sm-2 { .p-sm-2 {
padding: .5rem !important; } padding: 0.5rem !important; }
.pt-sm-2, .py-sm-2 { .pt-sm-2, .py-sm-2 {
padding-top: .5rem !important; } padding-top: 0.5rem !important; }
.pr-sm-2, .px-sm-2 { .pr-sm-2, .px-sm-2 {
padding-right: .5rem !important; } padding-right: 0.5rem !important; }
.pb-sm-2, .py-sm-2 { .pb-sm-2, .py-sm-2 {
padding-bottom: .5rem !important; } padding-bottom: 0.5rem !important; }
.pl-sm-2, .px-sm-2 { .pl-sm-2, .px-sm-2 {
padding-left: .5rem !important; } padding-left: 0.5rem !important; }
.p-sm-3 { .p-sm-3 {
padding: 1rem !important; } padding: 1rem !important; }
.pt-sm-3, .py-sm-3 { .pt-sm-3, .py-sm-3 {
@@ -4589,25 +4589,25 @@ html {
.ml-md-0, .mx-md-0 { .ml-md-0, .mx-md-0 {
margin-left: 0 !important; } margin-left: 0 !important; }
.m-md-1 { .m-md-1 {
margin: .25rem !important; } margin: 0.25rem !important; }
.mt-md-1, .my-md-1 { .mt-md-1, .my-md-1 {
margin-top: .25rem !important; } margin-top: 0.25rem !important; }
.mr-md-1, .mx-md-1 { .mr-md-1, .mx-md-1 {
margin-right: .25rem !important; } margin-right: 0.25rem !important; }
.mb-md-1, .my-md-1 { .mb-md-1, .my-md-1 {
margin-bottom: .25rem !important; } margin-bottom: 0.25rem !important; }
.ml-md-1, .mx-md-1 { .ml-md-1, .mx-md-1 {
margin-left: .25rem !important; } margin-left: 0.25rem !important; }
.m-md-2 { .m-md-2 {
margin: .5rem !important; } margin: 0.5rem !important; }
.mt-md-2, .my-md-2 { .mt-md-2, .my-md-2 {
margin-top: .5rem !important; } margin-top: 0.5rem !important; }
.mr-md-2, .mx-md-2 { .mr-md-2, .mx-md-2 {
margin-right: .5rem !important; } margin-right: 0.5rem !important; }
.mb-md-2, .my-md-2 { .mb-md-2, .my-md-2 {
margin-bottom: .5rem !important; } margin-bottom: 0.5rem !important; }
.ml-md-2, .mx-md-2 { .ml-md-2, .mx-md-2 {
margin-left: .5rem !important; } margin-left: 0.5rem !important; }
.m-md-3 { .m-md-3 {
margin: 1rem !important; } margin: 1rem !important; }
.mt-md-3, .my-md-3 { .mt-md-3, .my-md-3 {
@@ -4649,25 +4649,25 @@ html {
.pl-md-0, .px-md-0 { .pl-md-0, .px-md-0 {
padding-left: 0 !important; } padding-left: 0 !important; }
.p-md-1 { .p-md-1 {
padding: .25rem !important; } padding: 0.25rem !important; }
.pt-md-1, .py-md-1 { .pt-md-1, .py-md-1 {
padding-top: .25rem !important; } padding-top: 0.25rem !important; }
.pr-md-1, .px-md-1 { .pr-md-1, .px-md-1 {
padding-right: .25rem !important; } padding-right: 0.25rem !important; }
.pb-md-1, .py-md-1 { .pb-md-1, .py-md-1 {
padding-bottom: .25rem !important; } padding-bottom: 0.25rem !important; }
.pl-md-1, .px-md-1 { .pl-md-1, .px-md-1 {
padding-left: .25rem !important; } padding-left: 0.25rem !important; }
.p-md-2 { .p-md-2 {
padding: .5rem !important; } padding: 0.5rem !important; }
.pt-md-2, .py-md-2 { .pt-md-2, .py-md-2 {
padding-top: .5rem !important; } padding-top: 0.5rem !important; }
.pr-md-2, .px-md-2 { .pr-md-2, .px-md-2 {
padding-right: .5rem !important; } padding-right: 0.5rem !important; }
.pb-md-2, .py-md-2 { .pb-md-2, .py-md-2 {
padding-bottom: .5rem !important; } padding-bottom: 0.5rem !important; }
.pl-md-2, .px-md-2 { .pl-md-2, .px-md-2 {
padding-left: .5rem !important; } padding-left: 0.5rem !important; }
.p-md-3 { .p-md-3 {
padding: 1rem !important; } padding: 1rem !important; }
.pt-md-3, .py-md-3 { .pt-md-3, .py-md-3 {
@@ -4721,25 +4721,25 @@ html {
.ml-lg-0, .mx-lg-0 { .ml-lg-0, .mx-lg-0 {
margin-left: 0 !important; } margin-left: 0 !important; }
.m-lg-1 { .m-lg-1 {
margin: .25rem !important; } margin: 0.25rem !important; }
.mt-lg-1, .my-lg-1 { .mt-lg-1, .my-lg-1 {
margin-top: .25rem !important; } margin-top: 0.25rem !important; }
.mr-lg-1, .mx-lg-1 { .mr-lg-1, .mx-lg-1 {
margin-right: .25rem !important; } margin-right: 0.25rem !important; }
.mb-lg-1, .my-lg-1 { .mb-lg-1, .my-lg-1 {
margin-bottom: .25rem !important; } margin-bottom: 0.25rem !important; }
.ml-lg-1, .mx-lg-1 { .ml-lg-1, .mx-lg-1 {
margin-left: .25rem !important; } margin-left: 0.25rem !important; }
.m-lg-2 { .m-lg-2 {
margin: .5rem !important; } margin: 0.5rem !important; }
.mt-lg-2, .my-lg-2 { .mt-lg-2, .my-lg-2 {
margin-top: .5rem !important; } margin-top: 0.5rem !important; }
.mr-lg-2, .mx-lg-2 { .mr-lg-2, .mx-lg-2 {
margin-right: .5rem !important; } margin-right: 0.5rem !important; }
.mb-lg-2, .my-lg-2 { .mb-lg-2, .my-lg-2 {
margin-bottom: .5rem !important; } margin-bottom: 0.5rem !important; }
.ml-lg-2, .mx-lg-2 { .ml-lg-2, .mx-lg-2 {
margin-left: .5rem !important; } margin-left: 0.5rem !important; }
.m-lg-3 { .m-lg-3 {
margin: 1rem !important; } margin: 1rem !important; }
.mt-lg-3, .my-lg-3 { .mt-lg-3, .my-lg-3 {
@@ -4781,25 +4781,25 @@ html {
.pl-lg-0, .px-lg-0 { .pl-lg-0, .px-lg-0 {
padding-left: 0 !important; } padding-left: 0 !important; }
.p-lg-1 { .p-lg-1 {
padding: .25rem !important; } padding: 0.25rem !important; }
.pt-lg-1, .py-lg-1 { .pt-lg-1, .py-lg-1 {
padding-top: .25rem !important; } padding-top: 0.25rem !important; }
.pr-lg-1, .px-lg-1 { .pr-lg-1, .px-lg-1 {
padding-right: .25rem !important; } padding-right: 0.25rem !important; }
.pb-lg-1, .py-lg-1 { .pb-lg-1, .py-lg-1 {
padding-bottom: .25rem !important; } padding-bottom: 0.25rem !important; }
.pl-lg-1, .px-lg-1 { .pl-lg-1, .px-lg-1 {
padding-left: .25rem !important; } padding-left: 0.25rem !important; }
.p-lg-2 { .p-lg-2 {
padding: .5rem !important; } padding: 0.5rem !important; }
.pt-lg-2, .py-lg-2 { .pt-lg-2, .py-lg-2 {
padding-top: .5rem !important; } padding-top: 0.5rem !important; }
.pr-lg-2, .px-lg-2 { .pr-lg-2, .px-lg-2 {
padding-right: .5rem !important; } padding-right: 0.5rem !important; }
.pb-lg-2, .py-lg-2 { .pb-lg-2, .py-lg-2 {
padding-bottom: .5rem !important; } padding-bottom: 0.5rem !important; }
.pl-lg-2, .px-lg-2 { .pl-lg-2, .px-lg-2 {
padding-left: .5rem !important; } padding-left: 0.5rem !important; }
.p-lg-3 { .p-lg-3 {
padding: 1rem !important; } padding: 1rem !important; }
.pt-lg-3, .py-lg-3 { .pt-lg-3, .py-lg-3 {
@@ -4853,25 +4853,25 @@ html {
.ml-xl-0, .mx-xl-0 { .ml-xl-0, .mx-xl-0 {
margin-left: 0 !important; } margin-left: 0 !important; }
.m-xl-1 { .m-xl-1 {
margin: .25rem !important; } margin: 0.25rem !important; }
.mt-xl-1, .my-xl-1 { .mt-xl-1, .my-xl-1 {
margin-top: .25rem !important; } margin-top: 0.25rem !important; }
.mr-xl-1, .mx-xl-1 { .mr-xl-1, .mx-xl-1 {
margin-right: .25rem !important; } margin-right: 0.25rem !important; }
.mb-xl-1, .my-xl-1 { .mb-xl-1, .my-xl-1 {
margin-bottom: .25rem !important; } margin-bottom: 0.25rem !important; }
.ml-xl-1, .mx-xl-1 { .ml-xl-1, .mx-xl-1 {
margin-left: .25rem !important; } margin-left: 0.25rem !important; }
.m-xl-2 { .m-xl-2 {
margin: .5rem !important; } margin: 0.5rem !important; }
.mt-xl-2, .my-xl-2 { .mt-xl-2, .my-xl-2 {
margin-top: .5rem !important; } margin-top: 0.5rem !important; }
.mr-xl-2, .mx-xl-2 { .mr-xl-2, .mx-xl-2 {
margin-right: .5rem !important; } margin-right: 0.5rem !important; }
.mb-xl-2, .my-xl-2 { .mb-xl-2, .my-xl-2 {
margin-bottom: .5rem !important; } margin-bottom: 0.5rem !important; }
.ml-xl-2, .mx-xl-2 { .ml-xl-2, .mx-xl-2 {
margin-left: .5rem !important; } margin-left: 0.5rem !important; }
.m-xl-3 { .m-xl-3 {
margin: 1rem !important; } margin: 1rem !important; }
.mt-xl-3, .my-xl-3 { .mt-xl-3, .my-xl-3 {
@@ -4913,25 +4913,25 @@ html {
.pl-xl-0, .px-xl-0 { .pl-xl-0, .px-xl-0 {
padding-left: 0 !important; } padding-left: 0 !important; }
.p-xl-1 { .p-xl-1 {
padding: .25rem !important; } padding: 0.25rem !important; }
.pt-xl-1, .py-xl-1 { .pt-xl-1, .py-xl-1 {
padding-top: .25rem !important; } padding-top: 0.25rem !important; }
.pr-xl-1, .px-xl-1 { .pr-xl-1, .px-xl-1 {
padding-right: .25rem !important; } padding-right: 0.25rem !important; }
.pb-xl-1, .py-xl-1 { .pb-xl-1, .py-xl-1 {
padding-bottom: .25rem !important; } padding-bottom: 0.25rem !important; }
.pl-xl-1, .px-xl-1 { .pl-xl-1, .px-xl-1 {
padding-left: .25rem !important; } padding-left: 0.25rem !important; }
.p-xl-2 { .p-xl-2 {
padding: .5rem !important; } padding: 0.5rem !important; }
.pt-xl-2, .py-xl-2 { .pt-xl-2, .py-xl-2 {
padding-top: .5rem !important; } padding-top: 0.5rem !important; }
.pr-xl-2, .px-xl-2 { .pr-xl-2, .px-xl-2 {
padding-right: .5rem !important; } padding-right: 0.5rem !important; }
.pb-xl-2, .py-xl-2 { .pb-xl-2, .py-xl-2 {
padding-bottom: .5rem !important; } padding-bottom: 0.5rem !important; }
.pl-xl-2, .px-xl-2 { .pl-xl-2, .px-xl-2 {
padding-left: .5rem !important; } padding-left: 0.5rem !important; }
.p-xl-3 { .p-xl-3 {
padding: 1rem !important; } padding: 1rem !important; }
.pt-xl-3, .py-xl-3 { .pt-xl-3, .py-xl-3 {
@@ -4980,14 +4980,14 @@ html {
visibility: hidden !important; } visibility: hidden !important; }
.add-exp-button { .add-exp-button {
margin-right: 0px; } margin-right: 0; }
.remove-exp-button { .remove-exp-button {
margin-left: 0px; } margin-left: 0; }
.exp-input { .exp-input {
margin-right: 0px; margin-right: 0;
margin-left: 0px; margin-left: 0;
margin-top: 5px; margin-top: 5px;
margin-bottom: 5px; margin-bottom: 5px;
padding: 2px 5px; } padding: 2px 5px; }
@@ -4998,14 +4998,40 @@ html {
vertical-align: middle; } vertical-align: middle; }
.touch-right { .touch-right {
margin-right: 0px; } margin-right: 0; }
.touch-left { .touch-left {
margin-left: 0px; } margin-left: 0; }
.touch-sides { .touch-sides {
margin-left: 0px; margin-left: 0;
margin-right: 0px; } 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*/ /*# sourceMappingURL=engineStyle.css.map*/

78
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -11,7 +11,7 @@ user's physical and mental faculties.
Augmentations provide persistent upgrades in the form of multipliers. Augmentations provide persistent upgrades in the form of multipliers.
These multipliers apply to a wide variety of things such as stats, These multipliers apply to a wide variety of things such as stats,
experience gain, and hacking, just to name a few. Your multipliers 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 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 | | Early Game | Faction Name | Requirements | Joining this Faction prevents |
| Factions | | | you from joining: | | Factions | | | you from joining: |
+ +----------------+-----------------------------------------+-------------------------------+ + +----------------+-----------------------------------------+-------------------------------+
| | CyberSec | * Hack CSEC Manually | | | | CyberSec | * Install a backdoor on the CSEC server | |
+ +----------------+-----------------------------------------+-------------------------------+ + +----------------+-----------------------------------------+-------------------------------+
| | Tian Di Hui | * $1m | | | | Tian Di Hui | * $1m | |
| | | * Hacking Level 50 | | | | | * Hacking Level 50 | |
@@ -74,13 +74,16 @@ List of Factions and their Requirements
| | | | * New Tokyo | | | | | * New Tokyo |
| | | | * Ishima | | | | | * Ishima |
+---------------------+----------------+-----------------------------------------+-------------------------------+ +---------------------+----------------+-----------------------------------------+-------------------------------+
| Hacking | NiteSec | * Hack avmnite-02h manually | | | Hacking | NiteSec | * Install a backdoor on the avmnite-02h | |
| Groups | | * Home Computer RAM of at least 32GB | | | 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 | | | | | * 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 | | | | | * Home Computer RAM of at least 128GB | |
+---------------------+----------------+-----------------------------------------+-------------------------------+ +---------------------+----------------+-----------------------------------------+-------------------------------+
| Megacorporations | ECorp | * Have 200k reputation with | | | Megacorporations | ECorp | * Have 200k reputation with | |
@@ -112,7 +115,8 @@ List of Factions and their Requirements
+ +----------------+-----------------------------------------+-------------------------------+ + +----------------+-----------------------------------------+-------------------------------+
| | Fulcrum Secret | * Have 250k reputation with | | | | Fulcrum Secret | * Have 250k reputation with | |
| | Technologies | the Corporation | | | | Technologies | the Corporation | |
| | | * Hack fulcrumassets manually | | | | | * Install a backdoor on the | |
| | | fulcrumassets server | |
+---------------------+----------------+-----------------------------------------+-------------------------------+ +---------------------+----------------+-----------------------------------------+-------------------------------+
| Criminal | Slum Snakes | * All Combat Stats of 30 | | | Criminal | Slum Snakes | * All Combat Stats of 30 | |
| Organizations | | * -9 Karma | | | 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 such as an estimated chance to successfully hack, an estimate of how much money is
available on the server, etc. 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 buy
^^^ ^^^

View File

@@ -3,6 +3,258 @@
Changelog Changelog
========= =========
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)
----------------------------------------------
**New location: The Iker Molina Casino**
* A casino opened in Aevum. However the house is rumored to cheat. If only
we could give them a taste of their own medicine.
**Misc.**
* Link to discord added under options
* 'getMemberInformation' doc updated, oops
* tech vendor now handle max ram and cores.
v0.51.1 - 2021-04-06 Bugfixes because the author of the last patch sucks (it's hydroflame)
------------------------------------------------------------------------------------------
**Netscript**
* 'getPlayer' returns players faction and tor
* 'hospitalization' is a new singularity function.
* 'gang.getMemberInformation' now returns more information.
* 'hacknet.hashCapacity' is a new hacknet function that returns the maximum hash capacity.
**Hospitalization**
* Now only cost at most 10% of your money.
**Bugfix**
* confirmation dialog box no longer use previous text
**Accessibility**
* The game is a little easier to handle for screen readers (yes, there's an
absolute legend playing this game with a screen reader)
* Infiltration use buttons instead of a-links
* New option to disable ASCII art. This will make the metro map and world
map display as a list of buttons.
**Misc.**
* 'fl1ght.exe' will no longer suggest the combat path. Related faction
requirements unchanged.
v0.51.0 - 2021-03-31 Formulas (hydroflame) v0.51.0 - 2021-03-31 Formulas (hydroflame)
------------------------------------------ ------------------------------------------

View File

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

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. 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 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 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 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 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 BruteSSH.exe
$ run NUKE.exe $ run NUKE.exe
$ hack $ backdoor
Keep hacking the server until you are successful. After you successfully hack it, you should After you successfully install the backdoor, you should receive a faction
receive a faction invitation from |CyberSec| shortly afterwards. Accept it. If you accidentally invitation from |CyberSec| shortly afterwards. Accept it. If you accidentally
reject the invitation, that's okay. Just go to the :code:`Factions` tab 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 (|Keyboard shortcut| Alt + f) and you should see an option that lets you
accept the invitation. accept the invitation.

View File

@@ -278,6 +278,7 @@ Description
hashes, which can be spent on a variety of different upgrades. hashes, which can be spent on a variety of different upgrades.
In this BitNode: In this BitNode:
* Your stats are significantly decreased * Your stats are significantly decreased
* You cannnot purchase additional servers * You cannnot purchase additional servers
* Hacking is significantly less profitable * Hacking is significantly less profitable
@@ -292,7 +293,7 @@ Source-File
* Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode * 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 (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 Difficulty
Hard Hard
@@ -312,6 +313,7 @@ Description
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously 2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
In this BitNode: In this BitNode:
* Your stats are significantly decreased * Your stats are significantly decreased
* All methods of gaining money are half as profitable (except Stock Market) * All methods of gaining money are half as profitable (except Stock Market)
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit * Purchased servers are more expensive, have less max RAM, and a lower maximum limit

View File

@@ -27,7 +27,7 @@ getServer() Netscript Function
sshPortOpen sshPortOpen
baseDifficulty baseDifficulty
hackDifficulty hackDifficulty
manuallyHacked backdoorInstalled
minDifficulty minDifficulty
moneyAvailable moneyAvailable
moneyMax 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

@@ -1,11 +1,11 @@
isRunning() Netscript Function isRunning() Netscript Function
============================== ==============================
.. js:function:: isRunning(filename, hostname, [args...]) .. js:function:: isRunning(filename[, hostname=current hostname[, args...]])
:RAM cost: 0.1 GB :RAM cost: 0.1 GB
:param string filename: Filename of script to check. case-sensitive. :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 :param args...: Arguments to specify/identify which scripts to search for
:returns: ``true`` if that script with those args is running on that server. :returns: ``true`` if that script with those args is running on that server.
@@ -38,3 +38,17 @@ isRunning() Netscript Function
.. code-block:: javascript .. code-block:: javascript
isRunning("foo.script", "joesguns", 1, 5, "test"); 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 print() Netscript Function
=========================== ===========================
.. js:function:: print(x) .. js:function:: print(args...)
:RAM cost: 0 GB :RAM cost: 0 GB
:param x: Value to be printed. :param args: Values to be printed.
Prints a value or a variable to the script's logs. Prints any number of values to the script's logs.
Example: Example:
.. code-block:: javascript .. code-block:: javascript
print("Hello world!"); // Prints "Hello world!" in the logs. print("Hello world!"); // Prints "Hello world!" in the logs.
print({a:5}); // Prints '{"a":5}' in the logs.

View File

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

View File

@@ -1,7 +1,7 @@
tail() Netscript Function tail() Netscript Function
================================== ==================================
.. js:function:: tail([fn[, hostname=current hostname[, [...args]]]) .. js:function:: tail([fn[, hostname=current hostname[, ...args]])
:RAM cost: 0 GB :RAM cost: 0 GB
:param string fn: Optional. Filename of script to get logs from. :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"] // Open logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"]
tail("foo.script", "foodnstuff", 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 tprint() Netscript Function
=========================== ===========================
.. js:function:: tprint(x) .. js:function:: tprint(args...)
:RAM cost: 0 GB :RAM cost: 0 GB
:param x: Value to be printed :param args: Values to be printed
Prints a value or a variable to the Terminal. Prints any number of values to the Terminal.
Example: Example:
.. code-block:: javascript .. code-block:: javascript
tprint("Hello world!"); // Prints "Hello world!" to the terminal. tprint("Hello world!"); // Prints "Hello world!" to the terminal.
tprint({a:5}); // Prints '{"a":5}' to the terminal.

View File

@@ -5,7 +5,7 @@ calculateExp() Netscript Function
:RAM cost: 0 GB :RAM cost: 0 GB
:param number skillLevel: ``skillLevel`` to convert to exp. :param number skillLevel: ``skillLevel`` to convert to exp.
:param number mult: Assume a specific skill multipler. :param number mult: Assume a specific skill multipler (not exp multiplier).
:returns: number of exp required to reach given ``skillLevel`` with that multiplier. :returns: number of exp required to reach given ``skillLevel`` with that multiplier.
You must have Source-File 5-1 in order to use this function. You must have Source-File 5-1 in order to use this function.

View File

@@ -5,7 +5,7 @@ calculateSkill() Netscript Function
:RAM cost: 0 GB :RAM cost: 0 GB
:param number exp: ``exp`` to convert to skillLevel. :param number exp: ``exp`` to convert to skillLevel.
:param number mult: Assume a specific skill multipler. :param number mult: Assume a specific skill multipler (not exp multiplier).
:returns: skillLevel that ``exp`` would reach with that multiplier. :returns: skillLevel that ``exp`` would reach with that multiplier.
You must have Source-File 5-1 in order to use this function. You must have Source-File 5-1 in order to use this function.

View File

@@ -10,27 +10,35 @@ getMemberInformation() Netscript Function
The object has the following structure:: The object has the following structure::
{ {
agility: Agility stat name: Name of this member.
agilityEquipMult: Agility multiplier from equipment. Decimal form task: Name of currently assigned task.
agilityAscensionMult: Agility multiplier from ascension. Decimal form earnedRespect: Total amount of respect earned by this member.
augmentations: Array of names of all owned Augmentations hack: Hacking stat
charisma: Charisma stat str: Strength stat
charismaEquipMult: Charisma multiplier from equipment. Decimal form def: Defense stat
charismaAscensionMult: Charisma multiplier from ascension. Decimal form dex: Dexterity stat
defense: Defense stat agi: Agility stat
defenseEquipMult: Defense multiplier from equipment. Decimal form cha: Charisma stat
defenseAscensionMult: Defense multiplier from ascension. Decimal form hack_exp: Hacking experience
dexterity: Dexterity stat str_exp: Strength experience
dexterityEquipMult: Dexterity multiplier from equipment. Decimal form def_exp: Defense experience
dexterityAscensionMult: Dexterity multiplier from ascension. Decimal form dex_exp: Dexterity experience
equipment: Array of names of all owned Non-Augmentation Equipment agi_exp: Agility experience
hacking: Hacking stat cha_exp: Charisma experience
hackingEquipMult: Hacking multiplier from equipment. Decimal form hack_mult: Hacking multiplier from equipment. Decimal form
hackingAscensionMult: Hacking multiplier from ascension. Decimal form str_mult: Strength multiplier from equipment. Decimal form
strength: Strength stat def_mult: Defense multiplier from equipment. Decimal form
strengthEquipMult: Strength multiplier from equipment. Decimal form dex_mult: Dexterity multiplier from equipment. Decimal form
strengthAscensionMult: Strength multiplier from ascension. Decimal form agi_mult: Agility multiplier from equipment. Decimal form
task: Name of currently assigned task cha_mult: Charisma multiplier from equipment. Decimal form
hack_asc_mult: Hacking multiplier from ascension. Decimal form
str_asc_mult: Strength multiplier from ascension. Decimal form
def_asc_mult: Defense multiplier from ascension. Decimal form
dex_asc_mult: Dexterity multiplier from ascension. Decimal form
agi_asc_mult: Agility multiplier from ascension. Decimal form
cha_asc_mult: Charisma multiplier from ascension. Decimal form
upgrades: Array of names of all owned Non-Augmentation Equipment
augmentations: Array of names of all owned Augmentations
} }
Get stat and equipment-related information about a Gang Member Get stat and equipment-related information about a Gang Member

View File

@@ -0,0 +1,12 @@
hashCapacity() Netscript Function
=================================
.. warning:: This page contains spoilers for the game
.. js:function:: hashCapacity()
:RAM cost: 0 GB
:returns: The players maximum hash capacity.
.. note:: This function is only applicable for Hacknet Servers (the upgraded version of
a Hacknet Node).

View File

@@ -5,13 +5,13 @@ Netscript Bladeburner API
Netscript provides the following API for interacting with the game's Bladeburner mechanic. 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 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 .. warning:: This page contains spoilers for the game
The Bladeburner API is unlocked in BitNode-7. If you are in BitNode-7, you will 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 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** **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() { 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 //it overrides Bladeburner stuff
if (!this.hasSimulacrum() && this.ns.isBusy()) { if (!this.hasSimulacrum() && this.ns.isBusy()) {
this.ns.print("Idling bc player is busy with some other action"); this.ns.print("Idling bc player is busy with some other action");

View File

@@ -75,6 +75,7 @@ This includes information such as function signatures, what they do, and their r
scriptKill() <basicfunctions/scriptKill> scriptKill() <basicfunctions/scriptKill>
getScriptName() <basicfunctions/getScriptName> getScriptName() <basicfunctions/getScriptName>
getScriptRam() <basicfunctions/getScriptRam> getScriptRam() <basicfunctions/getScriptRam>
getRunningScript() <basicfunctions/getRunningScript>
getHackTime() <basicfunctions/getHackTime> getHackTime() <basicfunctions/getHackTime>
getGrowTime() <basicfunctions/getGrowTime> getGrowTime() <basicfunctions/getGrowTime>
getWeakenTime() <basicfunctions/getWeakenTime> getWeakenTime() <basicfunctions/getWeakenTime>
@@ -88,3 +89,4 @@ This includes information such as function signatures, what they do, and their r
prompt() <basicfunctions/prompt> prompt() <basicfunctions/prompt>
wget() <basicfunctions/wget> wget() <basicfunctions/wget>
getFavorToDonate() <basicfunctions/getFavorToDonate> getFavorToDonate() <basicfunctions/getFavorToDonate>
flags() <basicfunctions/flags>

View File

@@ -46,6 +46,7 @@ In :ref:`netscriptjs`::
upgradeCache() <hacknetnodeapi/upgradeCache> upgradeCache() <hacknetnodeapi/upgradeCache>
getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost> getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost>
numHashes() <hacknetnodeapi/numHashes> numHashes() <hacknetnodeapi/numHashes>
hashCapacity() <hacknetnodeapi/hashCapacity>
hashCost() <hacknetnodeapi/hashCost> hashCost() <hacknetnodeapi/hashCost>
spendHashes() <hacknetnodeapi/spendHashes> spendHashes() <hacknetnodeapi/spendHashes>
getHashUpgradeLevel() <hacknetnodeapi/getHashUpgradeLevel> getHashUpgradeLevel() <hacknetnodeapi/getHashUpgradeLevel>

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 * Supports (almost) all features of modern JavaScript
* Extremely fast - code is executed as an Async Function * Extremely fast - code is executed as an Async Function
* Currently only works with Google Chrome browser * Works on most modern browsers.
* Each script becomes a module and therefore all instances of that script can easily * Each script becomes a module and therefore all instances of that script can easily
share data between each other (essentially global/static variables) share data between each other (essentially global/static variables)

View File

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

View File

@@ -93,6 +93,8 @@ getPlayer() Netscript Function
playtimeSinceLastAug playtimeSinceLastAug
playtimeSinceLastBitnode playtimeSinceLastBitnode
jobs jobs
factions
tor
} }
Example:: Example::

View File

@@ -0,0 +1,11 @@
hospitalize() Netscript Function
===================================
.. js:function:: hospitalize()
:RAM cost: 1 GB
:returns: The cost of your visit to the hospital.
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
Hospitalize yourself. Recovering all lost hp.

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. 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 function will perform a manual hack on the server you are currently connected to.
This is typically required to join factions.
Examples: Examples:
.. code-block:: javascript .. code-block:: javascript
connect("CSEC"); connect("foodnstuff");
manualHack(); manualHack();
.. warning:: .. warning::

View File

@@ -1,9 +1,13 @@
softReset() Netscript Function softReset() Netscript Function
=================================== ===================================
.. js:function:: softReset() .. js:function:: softReset([callbackScript])
:RAM cost: 5 GB :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. 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"> <li id="help-menu-header-li">
<button id="help-menu-header" class="mainmenu-accordion-header"> Help </button> <button id="help-menu-header" class="mainmenu-accordion-header"> Help </button>
</li> </li>
<li id="tutorial-tab" class="mainmenu-accordion-panel"> <li id="milestones-tab" class="mainmenu-accordion-panel">
<button id="tutorial-menu-link"> Tutorial </button> <button id="milestones-menu-link"> Milestones </button>
</li> </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"> <li id="options-tab" class="mainmenu-accordion-panel">
<button id="options-menu-link"> Options </button> <button id="options-menu-link"> Options </button>
</li> </li>
@@ -177,7 +180,7 @@
<table id="terminal"> <table id="terminal">
<tr id="terminal-input"> <tr id="terminal-input">
<td id="terminal-input-td" tabindex="2">$ <td id="terminal-input-td" tabindex="2">$
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/> <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off"/>
</td> </td>
</tr> </tr>
</table> </table>
@@ -226,6 +229,10 @@
<!-- Augmentations --> <!-- Augmentations -->
<div id="augmentations-container" class="generic-menupage-container"></div> <div id="augmentations-container" class="generic-menupage-container"></div>
<!-- Milestones content -->
<div id="milestones-container" class="generic-menupage-container">
</div>
<!-- Tutorial content --> <!-- Tutorial content -->
<div id="tutorial-container" class="generic-menupage-container"> <div id="tutorial-container" class="generic-menupage-container">
<h1> Tutorial (AKA Links to Documentation) </h1> <h1> Tutorial (AKA Links to Documentation) </h1>
@@ -261,16 +268,16 @@
<div id="infiltration-left-panel"> <div id="infiltration-left-panel">
<p id="infiltration-level-text"> </p> <p id="infiltration-level-text"> </p>
<div id="infiltration-buttons"> <div id="infiltration-buttons">
<a class="a-link-button tooltip" id="infiltration-kill"> </a> <button class="a-link-button tooltip" id="infiltration-kill"> </button>
<a class="a-link-button tooltip" id="infiltration-knockout"> </a> <button class="a-link-button tooltip" id="infiltration-knockout"> </button>
<a class="a-link-button tooltip" id="infiltration-stealthknockout"> </a> <button class="a-link-button tooltip" id="infiltration-stealthknockout"> </button>
<a class="a-link-button tooltip" id="infiltration-assassinate"> </a> <button class="a-link-button tooltip" id="infiltration-assassinate"> </button>
<a class="a-link-button tooltip" id="infiltration-hacksecurity"> </a> <button class="a-link-button tooltip" id="infiltration-hacksecurity"> </button>
<a class="a-link-button tooltip" id="infiltration-destroysecurity"> </a> <button class="a-link-button tooltip" id="infiltration-destroysecurity"> </button>
<a class="a-link-button tooltip" id="infiltration-sneak"> </a> <button class="a-link-button tooltip" id="infiltration-sneak"> </button>
<a class="a-link-button tooltip" id="infiltration-pickdoor"> </a> <button class="a-link-button tooltip" id="infiltration-pickdoor"> </button>
<a class="a-link-button tooltip" id="infiltration-bribe"> </a> <button class="a-link-button tooltip" id="infiltration-bribe"> </button>
<a class="a-link-button tooltip" id="infiltration-escape"> </a> <button class="a-link-button tooltip" id="infiltration-escape"> </button>
</div> </div>
</div> </div>
<div id="infiltration-right-panel"> <div id="infiltration-right-panel">
@@ -381,13 +388,13 @@
<!-- Status text --> <!-- Status text -->
<div id="status-text-container"> <div id="status-text-container">
<p id="status-text"> </p> <p id="status-text"></p>
</div> </div>
<!-- Game Options --> <!-- Game Options -->
<div id="game-options-container" class="popup-box-container"> <div id="game-options-container" class="popup-box-container">
<div id="game-options-content" class="game-options-box"> <div id="game-options-content" class="game-options-box">
<button id="game-options-close-button">&times;</button> <button id="game-options-close-button" aria-label="close options dialog">&times;</button>
<h1> Game Options </h1> <h1> Game Options </h1>
<br/> <br/>
<div id="game-options-left-panel"> <div id="game-options-left-panel">
@@ -511,6 +518,26 @@
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys"> <input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
</fieldset> </fieldset>
<!-- View city as list of buttons instead of ASCII art. -->
<fieldset>
<label for="settingsDisableASCIIArt" class="tooltip">Disable ASCII art:
<span class="tooltiptexthigh">
If this is set all ASCII art will be disabled.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
</fieldset>
<!-- 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 --> <!-- Locale for displaying numbers -->
<fieldset> <fieldset>
<label for="settingsLocale" class="tooltip">Locale: <label for="settingsLocale" class="tooltip">Locale:
@@ -549,6 +576,7 @@
<div id="game-options-right-panel"> <div id="game-options-right-panel">
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> Changelog </a> <a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank"> Changelog </a>
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a> <a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank">Documentation</a>
<a class="a-link-button" href="https://discord.gg/TFc3hKD" target="_blank">Discord</a>
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a> <a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
<button id="save-game-link" class="a-link-button"> Save Game </button> <button id="save-game-link" class="a-link-button"> Save Game </button>
<button id="delete-game-link" class="a-link-button"> Delete Game </button> <button id="delete-game-link" class="a-link-button"> Delete Game </button>

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

View File

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

View File

@@ -49,31 +49,27 @@ interface IConstructorParams {
} }
export class Augmentation { 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 // How much money this costs to buy
baseCost: number = 0; baseCost = 0;
// How much faction reputation is required to unlock this // How much faction reputation is required to unlock this
baseRepRequirement: number = 0; baseRepRequirement = 0;
// Description of what this Aug is and what it does // Description of what this Aug is and what it does
info: string = ""; info = "";
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs) // 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 // Augmentation level - for repeatable Augs like NeuroFlux Governor
level: number = 0; level = 0;
// Name of Augmentation // Name of Augmentation
name: string = ""; name = "";
// Whether the player owns this Augmentation // Whether the player owns this Augmentation
owned: boolean = false; owned = false;
// Array of names of all prerequisites // Array of names of all prerequisites
prereqs: string[] = []; prereqs: string[] = [];
@@ -83,7 +79,7 @@ export class Augmentation {
mults: IMap<number> = {} mults: IMap<number> = {}
// Initial cost. Doesn't change when you purchase multiple Augmentation // Initial cost. Doesn't change when you purchase multiple Augmentation
startingCost: number = 0; startingCost = 0;
constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) { constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) {
this.name = params.name; 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]}`); console.warn(`In Augmentation.addToFactions(), could not find faction with this name: ${factionList[i]}`);
continue; 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}`); console.warn(`Invalid Faction object in addToAllFactions(). Key value: ${fac}`);
continue; continue;
} }
facObj!.augmentations.push(this.name); facObj.augmentations.push(this.name);
} }
} }
} }
@@ -163,6 +159,12 @@ export class Augmentation {
toJSON(): any { toJSON(): any {
return Generic_toJSON("Augmentation", this); 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; Reviver.constructors.Augmentation = Augmentation;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@ import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { Augmentations} from "../Augmentations"; import { Augmentations} from "../Augmentations";
function calculateAugmentedStats() { function calculateAugmentedStats(): any {
const augP: any = {}; const augP: any = {};
for(const aug of Player.queuedAugmentations) { for(const aug of Player.queuedAugmentations) {
const augObj = Augmentations[aug.name]; const augObj = Augmentations[aug.name];
@@ -22,12 +22,12 @@ function calculateAugmentedStats() {
export function PlayerMultipliers(): React.ReactElement { export function PlayerMultipliers(): React.ReactElement {
const mults = calculateAugmentedStats(); const mults = calculateAugmentedStats();
function MultiplierTable(rows: any[]): React.ReactElement { function MultiplierTable(rows: any[]): React.ReactElement {
function improvements(r: number) { function improvements(r: number): JSX.Element[] {
let elems: any[] = []; let elems: JSX.Element[] = [];
if(r) { if(r) {
elems = [ elems = [
<td key='2'>&nbsp;=>&nbsp;</td>, <td key="2">&nbsp;{"=>"}&nbsp;</td>,
<td key='3'>{numeralWrapper.formatPercentage(r)}</td> <td key="3">{numeralWrapper.formatPercentage(r)}</td>,
]; ];
} }
return elems; return elems;
@@ -36,8 +36,8 @@ export function PlayerMultipliers(): React.ReactElement {
return <table> return <table>
<tbody> <tbody>
{rows.map((r: any) => <tr key={r[0]}> {rows.map((r: any) => <tr key={r[0]}>
<td key='0'><span>{r[0]} multiplier:&nbsp;</span></td> <td key="0"><span>{r[0]} multiplier:&nbsp;</span></td>
<td key='1' style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td> <td key="1" style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
{improvements(r[2])} {improvements(r[2])}
</tr>)} </tr>)}
</tbody> </tbody>
@@ -51,38 +51,38 @@ export function PlayerMultipliers(): React.ReactElement {
['Hacking Chance ', Player.hacking_chance_mult, Player.hacking_chance_mult*mults.hacking_chance_mult], ['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 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 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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Hacking Level ', Player.hacking_mult, Player.hacking_mult*mults.hacking_mult], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Strength Level ', Player.strength_mult, Player.strength_mult*mults.strength_mult], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Defense Level ', Player.defense_mult, Player.defense_mult*mults.defense_mult], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Dexterity Level ', Player.dexterity_mult, Player.dexterity_mult*mults.dexterity_mult], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Agility Level ', Player.agility_mult, Player.agility_mult*mults.agility_mult], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Charisma Level ', Player.charisma_mult, Player.charisma_mult*mults.charisma_mult], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
@@ -90,13 +90,13 @@ 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 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 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 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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([
['Company reputation gain ', Player.company_rep_mult, Player.company_rep_mult*mults.company_rep_mult], ['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], ['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 /> ])}<br />
{MultiplierTable([ {MultiplierTable([

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ class BitNode {
number: number; number: number;
constructor(n: number, name: string, desc: string="", info: string="") { constructor(n: number, name: string, desc="", info="") {
this.number = n; this.number = n;
this.name = name; this.name = name;
this.desc = desc; this.desc = desc;
@@ -234,7 +234,7 @@ BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
"Level 3: 56%"); "Level 3: 56%");
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.", BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
"To iterate is human, to recurse divine.<br><br>" + "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 " + "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. " + "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)"); "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)");
@@ -252,11 +252,11 @@ BitNodes["BitNode22"] = new BitNode(22, "", "COMING SOON");
BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON"); BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON");
BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON"); BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON");
export function initBitNodeMultipliers(p: IPlayer) { export function initBitNodeMultipliers(p: IPlayer): void {
if (p.bitNodeN == null) { if (p.bitNodeN == null) {
p.bitNodeN = 1; p.bitNodeN = 1;
} }
for (var mult in BitNodeMultipliers) { for (const mult in BitNodeMultipliers) {
if (BitNodeMultipliers.hasOwnProperty(mult)) { if (BitNodeMultipliers.hasOwnProperty(mult)) {
BitNodeMultipliers[mult] = 1; BitNodeMultipliers[mult] = 1;
} }
@@ -433,15 +433,15 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.FourSigmaMarketDataCost = 4; BitNodeMultipliers.FourSigmaMarketDataCost = 4;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4; BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
break; break;
case 12: //The Recursion case 12: { //The Recursion
var sf12Lvl = 0; let sf12Lvl = 0;
for (var i = 0; i < p.sourceFiles.length; i++) { for (let i = 0; i < p.sourceFiles.length; i++) {
if (p.sourceFiles[i].n === 12) { if (p.sourceFiles[i].n === 12) {
sf12Lvl = p.sourceFiles[i].lvl; sf12Lvl = p.sourceFiles[i].lvl;
} }
} }
var inc = Math.pow(1.02, sf12Lvl); const inc = Math.pow(1.02, sf12Lvl);
var dec = 1/inc; const dec = 1/inc;
// Multiplier for number of augs needed for Daedalus increases // Multiplier for number of augs needed for Daedalus increases
// up to a maximum of 1.34, which results in 40 Augs required // up to a maximum of 1.34, which results in 40 Augs required
@@ -499,6 +499,7 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.BladeburnerRank = dec; BitNodeMultipliers.BladeburnerRank = dec;
BitNodeMultipliers.BladeburnerSkillCost = inc; BitNodeMultipliers.BladeburnerSkillCost = inc;
break; break;
}
default: default:
console.warn("Player.bitNodeN invalid"); console.warn("Player.bitNodeN invalid");
break; break;

View File

@@ -1,13 +1,13 @@
import { Augmentations } from "./Augmentation/Augmentations"; import { Augmentations } from "./Augmentation/Augmentations";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import { CONSTANTS } from "./Constants";
import { Engine } from "./engine"; import { Engine } from "./engine";
import { Faction } from "./Faction/Faction"; import { Faction } from "./Faction/Faction";
import { Factions, factionExists } from "./Faction/Factions"; import { Factions, factionExists } from "./Faction/Factions";
import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers"; import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers";
import { Player } from "./Player"; import { Player } from "./Player";
import { hackWorldDaemon, redPillFlag } from "./RedPill"; import { hackWorldDaemon, redPillFlag } from "./RedPill";
import { calculateHospitalizationCost } from "./Hospital/Hospital";
import { Page, routing } from "./ui/navigationTracking"; import { Page, routing } from "./ui/navigationTracking";
import { numeralWrapper } from "./ui/numeralFormat"; import { numeralWrapper } from "./ui/numeralFormat";
@@ -16,17 +16,19 @@ import { dialogBoxCreate } from "../utils/DialogBox";
import { import {
Reviver, Reviver,
Generic_toJSON, Generic_toJSON,
Generic_fromJSON Generic_fromJSON,
} from "../utils/JSONReviver"; } from "../utils/JSONReviver";
import { setTimeoutRef } from "./utils/SetTimeoutRef"; import { setTimeoutRef } from "./utils/SetTimeoutRef";
import { formatNumber } from "../utils/StringHelperFunctions"; import {
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../utils/StringHelperFunctions";
import { ConsoleHelpText } from "./Bladeburner/data/Help"; import { ConsoleHelpText } from "./Bladeburner/data/Help";
import { City } from "./Bladeburner/City"; import { City } from "./Bladeburner/City";
import { BladeburnerConstants } from "./Bladeburner/data/Constants"; import { BladeburnerConstants } from "./Bladeburner/data/Constants";
import { Skill } from "./Bladeburner/Skill"; import { Skill } from "./Bladeburner/Skill";
import { Skills } from "./Bladeburner/Skills"; import { Skills } from "./Bladeburner/Skills";
import { SkillNames } from "./Bladeburner/data/SkillNames";
import { Operation } from "./Bladeburner/Operation"; import { Operation } from "./Bladeburner/Operation";
import { BlackOperation } from "./Bladeburner/BlackOperation"; import { BlackOperation } from "./Bladeburner/BlackOperation";
import { BlackOperations } from "./Bladeburner/BlackOperations"; import { BlackOperations } from "./Bladeburner/BlackOperations";
@@ -44,7 +46,6 @@ import { KEY } from "../utils/helpers/keyCodes";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement"; import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
import { appendLineBreaks } from "../utils/uiHelpers/appendLineBreaks"; import { appendLineBreaks } from "../utils/uiHelpers/appendLineBreaks";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { createElement } from "../utils/uiHelpers/createElement"; import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup"; import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElement } from "../utils/uiHelpers/removeElement"; import { removeElement } from "../utils/uiHelpers/removeElement";
@@ -235,7 +236,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(25, 150), countGrowth:getRandomInt(5, 75)/10, 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}, 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}, 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({ this.contracts["Bounty Hunter"] = new Contract({
name:"Bounty Hunter", name:"Bounty Hunter",
@@ -247,7 +248,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10, 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}, 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}, 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({ this.contracts["Retirement"] = new Contract({
name:"Retirement", name:"Retirement",
@@ -259,7 +260,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(5, 150), countGrowth:getRandomInt(5, 75)/10, 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}, 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}, 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({ this.operations["Investigation"] = new Operation({
@@ -274,7 +275,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10, 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}, 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}, 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({ this.operations["Undercover Operation"] = new Operation({
name:"Undercover Operation", name:"Undercover Operation",
@@ -287,7 +288,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 100), countGrowth:getRandomInt(10, 40)/10, 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}, 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}, 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({ this.operations["Sting Operation"] = new Operation({
name:"Sting Operation", name:"Sting Operation",
@@ -298,19 +299,19 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 150), countGrowth:getRandomInt(3, 40)/10, 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}, 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}, 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({ this.operations["Raid"] = new Operation({
name:"Raid", name:"Raid",
desc:"Lead an assault on a known Synthoid community. Note that " + desc:"Lead an assault on a known Synthoid community. Note that " +
"there must be an existing Synthoid community in your current city " + "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, baseDifficulty:800, difficultyFac:1.045, rewardFac:1.1, reqdRank:3000,
rankGain:55,rankLoss:2.5,hpLoss:50, rankGain:55,rankLoss:2.5,hpLoss:50,
count:getRandomInt(1, 150), countGrowth:getRandomInt(2, 40)/10, 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}, 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}, 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({ this.operations["Stealth Retirement Operation"] = new Operation({
name:"Stealth Retirement Operation", name:"Stealth Retirement Operation",
@@ -322,7 +323,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10, 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}, 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}, 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({ this.operations["Assassination"] = new Operation({
name:"Assassination", name:"Assassination",
@@ -334,7 +335,7 @@ Bladeburner.prototype.create = function() {
count:getRandomInt(1, 150), countGrowth:getRandomInt(1, 20)/10, 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}, 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}, 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,
}); });
} }
@@ -728,9 +729,10 @@ Bladeburner.prototype.completeAction = function() {
damage = action.hpLoss * difficultyMultiplier; damage = action.hpLoss * difficultyMultiplier;
damage = Math.ceil(addOffset(damage, 10)); damage = Math.ceil(addOffset(damage, 10));
this.hpLost += damage; this.hpLost += damage;
const cost = calculateHospitalizationCost(Player, damage);
if (Player.takeDamage(damage)) { if (Player.takeDamage(damage)) {
++this.numHosp; ++this.numHosp;
this.moneyLost += (CONSTANTS.HospitalCostPerHp * Player.max_hp); this.moneyLost += cost;
} }
} }
var logLossText = ""; var logLossText = "";
@@ -800,9 +802,10 @@ Bladeburner.prototype.completeAction = function() {
if (action.hpLoss) { if (action.hpLoss) {
damage = action.hpLoss * difficultyMultiplier; damage = action.hpLoss * difficultyMultiplier;
damage = Math.ceil(addOffset(damage, 10)); damage = Math.ceil(addOffset(damage, 10));
const cost = calculateHospitalizationCost(Player, damage);
if (Player.takeDamage(damage)) { if (Player.takeDamage(damage)) {
++this.numHosp; ++this.numHosp;
this.moneyLost += (CONSTANTS.HospitalCostPerHp * Player.max_hp); this.moneyLost += cost;
} }
} }
teamLossMax = Math.floor(teamCount); teamLossMax = Math.floor(teamCount);
@@ -1066,7 +1069,11 @@ Bladeburner.prototype.gainActionStats = function(action, success) {
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult); Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult); Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult); Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
Player.gainIntelligenceExp(unweightedIntGain * action.weights.int * skillMult); let intExp = unweightedIntGain * action.weights.int * skillMult;
if (intExp > 1) {
intExp = Math.pow(intExp, 0.8);
}
Player.gainIntelligenceExp(intExp);
} }
Bladeburner.prototype.randomEvent = function() { Bladeburner.prototype.randomEvent = function() {
@@ -1264,7 +1271,7 @@ Bladeburner.prototype.createContent = function() {
DomElems.consoleInput.focus(); DomElems.consoleInput.focus();
} }
return false; return false;
} },
}); });
DomElems.consoleTable = createElement("table", {class:"bladeburner-console-table"}); DomElems.consoleTable = createElement("table", {class:"bladeburner-console-table"});
DomElems.consoleInputRow = createElement("tr", {class:"bladeburner-console-input-row", id:"bladeburner-console-input-row"}); DomElems.consoleInputRow = createElement("tr", {class:"bladeburner-console-input-row", id:"bladeburner-console-input-row"});
@@ -1272,7 +1279,7 @@ Bladeburner.prototype.createContent = function() {
DomElems.consoleInputHeader = createElement("pre", {innerText:"> "}); DomElems.consoleInputHeader = createElement("pre", {innerText:"> "});
DomElems.consoleInput = createElement("input", { DomElems.consoleInput = createElement("input", {
type:"text", class:"bladeburner-console-input", tabIndex:1, 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); DomElems.consoleInputCell.appendChild(DomElems.consoleInputHeader);
@@ -1356,7 +1363,7 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText:"Est. Synthoid Population: ", innerText:"Est. Synthoid Population: ",
display:"inline-block", display:"inline-block",
tooltip:"This is your Bladeburner division's estimate of how many Synthoids exist " + 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", { DomElems.overviewEstPopHelpTip = createElement("div", {
@@ -1374,7 +1381,7 @@ Bladeburner.prototype.createOverviewContent = function() {
"The Synthoid populations of cities can change due to your " + "The Synthoid populations of cities can change due to your " +
"actions or random events. If random events occur, they will " + "actions or random events. If random events occur, they will " +
"be logged in the Bladeburner Console."); "be logged in the Bladeburner Console.");
} },
}); });
DomElems.overviewEstComms = createElement("p", { DomElems.overviewEstComms = createElement("p", {
@@ -1388,14 +1395,14 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText:"City Chaos: ", innerText:"City Chaos: ",
display:"inline-block", display:"inline-block",
tooltip:"The city's chaos level due to tensions and conflicts between humans and Synthoids. " + 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", { DomElems.overviewBonusTime = createElement("p", {
innerText: "Bonus time: ", innerText: "Bonus time: ",
display: "inline-block", 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). " + 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"}); DomElems.overviewSkillPoints = createElement("p", {display:"block"});
@@ -1431,7 +1438,7 @@ Bladeburner.prototype.createOverviewContent = function() {
innerText:"Cancel", class:"a-link-button", innerText:"Cancel", class:"a-link-button",
clickListener:() => { clickListener:() => {
removeElementById(popupId); return false; removeElementById(popupId); return false;
} },
})) }))
popupArguments.push(createElement("p", { // Info Text popupArguments.push(createElement("p", { // Info Text
innerText:"Travel to a different city for your Bladeburner " + innerText:"Travel to a different city for your Bladeburner " +
@@ -1453,12 +1460,12 @@ Bladeburner.prototype.createOverviewContent = function() {
removeElementById(popupId); removeElementById(popupId);
inst.updateOverviewContent(); inst.updateOverviewContent();
return false; return false;
} },
})); }));
})(this, i); })(this, i);
} }
createPopup(popupId, popupArguments); createPopup(popupId, popupArguments);
} },
})); }));
// Faction button // Faction button
@@ -1486,7 +1493,7 @@ Bladeburner.prototype.createOverviewContent = function() {
} }
} }
return false; return false;
} },
})); }));
} }
@@ -1519,14 +1526,14 @@ Bladeburner.prototype.createActionAndSkillsContent = function() {
DomElems.currentTab = buttons[i].toLowerCase(); DomElems.currentTab = buttons[i].toLowerCase();
inst.createActionAndSkillsContent(); inst.createActionAndSkillsContent();
return false; return false;
} },
})); }));
}) (buttons, i, this, currTab); }) (buttons, i, this, currTab);
} }
// General info/description for each action // General info/description for each action
DomElems.actionsAndSkillsDesc = createElement("p", { DomElems.actionsAndSkillsDesc = createElement("p", {
display:"block", margin:"4px", padding:"4px" display:"block", margin:"4px", padding:"4px",
}); });
// List for actions/skills // List for actions/skills
@@ -1571,7 +1578,7 @@ Bladeburner.prototype.createGeneralActionsContent = function() {
for (var actionName in GeneralActions) { for (var actionName in GeneralActions) {
if (GeneralActions.hasOwnProperty(actionName)) { if (GeneralActions.hasOwnProperty(actionName)) {
DomElems.generalActions[actionName] = createElement("div", { DomElems.generalActions[actionName] = createElement("div", {
class:"bladeburner-action", name:actionName class:"bladeburner-action", name:actionName,
}); });
DomElems.actionsAndSkillsList.appendChild(DomElems.generalActions[actionName]); DomElems.actionsAndSkillsList.appendChild(DomElems.generalActions[actionName]);
} }
@@ -1593,7 +1600,7 @@ Bladeburner.prototype.createContractsContent = function() {
for (var contractName in this.contracts) { for (var contractName in this.contracts) {
if (this.contracts.hasOwnProperty(contractName)) { if (this.contracts.hasOwnProperty(contractName)) {
DomElems.contracts[contractName] = createElement("div", { DomElems.contracts[contractName] = createElement("div", {
class:"bladeburner-action", name:contractName class:"bladeburner-action", name:contractName,
}); });
DomElems.actionsAndSkillsList.appendChild(DomElems.contracts[contractName]); DomElems.actionsAndSkillsList.appendChild(DomElems.contracts[contractName]);
} }
@@ -1622,7 +1629,7 @@ Bladeburner.prototype.createOperationsContent = function() {
for (var operationName in this.operations) { for (var operationName in this.operations) {
if (this.operations.hasOwnProperty(operationName)) { if (this.operations.hasOwnProperty(operationName)) {
DomElems.operations[operationName] = createElement("div", { DomElems.operations[operationName] = createElement("div", {
class:"bladeburner-action", name:operationName class:"bladeburner-action", name:operationName,
}); });
DomElems.actionsAndSkillsList.appendChild(DomElems.operations[operationName]); DomElems.actionsAndSkillsList.appendChild(DomElems.operations[operationName]);
} }
@@ -1660,7 +1667,7 @@ Bladeburner.prototype.createBlackOpsContent = function() {
for (var i = blackops.length-1; i >= 0 ; --i) { 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. 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", { 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]); DomElems.actionsAndSkillsList.appendChild(DomElems.blackops[blackops[i].name]);
} }
@@ -1743,7 +1750,7 @@ Bladeburner.prototype.createSkillsContent = function() {
// Skill Points // Skill Points
DomElems.skillPointsDisplay = createElement("p", { 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); DomElems.actionAndSkillsDiv.appendChild(DomElems.skillPointsDisplay);
@@ -1751,7 +1758,7 @@ Bladeburner.prototype.createSkillsContent = function() {
for (var skillName in Skills) { for (var skillName in Skills) {
if (Skills.hasOwnProperty(skillName)) { if (Skills.hasOwnProperty(skillName)) {
DomElems.skills[skillName] = createElement("div", { DomElems.skills[skillName] = createElement("div", {
class:"bladeburner-action", name:skillName class:"bladeburner-action", name:skillName,
}); });
DomElems.actionsAndSkillsList.appendChild(DomElems.skills[skillName]); DomElems.actionsAndSkillsList.appendChild(DomElems.skills[skillName]);
} }
@@ -1771,7 +1778,7 @@ Bladeburner.prototype.updateOverviewContent = function() {
Stamina Penalty: {formatNumber((1-this.calculateStaminaPenalty())*100, 1)}%<br /><br /> Stamina Penalty: {formatNumber((1-this.calculateStaminaPenalty())*100, 1)}%<br /><br />
Team Size: {formatNumber(this.teamSize, 0)}<br /> Team Size: {formatNumber(this.teamSize, 0)}<br />
Team Members Lost: {formatNumber(this.teamLost, 0)}<br /><br /> Team Members Lost: {formatNumber(this.teamLost, 0)}<br /><br />
Num Times Hospitalized: this.numHosp<br /> Num Times Hospitalized: {this.numHosp}<br />
Money Lost From Hospitalizations: {Money(this.moneyLost)}<br /><br /> Money Lost From Hospitalizations: {Money(this.moneyLost)}<br /><br />
Current City: {this.city}<br /> Current City: {this.city}<br />
</>, DomElems.overviewGen1); </>, DomElems.overviewGen1);
@@ -1895,7 +1902,7 @@ Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
var progress = this.actionTimeCurrent / this.actionTimeToComplete; var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
display:"block", display:"block",
innerText:createProgressBarText({progress:progress}) innerText:createProgressBarText({progress:progress}),
})); }));
} else { } else {
// Start button // Start button
@@ -1908,13 +1915,13 @@ Bladeburner.prototype.updateGeneralActionsUIElement = function(el, action) {
this.startAction(this.action); this.startAction(this.action);
this.updateActionAndSkillsContent(); this.updateActionAndSkillsContent();
return false; return false;
} },
})); }));
} }
appendLineBreaks(el, 2); appendLineBreaks(el, 2);
el.appendChild(createElement("pre", { // Info el.appendChild(createElement("pre", { // Info
innerHTML:action.desc, display:"inline-block" innerHTML:action.desc, display:"inline-block",
})); }));
@@ -1930,14 +1937,14 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
formatNumber(this.actionTimeCurrent, 0) + " / " + formatNumber(this.actionTimeCurrent, 0) + " / " +
formatNumber(this.actionTimeToComplete, 0) + ")" formatNumber(this.actionTimeToComplete, 0) + ")"
: action.name, : action.name,
display:"inline-block" display:"inline-block",
})); }));
if (isActive) { // Progress bar if its active if (isActive) { // Progress bar if its active
var progress = this.actionTimeCurrent / this.actionTimeToComplete; var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
display:"block", display:"block",
innerText:createProgressBarText({progress:progress}) innerText:createProgressBarText({progress:progress}),
})); }));
} else { // Start button } else { // Start button
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
@@ -1949,7 +1956,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
this.startAction(this.action); this.startAction(this.action);
this.updateActionAndSkillsContent(); this.updateActionAndSkillsContent();
return false; return false;
} },
})); }));
} }
@@ -1960,7 +1967,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
display:"inline-block", display:"inline-block",
innerText:"Level: " + action.level + " / " + action.maxLevel, innerText:"Level: " + action.level + " / " + action.maxLevel,
tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel) + " successes " + tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel) + " successes " +
"needed for next level" "needed for next level",
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;", class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@@ -1972,7 +1979,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action if (isActive) {this.startAction(this.action);} // Restart Action
this.updateContractsUIElement(el, action); this.updateContractsUIElement(el, action);
return false; return false;
} },
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"&darr;", class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"&darr;",
@@ -1984,7 +1991,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action if (isActive) {this.startAction(this.action);} // Restart Action
this.updateContractsUIElement(el, action); this.updateContractsUIElement(el, action);
return false; return false;
} },
})); }));
var actionTime = action.getActionTime(this); var actionTime = action.getActionTime(this);
@@ -2004,7 +2011,7 @@ Bladeburner.prototype.updateContractsUIElement = function(el, action) {
var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox"; var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox";
el.appendChild(createElement("label", { el.appendChild(createElement("label", {
for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white", for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white",
tooltip:"Automatically increase contract level when possible" tooltip:"Automatically increase contract level when possible",
})); }));
const checkboxInput = createElement("input", { const checkboxInput = createElement("input", {
@@ -2028,14 +2035,14 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
formatNumber(this.actionTimeCurrent, 0) + " / " + formatNumber(this.actionTimeCurrent, 0) + " / " +
formatNumber(this.actionTimeToComplete, 0) + ")" formatNumber(this.actionTimeToComplete, 0) + ")"
: action.name, : action.name,
display:"inline-block" display:"inline-block",
})); }));
if (isActive) { // Progress bar if its active if (isActive) { // Progress bar if its active
var progress = this.actionTimeCurrent / this.actionTimeToComplete; var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
display:"block", display:"block",
innerText:createProgressBarText({progress:progress}) innerText:createProgressBarText({progress:progress}),
})); }));
} else { // Start button and set Team Size button } else { // Start button and set Team Size button
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
@@ -2047,7 +2054,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
this.startAction(this.action); this.startAction(this.action);
this.updateActionAndSkillsContent(); this.updateActionAndSkillsContent();
return false; return false;
} },
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button", innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button",
@@ -2058,7 +2065,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
innerText:"Enter the amount of team members you would like to take on these " + 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, " + "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 " + "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", { var input = createElement("input", {
@@ -2068,25 +2075,25 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
innerText:"Confirm", class:"a-link-button", innerText:"Confirm", class:"a-link-button",
clickListener:() => { clickListener:() => {
var num = Math.round(parseFloat(input.value)); var num = Math.round(parseFloat(input.value));
if (isNaN(num)) { if (isNaN(num) || num < 0) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric)") dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
} else { } else {
action.teamCount = num; action.teamCount = num;
this.updateOperationsUIElement(el, action); this.updateOperationsUIElement(el, action);
} }
removeElementById(popupId); removeElementById(popupId);
return false; return false;
} },
}); });
var cancelBtn = createElement("a", { var cancelBtn = createElement("a", {
innerText:"Cancel", class:"a-link-button", innerText:"Cancel", class:"a-link-button",
clickListener:() => { clickListener:() => {
removeElementById(popupId); removeElementById(popupId);
return false; return false;
} },
}); });
createPopup(popupId, [txt, input, setBtn, cancelBtn]); createPopup(popupId, [txt, input, setBtn, cancelBtn]);
} },
})); }));
} }
@@ -2097,7 +2104,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
display:"inline-block", display:"inline-block",
innerText:"Level: " + action.level + " / " + action.maxLevel, innerText:"Level: " + action.level + " / " + action.maxLevel,
tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel) + " successes " + tooltip:action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel) + " successes " +
"needed for next level" "needed for next level",
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;", class: maxLevel ? "a-link-button-inactive" : "a-link-button", innerHTML:"&uarr;",
@@ -2109,7 +2116,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action if (isActive) {this.startAction(this.action);} // Restart Action
this.updateOperationsUIElement(el, action); this.updateOperationsUIElement(el, action);
return false; return false;
} },
})); }));
el.appendChild(createElement("a", { el.appendChild(createElement("a", {
class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"&darr;", class: (action.level <= 1) ? "a-link-button-inactive" : "a-link-button", innerHTML:"&darr;",
@@ -2121,11 +2128,10 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
if (isActive) {this.startAction(this.action);} // Restart Action if (isActive) {this.startAction(this.action);} // Restart Action
this.updateOperationsUIElement(el, action); this.updateOperationsUIElement(el, action);
return false; return false;
} },
})); }));
// General Info // General Info
var difficulty = action.getDifficulty();
var actionTime = action.getActionTime(this); var actionTime = action.getActionTime(this);
appendLineBreaks(el, 2); appendLineBreaks(el, 2);
el.appendChild(createElement("pre", { el.appendChild(createElement("pre", {
@@ -2143,7 +2149,7 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox"; var autolevelCheckboxId = "bladeburner-" + action.name + "-autolevel-checkbox";
el.appendChild(createElement("label", { el.appendChild(createElement("label", {
for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white", for:autolevelCheckboxId, innerText:"Autolevel: ",color:"white",
tooltip:"Automatically increase operation level when possible" tooltip:"Automatically increase operation level when possible",
})); }));
const checkboxInput = createElement("input", { const checkboxInput = createElement("input", {
@@ -2163,7 +2169,6 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
var isActive = el.classList.contains(ActiveActionCssClass); var isActive = el.classList.contains(ActiveActionCssClass);
var isCompleted = (this.blackops[action.name] != null); var isCompleted = (this.blackops[action.name] != null);
var estimatedSuccessChance = action.getSuccessChance(this, {est:true}); var estimatedSuccessChance = action.getSuccessChance(this, {est:true});
var difficulty = action.getDifficulty();
var actionTime = action.getActionTime(this); var actionTime = action.getActionTime(this);
var hasReqdRank = this.rank >= action.reqdRank; var hasReqdRank = this.rank >= action.reqdRank;
@@ -2187,7 +2192,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
var progress = this.actionTimeCurrent / this.actionTimeToComplete; var progress = this.actionTimeCurrent / this.actionTimeToComplete;
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
display:"block", display:"block",
innerText:createProgressBarText({progress:progress}) innerText:createProgressBarText({progress:progress}),
})); }));
} else { } else {
el.appendChild(createElement("a", { // Start button el.appendChild(createElement("a", { // Start button
@@ -2199,7 +2204,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
this.startAction(this.action); this.startAction(this.action);
this.updateActionAndSkillsContent(); this.updateActionAndSkillsContent();
return false; return false;
} },
})); }));
el.appendChild(createElement("a", { // Set Team Size Button el.appendChild(createElement("a", { // Set Team Size Button
innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button", innerText:"Set Team Size (Curr Size: " + formatNumber(action.teamCount, 0) + ")", class:"a-link-button",
@@ -2210,7 +2215,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
innerText:"Enter the amount of team members you would like to take on this " + 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, " + "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 " + "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", { var input = createElement("input", {
@@ -2220,25 +2225,25 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
innerText:"Confirm", class:"a-link-button", innerText:"Confirm", class:"a-link-button",
clickListener:() => { clickListener:() => {
var num = Math.round(parseFloat(input.value)); var num = Math.round(parseFloat(input.value));
if (isNaN(num)) { if (isNaN(num) || num < 0) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric)") dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
} else { } else {
action.teamCount = num; action.teamCount = num;
this.updateBlackOpsUIElement(el, action); this.updateBlackOpsUIElement(el, action);
} }
removeElementById(popupId); removeElementById(popupId);
return false; return false;
} },
}); });
var cancelBtn = createElement("a", { var cancelBtn = createElement("a", {
innerText:"Cancel", class:"a-link-button", innerText:"Cancel", class:"a-link-button",
clickListener:() => { clickListener:() => {
removeElementById(popupId); removeElementById(popupId);
return false; return false;
} },
}); });
createPopup(popupId, [txt, input, setBtn, cancelBtn]); createPopup(popupId, [txt, input, setBtn, cancelBtn]);
} },
})); }));
} }
@@ -2250,7 +2255,7 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
})); }));
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
display:"block", color:hasReqdRank ? "white" : "red", 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", { el.appendChild(createElement("p", {
display:"inline-block", display:"inline-block",
@@ -2290,7 +2295,7 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
this.upgradeSkill(skill); this.upgradeSkill(skill);
this.createActionAndSkillsContent(); this.createActionAndSkillsContent();
return false; return false;
} },
})); }));
appendLineBreaks(el, 2); appendLineBreaks(el, 2);
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
@@ -2300,7 +2305,7 @@ Bladeburner.prototype.updateSkillsUIElement = function(el, skill) {
if (maxLvl) { if (maxLvl) {
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
color:"red", display:"block", color:"red", display:"block",
innerText:"MAX LEVEL" innerText:"MAX LEVEL",
})); }));
} else { } else {
el.appendChild(createElement("p", { el.appendChild(createElement("p", {
@@ -2501,7 +2506,7 @@ Bladeburner.prototype.executeAutomateConsoleCommand = function(args) {
case "gen": case "gen":
if (GeneralActions[val] != null) { if (GeneralActions[val] != null) {
var action = new ActionIdentifier({ var action = new ActionIdentifier({
type:ActionTypes[val], name:val type:ActionTypes[val], name:val,
}); });
if (highLow) { if (highLow) {
this.automateActionHigh = action; this.automateActionHigh = action;
@@ -2517,7 +2522,7 @@ Bladeburner.prototype.executeAutomateConsoleCommand = function(args) {
case "contracts": case "contracts":
if (this.contracts[val] != null) { if (this.contracts[val] != null) {
var action = new ActionIdentifier({ var action = new ActionIdentifier({
type:ActionTypes.Contract, name:val type:ActionTypes.Contract, name:val,
}); });
if (highLow) { if (highLow) {
this.automateActionHigh = action; this.automateActionHigh = action;
@@ -2535,7 +2540,7 @@ Bladeburner.prototype.executeAutomateConsoleCommand = function(args) {
case "operation": case "operation":
if (this.operations[val] != null) { if (this.operations[val] != null) {
var action = new ActionIdentifier({ var action = new ActionIdentifier({
type:ActionTypes.Operation, name:val type:ActionTypes.Operation, name:val,
}); });
if (highLow) { if (highLow) {
this.automateActionHigh = action; this.automateActionHigh = action;
@@ -3203,8 +3208,8 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
return -1; return -1;
} }
const sanitizedSize = Math.round(size); let sanitizedSize = Math.round(size);
if (isNaN(sanitizedSize)) { if (isNaN(sanitizedSize) || sanitizedSize < 0) {
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`); workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`);
return -1; return -1;
} }

View File

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

View File

@@ -13,21 +13,22 @@ export class BlackOperation extends Operation {
return 1.5; return 1.5;
} }
getChaosCompetencePenalty(inst: any, params: any): number { getChaosCompetencePenalty(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1; return 1;
} }
getChaosDifficultyBonus(inst: any, params: any): number { getChaosDifficultyBonus(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1; return 1;
} }
static fromJSON(value: any): Operation {
return Generic_fromJSON(BlackOperation, value.data);
}
toJSON(): any { toJSON(): any {
return Generic_toJSON("BlackOperation", this); 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; Reviver.constructors.BlackOperation = BlackOperation;

View File

@@ -16,12 +16,12 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:50, rankLoss:10, hpLoss:100, 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}, 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}, 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({ BlackOperations["Operation Zero"] = new BlackOperation({
name:"Operation Zero", name:"Operation Zero",
desc:"AeroCorp is one of the world's largest defense contractors. " + desc:"AeroCorp is one of the world's largest defense contractors. " +
"It's leader, Steve Watataki, is thought to be a supporter of " + "Its leader, Steve Watataki, is thought to be a supporter of " +
"Synthoid rights. He must be removed.<br><br>" + "Synthoid rights. He must be removed.<br><br>" +
"The goal of Operation Zero is to covertly infiltrate AeroCorp and " + "The goal of Operation Zero is to covertly infiltrate AeroCorp and " +
"uncover any incriminating evidence or " + "uncover any incriminating evidence or " +
@@ -33,7 +33,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:60, rankLoss:15, hpLoss:50, 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}, 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}, 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({ BlackOperations["Operation X"] = new BlackOperation({
name:"Operation X", name:"Operation X",
@@ -52,7 +52,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:75, rankLoss:15, hpLoss:100, 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}, 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}, 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({ BlackOperations["Operation Titan"] = new BlackOperation({
name:"Operation Titan", name:"Operation Titan",
@@ -70,7 +70,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:100, rankLoss:20, hpLoss:100, 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}, 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}, 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({ BlackOperations["Operation Ares"] = new BlackOperation({
name:"Operation Ares", name:"Operation Ares",
@@ -84,7 +84,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:125, rankLoss:20, hpLoss:200, 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}, 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}, 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({ BlackOperations["Operation Archangel"] = new BlackOperation({
name:"Operation Archangel", name:"Operation Archangel",
@@ -152,7 +152,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:750, rankLoss:60, hpLoss:1000, 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}, 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}, 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({ BlackOperations["Operation Deckard"] = new BlackOperation({
name:"Operation Deckard", name:"Operation Deckard",
@@ -202,7 +202,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:2e3, rankLoss:150, hpLoss:1500, 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}, 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}, 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({ BlackOperations["Operation Shoulder of Orion"] = new BlackOperation({
name:"Operation Shoulder of Orion", name:"Operation Shoulder of Orion",
@@ -218,7 +218,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:2.5e3, rankLoss:500, hpLoss:1500, 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}, 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}, 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({ BlackOperations["Operation Hyron"] = new BlackOperation({
name:"Operation Hyron", name:"Operation Hyron",
@@ -240,7 +240,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:3e3, rankLoss:1e3, hpLoss:500, 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}, 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}, 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({ BlackOperations["Operation Morpheus"] = new BlackOperation({
name:"Operation Morpheus", name:"Operation Morpheus",
@@ -257,7 +257,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:4e3, rankLoss:1e3, hpLoss:100, 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}, 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}, 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({ BlackOperations["Operation Ion Storm"] = new BlackOperation({
name:"Operation Ion Storm", name:"Operation Ion Storm",
@@ -272,7 +272,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:5e3, rankLoss:1e3, hpLoss:5000, 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}, 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}, 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({ BlackOperations["Operation Annihilus"] = new BlackOperation({
name:"Operation Annihilus", name:"Operation Annihilus",
@@ -286,7 +286,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:7.5e3, rankLoss:1e3, hpLoss:10e3, 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}, 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}, 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({ BlackOperations["Operation Ultron"] = new BlackOperation({
name:"Operation Ultron", name:"Operation Ultron",
@@ -306,7 +306,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
rankGain:10e3, rankLoss:2e3, hpLoss:10e3, 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}, 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}, 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({ BlackOperations["Operation Centurion"] = new BlackOperation({
name:"Operation Centurion", name:"Operation Centurion",

View File

@@ -5,13 +5,13 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviv
import { addOffset } from "../../utils/helpers/addOffset"; import { addOffset } from "../../utils/helpers/addOffset";
export class ChangePopulationByCountParams { export class ChangePopulationByCountParams {
estChange: number = 0; estChange = 0;
estOffset: number = 0; estOffset = 0;
} }
export class ChangePopulationByPercentageParams { export class ChangePopulationByPercentageParams {
nonZero: boolean = false; nonZero = false;
changeEstEqually: boolean = false; changeEstEqually = false;
} }
export class City { export class City {
@@ -19,32 +19,32 @@ export class City {
/** /**
* Name of the city. * Name of the city.
*/ */
name: string = ""; name = "";
/** /**
* Population of the city. * Population of the city.
*/ */
pop: number = 0; pop = 0;
/** /**
* Population estimation of the city. * Population estimation of the city.
*/ */
popEst: number = 0; popEst = 0;
/** /**
* Number of communities in the city. * Number of communities in the city.
*/ */
comms: number = 0; comms = 0;
/** /**
* Estimated number of communities in the city. * Estimated number of communities in the city.
*/ */
commsEst: number = 0; commsEst = 0;
/** /**
* Chaos level of the city. * Chaos level of the city.
*/ */
chaos: number = 0; chaos = 0;
constructor(name: string = BladeburnerConstants.CityNames[2]) { constructor(name: string = BladeburnerConstants.CityNames[2]) {
this.name = name; 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%) * 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; p = p*skillMult;
if (isNaN(p)) {throw new Error("NaN passed into City.improvePopulationEstimateByPercentage()");} if (isNaN(p)) {throw new Error("NaN passed into City.improvePopulationEstimateByPercentage()");}
if (this.popEst < this.pop) { 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 (isNaN(n)) {throw new Error("NaN passed into City.improveCommunityEstimate()");}
if (this.commsEst < this.comms) { if (this.commsEst < this.comms) {
this.commsEst += n; this.commsEst += n;
@@ -154,19 +154,20 @@ export class City {
if (this.chaos < 0) {this.chaos = 0;} 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. * Serialize the current object to a JSON save state.
*/ */
toJSON(): any { toJSON(): any {
return Generic_toJSON("City", this); 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; 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 { Action, IActionParams } from "./Action";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
@@ -8,17 +8,18 @@ export class Contract extends Action {
super(params); super(params);
} }
getActionTypeSkillSuccessBonus(inst: any): number { getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceContract; return inst.skillMultipliers.successChanceContract;
} }
static fromJSON(value: any): Contract {
return Generic_fromJSON(Contract, value.data);
}
toJSON(): any { toJSON(): any {
return Generic_toJSON("Contract", this); 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; Reviver.constructors.Contract = Contract;

View File

@@ -11,7 +11,7 @@ export const GeneralActions: IMap<Action> = {};
name:actionName, name:actionName,
desc:"Improve your abilities at the Bladeburner unit's specialized training " + desc:"Improve your abilities at the Bladeburner unit's specialized training " +
"center. Doing this gives experience for all combat stats and also " + "center. Doing this gives experience for all combat stats and also " +
"increases your max stamina." "increases your max stamina.",
}); });
actionName = "Field Analysis"; actionName = "Field Analysis";
@@ -21,7 +21,7 @@ export const GeneralActions: IMap<Action> = {};
"Bladeburner's unit intelligence on Synthoid locations and " + "Bladeburner's unit intelligence on Synthoid locations and " +
"activities. Completing this action will improve the accuracy " + "activities. Completing this action will improve the accuracy " +
"of your Synthoid population estimated in the current city.<br><br>" + "of your Synthoid population estimated in the current city.<br><br>" +
"Does NOT require stamina." "Does NOT require stamina.",
}); });
actionName = "Recruitment"; actionName = "Recruitment";
@@ -29,7 +29,7 @@ export const GeneralActions: IMap<Action> = {};
name:actionName, name:actionName,
desc:"Attempt to recruit members for your Bladeburner team. These members " + desc:"Attempt to recruit members for your Bladeburner team. These members " +
"can help you conduct operations.<br><br>" + "can help you conduct operations.<br><br>" +
"Does NOT require stamina." "Does NOT require stamina.",
}); });
actionName = "Diplomacy"; actionName = "Diplomacy";
@@ -37,7 +37,7 @@ export const GeneralActions: IMap<Action> = {};
name: actionName, name: actionName,
desc: "Improve diplomatic relations with the Synthoid population. " + desc: "Improve diplomatic relations with the Synthoid population. " +
"Completing this action will reduce the Chaos level in your current city.<br><br>" + "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"; 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 { BladeburnerConstants } from "./data/Constants";
import { Action, IActionParams } from "./Action"; import { Action, IActionParams } from "./Action";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
@@ -8,8 +9,8 @@ export interface IOperationParams extends IActionParams {
} }
export class Operation extends Action { export class Operation extends Action {
reqdRank: number = 100; reqdRank = 100;
teamCount: number = 0; teamCount = 0;
constructor(params: IOperationParams | null = null) { constructor(params: IOperationParams | null = null) {
super(params); super(params);
@@ -18,38 +19,39 @@ export class Operation extends Action {
} }
// For actions that have teams. To be implemented by subtypes. // For actions that have teams. To be implemented by subtypes.
getTeamSuccessBonus(inst: any): number { getTeamSuccessBonus(inst: IBladeburner): number {
if (this.teamCount && this.teamCount > 0) { if (this.teamCount && this.teamCount > 0) {
this.teamCount = Math.min(this.teamCount, inst.teamSize); 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 teamMultiplier;
} }
return 1; return 1;
} }
getActionTypeSkillSuccessBonus(inst: any): number { getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceOperation; return inst.skillMultipliers.successChanceOperation;
} }
getChaosDifficultyBonus(inst: any, params: any): number { getChaosDifficultyBonus(inst: IBladeburner/*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity(); const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) { if (city.chaos > BladeburnerConstants.ChaosThreshold) {
let diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold); const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
let mult = Math.pow(diff, 0.1); const mult = Math.pow(diff, 0.1);
return mult; return mult;
} }
return 1; return 1;
} }
static fromJSON(value: any): Operation {
return Generic_fromJSON(Operation, value.data);
}
toJSON(): any { toJSON(): any {
return Generic_toJSON("Operation", this); 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; Reviver.constructors.Operation = Operation;

View File

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

View File

@@ -10,55 +10,55 @@ export const Skills: IMap<Skill> = {};
desc:"Each level of this skill increases your success chance " + desc:"Each level of this skill increases your success chance " +
"for all Contracts, Operations, and BlackOps by 3%", "for all Contracts, Operations, and BlackOps by 3%",
baseCost: 3, costInc: 2.1, baseCost: 3, costInc: 2.1,
successChanceAll:3 successChanceAll:3,
}); });
Skills[SkillNames.Cloak] = new Skill({ Skills[SkillNames.Cloak] = new Skill({
name:SkillNames.Cloak, name:SkillNames.Cloak,
desc:"Each level of this skill increases your " + desc:"Each level of this skill increases your " +
"success chance in stealth-related Contracts, Operations, and BlackOps by 5.5%", "success chance in stealth-related Contracts, Operations, and BlackOps by 5.5%",
baseCost: 2, costInc: 1.1, baseCost: 2, costInc: 1.1,
successChanceStealth:5.5 successChanceStealth:5.5,
}); });
Skills[SkillNames.ShortCircuit] = new Skill({ Skills[SkillNames.ShortCircuit] = new Skill({
name:SkillNames.ShortCircuit, name:SkillNames.ShortCircuit,
desc:"Each level of this skill increases your success chance " + desc:"Each level of this skill increases your success chance " +
"in Contracts, Operations, and BlackOps that involve retirement by 5.5%", "in Contracts, Operations, and BlackOps that involve retirement by 5.5%",
baseCost: 2, costInc: 2.1, baseCost: 2, costInc: 2.1,
successChanceKill:5.5 successChanceKill:5.5,
}); });
Skills[SkillNames.DigitalObserver] = new Skill({ Skills[SkillNames.DigitalObserver] = new Skill({
name:SkillNames.DigitalObserver, name:SkillNames.DigitalObserver,
desc:"Each level of this skill increases your success chance in " + desc:"Each level of this skill increases your success chance in " +
"all Operations and BlackOps by 4%", "all Operations and BlackOps by 4%",
baseCost: 2, costInc: 2.1, baseCost: 2, costInc: 2.1,
successChanceOperation:4 successChanceOperation:4,
}); });
Skills[SkillNames.Tracer] = new Skill({ Skills[SkillNames.Tracer] = new Skill({
name:SkillNames.Tracer, name:SkillNames.Tracer,
desc:"Each level of this skill increases your success chance in " + desc:"Each level of this skill increases your success chance in " +
"all Contracts by 4%", "all Contracts by 4%",
baseCost: 2, costInc: 2.1, baseCost: 2, costInc: 2.1,
successChanceContract:4 successChanceContract:4,
}); });
Skills[SkillNames.Overclock] = new Skill({ Skills[SkillNames.Overclock] = new Skill({
name:SkillNames.Overclock, name:SkillNames.Overclock,
desc:"Each level of this skill decreases the time it takes " + desc:"Each level of this skill decreases the time it takes " +
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 90)", "to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 90)",
baseCost: 3, costInc: 1.4, maxLvl: 90, baseCost: 3, costInc: 1.4, maxLvl: 90,
actionTime:1 actionTime:1,
}); });
Skills[SkillNames.Reaper] = new Skill({ Skills[SkillNames.Reaper] = new Skill({
name: SkillNames.Reaper, name: SkillNames.Reaper,
desc: "Each level of this skill increases your effective combat stats for Bladeburner actions by 2%", desc: "Each level of this skill increases your effective combat stats for Bladeburner actions by 2%",
baseCost: 2, costInc: 2.1, 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({ Skills[SkillNames.EvasiveSystem] = new Skill({
name:SkillNames.EvasiveSystem, name:SkillNames.EvasiveSystem,
desc:"Each level of this skill increases your effective " + desc:"Each level of this skill increases your effective " +
"dexterity and agility for Bladeburner actions by 4%", "dexterity and agility for Bladeburner actions by 4%",
baseCost: 2, costInc: 2.1, baseCost: 2, costInc: 2.1,
effDex: 4, effAgi: 4 effDex: 4, effAgi: 4,
}); });
Skills[SkillNames.Datamancer] = new Skill({ Skills[SkillNames.Datamancer] = new Skill({
name:SkillNames.Datamancer, name:SkillNames.Datamancer,
@@ -67,13 +67,13 @@ export const Skills: IMap<Skill> = {};
"This affects all actions that can potentially increase " + "This affects all actions that can potentially increase " +
"the accuracy of your synthoid population/community estimates.", "the accuracy of your synthoid population/community estimates.",
baseCost:3, costInc:1, baseCost:3, costInc:1,
successChanceEstimate:5 successChanceEstimate:5,
}); });
Skills[SkillNames.CybersEdge] = new Skill({ Skills[SkillNames.CybersEdge] = new Skill({
name:SkillNames.CybersEdge, name:SkillNames.CybersEdge,
desc:"Each level of this skill increases your max stamina by 2%", desc:"Each level of this skill increases your max stamina by 2%",
baseCost:1, costInc:3, baseCost:1, costInc:3,
stamina:2 stamina:2,
}); });
Skills[SkillNames.HandsOfMidas] = new Skill({ Skills[SkillNames.HandsOfMidas] = new Skill({
name: SkillNames.HandsOfMidas, 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: [ helpList: [
"Use 'help [command]' to get more information about a particular Bladeburner console command.", "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", " log [en/dis] [type] Enable or disable logging for events and actions",
" skill [action] [name] Level or display info about your Bladeburner skills", " skill [action] [name] Level or display info about your Bladeburner skills",
" start [type] [name] Start a Bladeburner action/task" , " start [type] [name] Start a Bladeburner action/task" ,
" stop Stops your current Bladeburner action/task" " stop Stops your current Bladeburner action/task",
], ],
automate: [ automate: [
"automate [var] [val] [hi/low]", "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 " + "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 " + "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 " + "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: [
"clear", "clear",
"", "",
"Clears the console" "Clears the console",
], ],
cls: [ cls: [
"cls", "cls",
"", "",
"Clears the console" "Clears the console",
], ],
help: [ help: [
"help [command]", "help [command]",
@@ -51,7 +61,7 @@ export const ConsoleHelpText: {} = {
"", "",
" help automate", " help automate",
"", "",
"will display specific information about using the automate console command" "will display specific information about using the automate console command",
], ],
log: [ log: [
"log [en/dis] [type]", "log [en/dis] [type]",
@@ -71,7 +81,7 @@ export const ConsoleHelpText: {} = {
"Logging can be universally enabled/disabled using the 'all' keyword:", "Logging can be universally enabled/disabled using the 'all' keyword:",
"", "",
" log dis all", " log dis all",
" log en all" " log en all",
], ],
skill: [ skill: [
"skill [action] [name]", "skill [action] [name]",
@@ -91,7 +101,7 @@ export const ConsoleHelpText: {} = {
"", "",
"This console command can also be used to level up skills:", "This console command can also be used to level up skills:",
"", "",
" skill level [skill name]" " skill level [skill name]",
], ],
start: [ start: [
"start [type] [name]", "start [type] [name]",
@@ -106,11 +116,11 @@ export const ConsoleHelpText: {} = {
"Examples:", "Examples:",
"", "",
" start contract Tracking", " start contract Tracking",
" start op 'Undercover Operation'" " start op 'Undercover Operation'",
], ],
stop:[ stop:[
"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"; 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 // Put Black Operations in sequence of required rank
const blackops = []; const blackops = [];
for (const name in BlackOperations) { 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 /> 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 /> <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> 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 => {blackops.map(() => <div className="bladeburner-action">
<div className="bladeburner-action"> </div>,
</div>
)} )}
</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>
)
}

98
src/Casino/CoinFlip.tsx Normal file
View File

@@ -0,0 +1,98 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a gym
*
* This subcomponent renders all of the buttons for training at the gym
*/
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { BadRNG } from "./RNG";
import { Game } from "./Game";
import { trusted } from "./utils";
type IProps = {
p: IPlayer;
}
type IState = {
investment: number;
result: any;
status: string;
playLock: boolean;
}
const minPlay = 0;
const maxPlay = 10e3;
export class CoinFlip extends Game<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
investment: 1000,
result: <span> </span>,
status: '',
playLock: false,
};
this.play = this.play.bind(this);
this.updateInvestment = this.updateInvestment.bind(this);
}
updateInvestment(e: React.FormEvent<HTMLInputElement>): void {
let investment: number = parseInt(e.currentTarget.value);
if (isNaN(investment)) {
investment = minPlay;
}
if (investment > maxPlay) {
investment = maxPlay;
}
if (investment < minPlay) {
investment = minPlay;
}
this.setState({investment: investment});
}
play(guess: string): void {
if(this.reachedLimit(this.props.p)) return;
const v = BadRNG.random();
let letter: string;
if (v < 0.5) {
letter = 'H';
} else {
letter = 'T';
}
const correct: boolean = guess===letter;
this.setState({
result: <span className={correct ? "text" : "failure"}>{letter}</span>,
status: correct ? " win!" : "lose!",
playLock: true,
});
setTimeout(()=>this.setState({playLock: false}), 250);
if (correct) {
this.win(this.props.p, this.state.investment);
} else {
this.win(this.props.p, -this.state.investment);
}
if(this.reachedLimit(this.props.p)) return;
}
render(): React.ReactNode {
return <>
<pre>
++<br />
| | | |<br />
| | {this.state.result} | |<br />
| | | |<br />
++<br />
</pre>
<span className="text">Play for: </span><input type="number" className="text-input" onChange={this.updateInvestment} value={this.state.investment} /><br />
<StdButton onClick={trusted(() => this.play('H'))} text={"Head!"} disabled={this.state.playLock} />
<StdButton onClick={trusted(() => this.play('T'))} text={"Tail!"} disabled={this.state.playLock} />
<h1>{this.state.status}</h1>
</>
}
}

20
src/Casino/Game.tsx Normal file
View File

@@ -0,0 +1,20 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { dialogBoxCreate } from "../../utils/DialogBox";
const gainLimit = 10e9;
export class Game<T,U> extends React.Component<T, U> {
win(p: IPlayer, n: number): void{
p.gainMoney(n);
p.recordMoneySource(n, "casino");
}
reachedLimit(p: IPlayer): boolean {
const reached = p.getCasinoWinnings() > gainLimit;
if(reached) {
dialogBoxCreate(<>Alright cheater get out of here. You're not allowed here anymore.</>);
}
return reached;
}
}

64
src/Casino/RNG.ts Normal file
View File

@@ -0,0 +1,64 @@
export interface RNG {
random(): number;
}
/*
* very bad RNG, meant to be used as introduction to RNG manipulation. It has a
* period of 1024.
*/
class RNG0 implements RNG {
x: number;
m = 1024;
a = 341;
c = 1;
constructor() {
this.x = 0;
this.reset();
}
step(): void {
this.x = (this.a*this.x+this.c) % this.m;
}
random(): number {
this.step();
return this.x/this.m;
}
reset(): void {
this.x = (new Date()).getTime() % this.m;
}
}
export const BadRNG: RNG0 = new RNG0();
/*
* WichmannHill PRNG
* The period is 6e12.
*/
export class WHRNG implements RNG {
s1 = 0;
s2 = 0;
s3 = 0;
constructor(totalPlaytime: number) {
// This one is seeded by the players total play time.
const v: number = (totalPlaytime/1000)%30000;
this.s1 = v;
this.s2 = v;
this.s3 = v;
}
step(): void {
this.s1 = (171 * this.s1) % 30269;
this.s2 = (172 * this.s2) % 30307;
this.s3 = (170 * this.s3) % 30323;
}
random(): number {
this.step();
return (this.s1/30269.0 + this.s2/30307.0 + this.s3/30323.0)%1.0;
}
}

291
src/Casino/Roulette.tsx Normal file
View File

@@ -0,0 +1,291 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { Money } from "../ui/React/Money";
import { Game } from "./Game";
import { WHRNG } from "./RNG";
import { trusted } from "./utils";
type IProps = {
p: IPlayer;
}
type IState = {
investment: number;
canPlay: boolean;
status: string | JSX.Element;
n: number;
lock: boolean;
strategy: Strategy;
}
const minPlay = 0;
const maxPlay = 1e7;
function isRed(n: number): boolean {
return [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
21, 23, 25, 27, 30, 32, 34, 36].includes(n);
}
type Strategy = {
match: (n: number) => boolean;
payout: number;
}
const redNumbers: number[] = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
21, 23, 25, 27, 30, 32, 34, 36];
const strategies: {
Red: Strategy;
Black: Strategy;
Odd: Strategy;
Even: Strategy;
High: Strategy;
Low: Strategy;
Third1: Strategy;
Third2: Strategy;
Third3: Strategy;
} = {
Red: {
match: (n: number): boolean => {
if (n === 0) return false;
return redNumbers.includes(n);
},
payout: 1,
},
Black: {
match: (n: number): boolean => {
return !redNumbers.includes(n);
},
payout: 1,
},
Odd: {
match: (n: number): boolean => {
if (n === 0) return false;
return n%2 === 1;
},
payout: 1,
},
Even: {
match: (n: number): boolean => {
if (n === 0) return false;
return n%2 === 0;
},
payout: 1,
},
High: {
match: (n: number): boolean => {
if (n === 0) return false;
return n>18
},
payout: 1,
},
Low: {
match: (n: number): boolean => {
if (n === 0) return false;
return n<19;
},
payout: 1,
},
Third1: {
match: (n: number): boolean => {
if (n === 0) return false;
return n <= 12;
},
payout: 2,
},
Third2: {
match: (n: number): boolean => {
if (n === 0) return false;
return n >= 13 && n <= 24;
},
payout: 2,
},
Third3: {
match: (n: number): boolean => {
if (n === 0) return false;
return n >= 25;
},
payout: 2,
},
}
function Single(s: number): Strategy {
return {
match: (n: number): boolean => {
return s === n;
},
payout: 36,
}
}
export class Roulette extends Game<IProps, IState> {
interval = -1;
rng: WHRNG;
constructor(props: IProps) {
super(props);
this.rng = new WHRNG((new Date()).getTime());
this.state = {
investment: 1000,
canPlay: true,
status: 'waiting',
n: 0,
lock: true,
strategy: {
payout: 0,
match: (): boolean => { return false },
},
}
this.step = this.step.bind(this);
this.currentNumber = this.currentNumber.bind(this);
this.updateInvestment = this.updateInvestment.bind(this);
}
componentDidMount(): void {
this.interval = setInterval(this.step, 50);
}
step(): void {
if (!this.state.lock) {
this.setState({n: Math.floor(Math.random()*37)});
}
}
componentWillUnmount(): void {
clearInterval(this.interval);
}
updateInvestment(e: React.FormEvent<HTMLInputElement>): void {
let investment: number = parseInt(e.currentTarget.value);
if (isNaN(investment)) {
investment = minPlay;
}
if (investment > maxPlay) {
investment = maxPlay;
}
if (investment < minPlay) {
investment = minPlay;
}
this.setState({investment: investment});
}
currentNumber(): string {
if (this.state.n === 0) return '0';
const color = isRed(this.state.n) ? 'R' : 'B';
return `${this.state.n}${color}`;
}
play(s: Strategy): void {
if(this.reachedLimit(this.props.p)) return;
this.setState({
canPlay: false,
lock: false,
status: 'playing',
strategy: s,
})
setTimeout(() => {
let n = Math.floor(this.rng.random()*37);
let status = <></>;
let gain = 0;
let playerWin = this.state.strategy.match(n)
// oh yeah, the house straight up cheats. Try finding the seed now!
if(playerWin && Math.random() > 0.9) {
playerWin = false;
while(this.state.strategy.match(n)) {
n++;
}
}
if(playerWin) {
gain = this.state.investment*this.state.strategy.payout;
status = <>won {Money(gain)}</>;
} else {
gain = -this.state.investment;
status = <>lost {Money(-gain)}</>;
}
this.win(this.props.p, gain);
this.setState({
canPlay: true,
lock: true,
status: status,
n: n,
});
this.reachedLimit(this.props.p);
}, 1600);
}
render(): 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} />
<h1>{this.state.status}</h1>
<table>
<tbody>
<tr>
<td><StdButton text={"3"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(3)))} /></td>
<td><StdButton text={"6"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(6)))} /></td>
<td><StdButton text={"9"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(9)))} /></td>
<td><StdButton text={"12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(12)))} /></td>
<td><StdButton text={"15"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(15)))} /></td>
<td><StdButton text={"18"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(18)))} /></td>
<td><StdButton text={"21"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(21)))} /></td>
<td><StdButton text={"24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(24)))} /></td>
<td><StdButton text={"27"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(27)))} /></td>
<td><StdButton text={"30"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(30)))} /></td>
<td><StdButton text={"33"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(33)))} /></td>
<td><StdButton text={"36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(36)))} /></td>
</tr>
<tr>
<td><StdButton text={"2"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(2)))} /></td>
<td><StdButton text={"5"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(5)))} /></td>
<td><StdButton text={"8"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(8)))} /></td>
<td><StdButton text={"11"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(11)))} /></td>
<td><StdButton text={"14"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(14)))} /></td>
<td><StdButton text={"17"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(17)))} /></td>
<td><StdButton text={"20"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(20)))} /></td>
<td><StdButton text={"23"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(23)))} /></td>
<td><StdButton text={"26"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(26)))} /></td>
<td><StdButton text={"29"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(29)))} /></td>
<td><StdButton text={"32"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(32)))} /></td>
<td><StdButton text={"35"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(35)))} /></td>
</tr>
<tr>
<td><StdButton text={"1"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(1)))} /></td>
<td><StdButton text={"4"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(4)))} /></td>
<td><StdButton text={"7"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(7)))} /></td>
<td><StdButton text={"10"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(10)))} /></td>
<td><StdButton text={"13"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(13)))} /></td>
<td><StdButton text={"16"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(16)))} /></td>
<td><StdButton text={"19"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(19)))} /></td>
<td><StdButton text={"22"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(22)))} /></td>
<td><StdButton text={"25"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(25)))} /></td>
<td><StdButton text={"28"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(28)))} /></td>
<td><StdButton text={"31"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(31)))} /></td>
<td><StdButton text={"34"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(34)))} /></td>
</tr>
<tr>
<td colSpan={4}><StdButton text={"1 to 12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third1))} /></td>
<td colSpan={4}><StdButton text={"13 to 24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third2))} /></td>
<td colSpan={4}><StdButton text={"25 to 36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third3))} /></td>
</tr>
<tr>
<td colSpan={2}><StdButton text={"Red"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Red))} /></td>
<td colSpan={2}><StdButton text={"Black"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Black))} /></td>
<td colSpan={2}><StdButton text={"Odd"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Odd))} /></td>
<td colSpan={2}><StdButton text={"Even"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Even))} /></td>
<td colSpan={2}><StdButton text={"High"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.High))} /></td>
<td colSpan={2}><StdButton text={"Low"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Low))} /></td>
</tr>
<tr>
<td><StdButton text={"0"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(0)))} /></td>
</tr>
</tbody>
</table>
</>
}
}

239
src/Casino/SlotMachine.tsx Normal file
View File

@@ -0,0 +1,239 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { StdButton } from "../ui/React/StdButton";
import { Money } from "../ui/React/Money";
import { WHRNG } from "./RNG";
import { Game } from "./Game";
import { trusted } from "./utils";
type IProps = {
p: IPlayer;
}
type IState = {
index: number[];
locks: number[];
investment: number;
canPlay: boolean;
status: string | JSX.Element;
}
// statically shuffled array of symbols.
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", "?"];
function getPayout(s: string, n: number): number {
switch (s) {
case "$":
return [20, 200, 1000][n];
case "@":
return [8, 80, 400][n];
case "♥":
case "?":
return [6, 20, 150][n];
case "D":
case "E":
return [1, 8, 30][n];
default:
return [1, 5, 20][n];
}
}
const payLines = [
// lines
[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]],
[[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]],
[[2, 0], [2, 1], [2, 2], [2, 3], [2, 4]],
// Vs
[[2, 0], [1, 1], [0, 2], [1, 3], [2, 4]],
[[0, 0], [1, 1], [2, 2], [1, 3], [0, 4]],
// rest
[[0, 0], [1, 1], [1, 2], [1, 3], [0, 4]],
[[2, 0], [1, 1], [1, 2], [1, 3], [2, 4]],
[[1, 0], [0, 1], [0, 2], [0, 3], [1, 4]],
[[1, 0], [2, 1], [2, 2], [2, 3], [1, 4]],
];
const minPlay = 0;
const maxPlay = 1e6;
export class SlotMachine extends Game<IProps, IState> {
rng: WHRNG;
interval = -1;
constructor(props: IProps) {
super(props);
this.rng = new WHRNG(this.props.p.totalPlaytime);
this.state = {
index: [0, 0, 0, 0, 0],
investment: 1000,
locks: [0, 0, 0, 0, 0],
canPlay: true,
status: 'waiting',
};
this.play = this.play.bind(this);
this.lock = this.lock.bind(this);
this.unlock = this.unlock.bind(this);
this.step = this.step.bind(this);
this.checkWinnings = this.checkWinnings.bind(this);
this.getTable = this.getTable.bind(this);
this.updateInvestment = this.updateInvestment.bind(this);
}
componentDidMount(): void {
this.interval = setInterval(this.step, 50);
}
step(): void {
let stoppedOne = false;
const index = this.state.index.slice();
for(const i in index) {
if (index[i] === this.state.locks[i] && !stoppedOne) continue;
index[i] = (index[i] + 1) % symbols.length;
stoppedOne = true;
}
this.setState({index: index});
if(stoppedOne && index.every((e, i) => e === this.state.locks[i])) {
this.checkWinnings();
}
}
componentWillUnmount(): void {
clearInterval(this.interval);
}
getTable(): string[][] {
return [
[symbols[(this.state.index[0]+symbols.length-1)%symbols.length], symbols[(this.state.index[1]+symbols.length-1)%symbols.length], symbols[(this.state.index[2]+symbols.length-1)%symbols.length], symbols[(this.state.index[3]+symbols.length-1)%symbols.length], symbols[(this.state.index[4]+symbols.length-1)%symbols.length]],
[symbols[this.state.index[0]], symbols[this.state.index[1]], symbols[this.state.index[2]], symbols[this.state.index[3]], symbols[this.state.index[4]]],
[symbols[(this.state.index[0]+1)%symbols.length], symbols[(this.state.index[1]+1)%symbols.length], symbols[(this.state.index[2]+1)%symbols.length], symbols[(this.state.index[3]+1)%symbols.length], symbols[(this.state.index[4]+1)%symbols.length]],
];
}
play(): void {
if(this.reachedLimit(this.props.p)) return;
this.setState({status: 'playing'});
this.win(this.props.p, -this.state.investment);
if(!this.state.canPlay) return;
this.unlock();
setTimeout(this.lock, this.rng.random()*2000+1000);
}
lock(): void {
this.setState({
locks: [
Math.floor(this.rng.random()*symbols.length),
Math.floor(this.rng.random()*symbols.length),
Math.floor(this.rng.random()*symbols.length),
Math.floor(this.rng.random()*symbols.length),
Math.floor(this.rng.random()*symbols.length),
],
})
}
checkWinnings(): void {
const t = this.getTable();
const getPaylineData = function(payline: number[][]): string[] {
const data = [];
for(const point of payline) {
data.push(t[point[0]][point[1]]);
}
return data;
}
const countSequence = function(data: string[]): number {
let count = 1;
for(let i = 1; i < data.length; i++) {
if (data[i]!==data[i-1]) break;
count++;
}
return count;
}
let gains = -this.state.investment;
for (const payline of payLines) {
const data = getPaylineData(payline);
const count = countSequence(data);
if (count < 3) continue;
const payout = getPayout(data[0], count-3);
gains += this.state.investment*payout;
this.win(this.props.p, this.state.investment*payout);
}
this.setState({
status: <>{gains>0?"gained":"lost"} {Money(Math.abs(gains))}</>,
canPlay: true,
})
if(this.reachedLimit(this.props.p)) return;
}
unlock(): void {
this.setState({
locks: [-1, -1, -1, -1, -1],
canPlay: false,
})
}
updateInvestment(e: React.FormEvent<HTMLInputElement>): void {
let investment: number = parseInt(e.currentTarget.value);
if (isNaN(investment)) {
investment = minPlay;
}
if (investment > maxPlay) {
investment = maxPlay;
}
if (investment < minPlay) {
investment = minPlay;
}
this.setState({investment: investment});
}
render(): React.ReactNode {
const t = this.getTable();
return <>
<pre>
++<br />
| | {t[0][0]} | {t[0][1]} | {t[0][2]} | {t[0][3]} | {t[0][4]} | |<br />
| | | | | | | |<br />
| | {symbols[this.state.index[0]]} | {symbols[this.state.index[1]]} | {symbols[this.state.index[2]]} | {symbols[this.state.index[3]]} | {symbols[this.state.index[4]]} | |<br />
| | | | | | | |<br />
| | {symbols[(this.state.index[0]+1)%symbols.length]} | {symbols[(this.state.index[1]+1)%symbols.length]} | {symbols[(this.state.index[2]+1)%symbols.length]} | {symbols[(this.state.index[3]+1)%symbols.length]} | {symbols[(this.state.index[4]+1)%symbols.length]} | |<br />
++<br />
</pre>
<input type="number" className="text-input" onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
<StdButton onClick={trusted(this.play)} text={"Spin!"} disabled={!this.state.canPlay} />
<h1>{this.state.status}</h1>
<h2>Pay lines</h2>
<pre>
----- ····· ····· <br />
····· ----- ····· <br />
····· ····· ----- <br />
</pre>
<br />
<pre>
··^·· \···/ \···/<br />
·/·\· ·\·/· ·---·<br />
/···\ ··v·· ·····<br />
</pre>
<br />
<pre>
····· ·---· ·····<br />
·---· /···\ \···/<br />
/···\ ····· ·---·<br />
</pre>
</>
}
}
// https://felgo.com/doc/how-to-make-a-slot-game-tutorial/

8
src/Casino/utils.ts Normal file
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"); var mainMenu = document.getElementById("mainmenu-container");
container.appendChild(createElement("br")); container.appendChild(createElement("br"));
return new Promise (function(resolve, reject) { return new Promise (function(resolve) {
container.appendChild(createElement("a", { container.appendChild(createElement("a", {
class:"a-link-button", innerText:"Continue...", class:"a-link-button", innerText:"Continue...",
clickListener:()=>{ clickListener:()=>{
@@ -99,7 +99,7 @@ function cinematicTextEnd() {
mainMenu.style.visibility = "visible"; mainMenu.style.visibility = "visible";
cinematicTextFlag = false; cinematicTextFlag = false;
resolve(); resolve();
} },
})); }));
}); });
} }

View File

@@ -2,7 +2,7 @@ import {
CodingContract, CodingContract,
CodingContractRewardType, CodingContractRewardType,
CodingContractTypes, CodingContractTypes,
ICodingContractReward ICodingContractReward,
} from "./CodingContracts"; } from "./CodingContracts";
import { Factions } from "./Faction/Factions"; import { Factions } from "./Faction/Factions";
import { Player } from "./Player"; import { Player } from "./Player";
@@ -15,7 +15,7 @@ import { HacknetServer } from "./Hacknet/HacknetServer";
import { getRandomInt } from "../utils/helpers/getRandomInt"; import { getRandomInt } from "../utils/helpers/getRandomInt";
export function generateRandomContract() { export function generateRandomContract(): void {
// First select a random problem type // First select a random problem type
const problemType = getRandomProblemType(); const problemType = getRandomProblemType();
@@ -31,7 +31,7 @@ export function generateRandomContract() {
randServer.addContract(contract); randServer.addContract(contract);
} }
export function generateRandomContractOnHome() { export function generateRandomContractOnHome(): void {
// First select a random problem type // First select a random problem type
const problemType = getRandomProblemType(); const problemType = getRandomProblemType();
@@ -53,7 +53,7 @@ export interface IGenerateContractParams {
fn?: string; fn?: string;
} }
export function generateContract(params: IGenerateContractParams) { export function generateContract(params: IGenerateContractParams): void {
// Problem Type // Problem Type
let problemType; let problemType;
const problemTypes = Object.keys(CodingContractTypes); const problemTypes = Object.keys(CodingContractTypes);
@@ -88,7 +88,7 @@ export function generateContract(params: IGenerateContractParams) {
fn = getRandomFilename(server, reward); fn = getRandomFilename(server, reward);
} }
let contract = new CodingContract(fn, problemType, reward); const contract = new CodingContract(fn, problemType, reward);
server.addContract(contract); server.addContract(contract);
} }
@@ -117,15 +117,15 @@ function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContrac
return type; return type;
} }
function getRandomProblemType() { function getRandomProblemType(): string {
const problemTypes = Object.keys(CodingContractTypes); const problemTypes = Object.keys(CodingContractTypes);
let randIndex = getRandomInt(0, problemTypes.length - 1); const randIndex = getRandomInt(0, problemTypes.length - 1);
return problemTypes[randIndex]; return problemTypes[randIndex];
} }
function getRandomReward(): ICodingContractReward { function getRandomReward(): ICodingContractReward {
let reward: ICodingContractReward = { const reward: ICodingContractReward = {
name: "", name: "",
type: getRandomInt(0, CodingContractRewardType.Money), type: getRandomInt(0, CodingContractRewardType.Money),
}; };
@@ -145,8 +145,8 @@ function getRandomReward(): ICodingContractReward {
case CodingContractRewardType.FactionReputation: { case CodingContractRewardType.FactionReputation: {
// Get a random faction that player is a part of. That // Get a random faction that player is a part of. That
// faction must allow hacking contracts // faction must allow hacking contracts
var numFactions = factionsThatAllowHacking.length; const numFactions = factionsThatAllowHacking.length;
var randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)]; const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
reward.name = randFaction; reward.name = randFaction;
break; break;
} }

View File

@@ -2,7 +2,7 @@ import {
codingContractTypesMetadata, codingContractTypesMetadata,
DescriptionFunc, DescriptionFunc,
GeneratorFunc, GeneratorFunc,
SolverFunc SolverFunc,
} from "./data/codingcontracttypes"; } from "./data/codingcontracttypes";
import { IMap } from "./types"; import { IMap } from "./types";
@@ -10,7 +10,7 @@ import { IMap } from "./types";
import { import {
Generic_fromJSON, Generic_fromJSON,
Generic_toJSON, Generic_toJSON,
Reviver Reviver,
} from "../utils/JSONReviver"; } from "../utils/JSONReviver";
import { KEY } from "../utils/helpers/keyCodes"; import { KEY } from "../utils/helpers/keyCodes";
import { createElement } from "../utils/uiHelpers/createElement"; import { createElement } from "../utils/uiHelpers/createElement";
@@ -108,12 +108,6 @@ export interface ICodingContractReward {
* The player receives a reward if the problem is solved correctly * The player receives a reward if the problem is solved correctly
*/ */
export class CodingContract { export class CodingContract {
/**
* Initiatizes a CodingContract from a JSON save state.
*/
static fromJSON(value: any): CodingContract {
return Generic_fromJSON(CodingContract, value.data);
}
/* Relevant data for the contract's problem */ /* Relevant data for the contract's problem */
data: any; data: any;
@@ -126,13 +120,13 @@ export class CodingContract {
reward: ICodingContractReward | null; reward: ICodingContractReward | null;
/* Number of times the Contract has been attempted */ /* Number of times the Contract has been attempted */
tries: number = 0; tries = 0;
/* String representing the contract's type. Must match type in ContractTypes */ /* String representing the contract's type. Must match type in ContractTypes */
type: string; type: string;
constructor(fn: string = "", constructor(fn = "",
type: string = "Find Largest Prime Factor", type = "Find Largest Prime Factor",
reward: ICodingContractReward | null = null) { reward: ICodingContractReward | null = null) {
this.fn = fn; this.fn = fn;
if (!this.fn.endsWith(".cct")) { if (!this.fn.endsWith(".cct")) {
@@ -178,19 +172,28 @@ export class CodingContract {
*/ */
async prompt(): Promise<CodingContractResult> { async prompt(): Promise<CodingContractResult> {
// tslint:disable-next-line // tslint:disable-next-line
return new Promise<CodingContractResult>((resolve: Function, reject: Function) => { return new Promise<CodingContractResult>((resolve) => {
const contractType: CodingContractType = CodingContractTypes[this.type]; const contractType: CodingContractType = CodingContractTypes[this.type];
const popupId: string = `coding-contract-prompt-popup-${this.fn}`; const popupId = `coding-contract-prompt-popup-${this.fn}`;
const title: HTMLElement = createElement("h1", {
innerHTML: this.type,
});
const txt: HTMLElement = createElement("p", { const txt: HTMLElement = createElement("p", {
innerHTML: ["You are attempting to solve a Coding Contract. You have", innerHTML: ["You are attempting to solve a Coding Contract. You have",
`${this.getMaxNumTries() - this.tries} tries remaining,`, `${this.getMaxNumTries() - this.tries} tries remaining,`,
"after which the contract will self-destruct.<br><br>", "after which the contract will self-destruct.<br><br>",
`${contractType.desc(this.data).replace(/\n/g, "<br>")}`].join(" "), `${contractType.desc(this.data).replace(/\n/g, "<br>")}`].join(" "),
}); });
let answerInput: HTMLInputElement;
let solveBtn: HTMLElement; let solveBtn: HTMLElement;
let cancelBtn: HTMLElement; const cancelBtn = createElement("a", {
answerInput = createElement("input", { class: "a-link-button",
clickListener: () => {
resolve(CodingContractResult.Cancelled);
removeElementById(popupId);
},
innerText: "Cancel",
});
const answerInput = createElement("input", {
onkeydown: (e: any) => { onkeydown: (e: any) => {
if (e.keyCode === KEY.ENTER && answerInput.value !== "") { if (e.keyCode === KEY.ENTER && answerInput.value !== "") {
e.preventDefault(); e.preventDefault();
@@ -216,16 +219,8 @@ export class CodingContract {
}, },
innerText: "Solve", innerText: "Solve",
}); });
cancelBtn = createElement("a", {
class: "a-link-button",
clickListener: () => {
resolve(CodingContractResult.Cancelled);
removeElementById(popupId);
},
innerText: "Cancel",
});
const lineBreak: HTMLElement = createElement("br"); const lineBreak: HTMLElement = createElement("br");
createPopup(popupId, [txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]); createPopup(popupId, [title, lineBreak, txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
answerInput.focus(); answerInput.focus();
}); });
} }
@@ -236,6 +231,14 @@ export class CodingContract {
toJSON(): any { toJSON(): any {
return Generic_toJSON("CodingContract", this); return Generic_toJSON("CodingContract", this);
} }
/**
* Initiatizes a CodingContract from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): CodingContract {
return Generic_fromJSON(CodingContract, value.data);
}
} }
Reviver.constructors.CodingContract = CodingContract; Reviver.constructors.CodingContract = CodingContract;

View File

@@ -6,7 +6,7 @@ import { Reviver } from "../../utils/JSONReviver";
export let Companies: IMap<Company> = {}; export let Companies: IMap<Company> = {};
function addCompany(params: IConstructorParams) { function addCompany(params: IConstructorParams): void {
if (Companies[params.name] != null) { if (Companies[params.name] != null) {
console.warn(`Duplicate Company Position being defined: ${params.name}`); console.warn(`Duplicate Company Position being defined: ${params.name}`);
} }
@@ -15,7 +15,7 @@ function addCompany(params: IConstructorParams) {
// Used to initialize new Company objects for the Companies map // Used to initialize new Company objects for the Companies map
// Called when creating new game or after a prestige/reset // Called when creating new game or after a prestige/reset
export function initCompanies() { export function initCompanies(): void {
// Save Old Company data for 'favor' // Save Old Company data for 'favor'
const oldCompanies = Companies; const oldCompanies = Companies;
@@ -40,11 +40,11 @@ export function initCompanies() {
} }
// Used to load Companies map from a save // Used to load Companies map from a save
export function loadCompanies(saveString: string) { export function loadCompanies(saveString: string): void {
Companies = JSON.parse(saveString, Reviver); Companies = JSON.parse(saveString, Reviver);
} }
// Utility function to check if a string is valid company name // Utility function to check if a string is valid company name
export function companyExists(name: string) { export function companyExists(name: string): boolean {
return Companies.hasOwnProperty(name); return Companies.hasOwnProperty(name);
} }

View File

@@ -25,12 +25,6 @@ const DefaultConstructorParams: IConstructorParams = {
} }
export class Company { export class Company {
/**
* Initiatizes a Company from a JSON save state.
*/
static fromJSON(value: any): Company {
return Generic_fromJSON(Company, value.data);
}
/** /**
* Company name * Company name
@@ -136,7 +130,7 @@ export class Company {
gainFavor(): void { gainFavor(): void {
if (this.favor == null) { this.favor = 0; } if (this.favor == null) { this.favor = 0; }
if (this.rolloverRep == null) { this.rolloverRep = 0; } if (this.rolloverRep == null) { this.rolloverRep = 0; }
var res = this.getFavorGain(); const res = this.getFavorGain();
if (res.length != 2) { if (res.length != 2) {
console.error("Invalid result from getFavorGain() function"); console.error("Invalid result from getFavorGain() function");
return; return;
@@ -170,6 +164,14 @@ export class Company {
toJSON(): any { toJSON(): any {
return Generic_toJSON("Company", this); return Generic_toJSON("Company", this);
} }
/**
* Initiatizes a Company from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Company {
return Generic_fromJSON(Company, value.data);
}
} }
Reviver.constructors.Company = Company; Reviver.constructors.Company = Company;

View File

@@ -5,7 +5,7 @@ import { IMap } from "../types";
export const CompanyPositions: IMap<CompanyPosition> = {}; export const CompanyPositions: IMap<CompanyPosition> = {};
function addCompanyPosition(params: IConstructorParams) { function addCompanyPosition(params: IConstructorParams): void {
if (CompanyPositions[params.name] != null) { if (CompanyPositions[params.name] != null) {
console.warn(`Duplicate Company Position being defined: ${params.name}`); console.warn(`Duplicate Company Position being defined: ${params.name}`);
} }

View File

@@ -5,8 +5,8 @@ import { CompanyPosition } from "./CompanyPosition";
* Returns a string with the given CompanyPosition's stat requirements * Returns a string with the given CompanyPosition's stat requirements
*/ */
export function getJobRequirementText(company: Company, pos: CompanyPosition, tooltiptext: boolean = false): string { export function getJobRequirementText(company: Company, pos: CompanyPosition, tooltiptext = false): string {
let reqText: string = ""; let reqText = "";
const offset: number = company.jobStatReqOffset; const offset: number = company.jobStatReqOffset;
const reqHacking: number = pos.requiredHacking > 0 ? pos.requiredHacking+offset : 0; const reqHacking: number = pos.requiredHacking > 0 ? pos.requiredHacking+offset : 0;
const reqStrength: number = pos.requiredStrength > 0 ? pos.requiredStrength+offset : 0; const reqStrength: number = pos.requiredStrength > 0 ? pos.requiredStrength+offset : 0;

View File

@@ -95,7 +95,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 3, expMultiplier: 3,
salaryMultiplier: 3, salaryMultiplier: 3,
@@ -107,7 +107,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 3, expMultiplier: 3,
salaryMultiplier: 3, salaryMultiplier: 3,
@@ -119,7 +119,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.6, expMultiplier: 2.6,
salaryMultiplier: 2.6, salaryMultiplier: 2.6,
@@ -131,7 +131,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.75, expMultiplier: 2.75,
salaryMultiplier: 2.75, salaryMultiplier: 2.75,
@@ -143,7 +143,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.75, expMultiplier: 2.75,
salaryMultiplier: 2.75, salaryMultiplier: 2.75,
@@ -155,7 +155,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.25, expMultiplier: 2.25,
salaryMultiplier: 2.25, salaryMultiplier: 2.25,
@@ -167,7 +167,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.25, expMultiplier: 2.25,
salaryMultiplier: 2.25, salaryMultiplier: 2.25,
@@ -179,7 +179,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.5, expMultiplier: 2.5,
salaryMultiplier: 2.5, salaryMultiplier: 2.5,
@@ -191,7 +191,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 2.2, expMultiplier: 2.2,
salaryMultiplier: 2.2, salaryMultiplier: 2.2,
@@ -202,7 +202,7 @@ export const companiesMetadata: IConstructorParams[] = [
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions AllBusinessPositions,
), ),
expMultiplier: 2, expMultiplier: 2,
salaryMultiplier: 2, salaryMultiplier: 2,
@@ -214,7 +214,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllSoftwareConsultantPositions, AllSoftwareConsultantPositions,
AllBusinessPositions AllBusinessPositions,
), ),
expMultiplier: 1.8, expMultiplier: 1.8,
salaryMultiplier: 1.8, salaryMultiplier: 1.8,
@@ -226,7 +226,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
CEOOnly, CEOOnly,
AllTechnologyPositions, AllTechnologyPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.75, expMultiplier: 1.75,
salaryMultiplier: 1.75, salaryMultiplier: 1.75,
@@ -238,7 +238,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
CEOOnly, CEOOnly,
AllTechnologyPositions, AllTechnologyPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.8, expMultiplier: 1.8,
salaryMultiplier: 1.8, salaryMultiplier: 1.8,
@@ -250,7 +250,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.8, expMultiplier: 1.8,
salaryMultiplier: 1.8, salaryMultiplier: 1.8,
@@ -262,7 +262,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.9, expMultiplier: 1.9,
salaryMultiplier: 1.9, salaryMultiplier: 1.9,
@@ -274,7 +274,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 2, expMultiplier: 2,
salaryMultiplier: 2, salaryMultiplier: 2,
@@ -286,7 +286,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.9, expMultiplier: 1.9,
salaryMultiplier: 1.9, salaryMultiplier: 1.9,
@@ -299,7 +299,7 @@ export const companiesMetadata: IConstructorParams[] = [
CEOOnly, CEOOnly,
OperationsManagerOnly, OperationsManagerOnly,
AllTechnologyPositions, AllTechnologyPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 1.7, expMultiplier: 1.7,
salaryMultiplier: 1.7, salaryMultiplier: 1.7,
@@ -351,7 +351,7 @@ export const companiesMetadata: IConstructorParams[] = [
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSoftwareConsultantPositions, AllSoftwareConsultantPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 1.8, expMultiplier: 1.8,
salaryMultiplier: 1.8, salaryMultiplier: 1.8,
@@ -364,7 +364,7 @@ export const companiesMetadata: IConstructorParams[] = [
AllTechnologyPositions, AllTechnologyPositions,
AllBusinessPositions, AllBusinessPositions,
AllSoftwareConsultantPositions, AllSoftwareConsultantPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 1.75, expMultiplier: 1.75,
salaryMultiplier: 1.75, salaryMultiplier: 1.75,
@@ -379,7 +379,7 @@ export const companiesMetadata: IConstructorParams[] = [
SecurityEngineerPositions, SecurityEngineerPositions,
AllITPositions, AllITPositions,
AllSecurityPositions, AllSecurityPositions,
AllAgentPositions AllAgentPositions,
), ),
expMultiplier: 2, expMultiplier: 2,
salaryMultiplier: 2, salaryMultiplier: 2,
@@ -394,7 +394,7 @@ export const companiesMetadata: IConstructorParams[] = [
SecurityEngineerPositions, SecurityEngineerPositions,
AllITPositions, AllITPositions,
AllSecurityPositions, AllSecurityPositions,
AllAgentPositions AllAgentPositions,
), ),
expMultiplier: 2, expMultiplier: 2,
salaryMultiplier: 2, salaryMultiplier: 2,
@@ -409,7 +409,7 @@ export const companiesMetadata: IConstructorParams[] = [
AllITPositions, AllITPositions,
AllSecurityPositions, AllSecurityPositions,
AllAgentPositions, AllAgentPositions,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.5, expMultiplier: 1.5,
salaryMultiplier: 1.5, salaryMultiplier: 1.5,
@@ -422,7 +422,7 @@ export const companiesMetadata: IConstructorParams[] = [
AllTechnologyPositions, AllTechnologyPositions,
AllSoftwareConsultantPositions, AllSoftwareConsultantPositions,
AllBusinessPositions, AllBusinessPositions,
AllSecurityPositions AllSecurityPositions,
), ),
expMultiplier: 1.4, expMultiplier: 1.4,
salaryMultiplier: 1.4, salaryMultiplier: 1.4,
@@ -433,7 +433,7 @@ export const companiesMetadata: IConstructorParams[] = [
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
SoftwarePositionsUpToLeadDeveloper, SoftwarePositionsUpToLeadDeveloper,
BusinessPositionsUpToOperationsManager BusinessPositionsUpToOperationsManager,
), ),
expMultiplier: 1.3, expMultiplier: 1.3,
salaryMultiplier: 1.3, salaryMultiplier: 1.3,
@@ -445,7 +445,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
SoftwarePositionsUpToLeadDeveloper, SoftwarePositionsUpToLeadDeveloper,
BusinessPositionsUpToOperationsManager, BusinessPositionsUpToOperationsManager,
AllSoftwareConsultantPositions AllSoftwareConsultantPositions,
), ),
expMultiplier: 1.5, expMultiplier: 1.5,
salaryMultiplier: 1.5, salaryMultiplier: 1.5,
@@ -456,7 +456,7 @@ export const companiesMetadata: IConstructorParams[] = [
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllSecurityPositions, AllSecurityPositions,
SoftwarePositionsUpToLeadDeveloper SoftwarePositionsUpToLeadDeveloper,
), ),
expMultiplier: 1.3, expMultiplier: 1.3,
salaryMultiplier: 1.3, salaryMultiplier: 1.3,
@@ -466,7 +466,7 @@ export const companiesMetadata: IConstructorParams[] = [
name: LocationName.VolhavenSysCoreSecurities, name: LocationName.VolhavenSysCoreSecurities,
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions AllTechnologyPositions,
), ),
expMultiplier: 1.3, expMultiplier: 1.3,
salaryMultiplier: 1.3, salaryMultiplier: 1.3,
@@ -476,7 +476,7 @@ export const companiesMetadata: IConstructorParams[] = [
name: LocationName.VolhavenCompuTek, name: LocationName.VolhavenCompuTek,
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions AllTechnologyPositions,
), ),
expMultiplier: 1.2, expMultiplier: 1.2,
salaryMultiplier: 1.2, salaryMultiplier: 1.2,
@@ -486,7 +486,7 @@ export const companiesMetadata: IConstructorParams[] = [
name: LocationName.AevumNetLinkTechnologies, name: LocationName.AevumNetLinkTechnologies,
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllTechnologyPositions AllTechnologyPositions,
), ),
expMultiplier: 1.2, expMultiplier: 1.2,
salaryMultiplier: 1.2, salaryMultiplier: 1.2,
@@ -509,7 +509,7 @@ export const companiesMetadata: IConstructorParams[] = [
name: LocationName.Sector12FoodNStuff, name: LocationName.Sector12FoodNStuff,
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
EmployeeOnly, PartTimeEmployeeOnly EmployeeOnly, PartTimeEmployeeOnly,
), ),
expMultiplier: 1, expMultiplier: 1,
salaryMultiplier: 1, salaryMultiplier: 1,
@@ -519,7 +519,7 @@ export const companiesMetadata: IConstructorParams[] = [
name: LocationName.Sector12JoesGuns, name: LocationName.Sector12JoesGuns,
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
EmployeeOnly, PartTimeEmployeeOnly EmployeeOnly, PartTimeEmployeeOnly,
), ),
expMultiplier: 1, expMultiplier: 1,
salaryMultiplier: 1, salaryMultiplier: 1,
@@ -531,7 +531,7 @@ export const companiesMetadata: IConstructorParams[] = [
companyPositions: Object.assign({}, companyPositions: Object.assign({},
AllSoftwarePositions, AllSoftwarePositions,
AllSoftwareConsultantPositions, AllSoftwareConsultantPositions,
AllITPositions AllITPositions,
), ),
expMultiplier: 1.1, expMultiplier: 1.1,
salaryMultiplier: 1.1, salaryMultiplier: 1.1,
@@ -541,7 +541,7 @@ export const companiesMetadata: IConstructorParams[] = [
name: LocationName.NewTokyoNoodleBar, name: LocationName.NewTokyoNoodleBar,
info: "", info: "",
companyPositions: Object.assign({}, companyPositions: Object.assign({},
WaiterOnly, PartTimeWaiterOnly WaiterOnly, PartTimeWaiterOnly,
), ),
expMultiplier: 1, expMultiplier: 1,
salaryMultiplier: 1, salaryMultiplier: 1,

View File

@@ -8,23 +8,23 @@ export const SoftwareCompanyPositions: string[] = [
"Head of Software", "Head of Software",
"Head of Engineering", "Head of Engineering",
"Vice President of Technology", "Vice President of Technology",
"Chief Technology Officer" "Chief Technology Officer",
]; ];
export const ITCompanyPositions: string[] = [ export const ITCompanyPositions: string[] = [
"IT Intern", "IT Intern",
"IT Analyst", "IT Analyst",
"IT Manager", "IT Manager",
"Systems Administrator" "Systems Administrator",
]; ];
export const SecurityEngineerCompanyPositions: string[] = [ export const SecurityEngineerCompanyPositions: string[] = [
"Security Engineer" "Security Engineer",
]; ];
export const NetworkEngineerCompanyPositions: string[] = [ export const NetworkEngineerCompanyPositions: string[] = [
"Network Engineer", "Network Engineer",
"Network Administrator" "Network Administrator",
]; ];
export const BusinessCompanyPositions: string[] = [ export const BusinessCompanyPositions: string[] = [
@@ -33,7 +33,7 @@ export const BusinessCompanyPositions: string[] = [
"Business Manager", "Business Manager",
"Operations Manager", "Operations Manager",
"Chief Financial Officer", "Chief Financial Officer",
"Chief Executive Officer" "Chief Executive Officer",
]; ];
export const SecurityCompanyPositions: string[] = [ export const SecurityCompanyPositions: string[] = [
@@ -42,31 +42,31 @@ export const SecurityCompanyPositions: string[] = [
"Security Guard", "Security Guard",
"Security Officer", "Security Officer",
"Security Supervisor", "Security Supervisor",
"Head of Security" "Head of Security",
]; ];
export const AgentCompanyPositions: string[] = [ export const AgentCompanyPositions: string[] = [
"Field Agent", "Field Agent",
"Secret Agent", "Secret Agent",
"Special Operative" "Special Operative",
]; ];
export const MiscCompanyPositions: string[] = [ export const MiscCompanyPositions: string[] = [
"Waiter", "Waiter",
"Employee" "Employee",
]; ];
export const SoftwareConsultantCompanyPositions: string[] = [ export const SoftwareConsultantCompanyPositions: string[] = [
"Software Consultant", "Software Consultant",
"Senior Software Consultant" "Senior Software Consultant",
]; ];
export const BusinessConsultantCompanyPositions: string[] = [ export const BusinessConsultantCompanyPositions: string[] = [
"Business Consultant", "Business Consultant",
"Senior Business Consultant" "Senior Business Consultant",
]; ];
export const PartTimeCompanyPositions: string[] = [ export const PartTimeCompanyPositions: string[] = [
"Part-time Waiter", "Part-time Waiter",
"Part-time Employee" "Part-time Employee",
]; ];

View File

@@ -5,14 +5,14 @@
*/ */
import { IMap } from "./types"; import { IMap } from "./types";
export let CONSTANTS: IMap<any> = { export const CONSTANTS: IMap<any> = {
Version: "0.51.0", Version: "0.51.7",
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience /** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then * and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
* the player will have this level assuming no multipliers. Multipliers can cause skills to go above this. * the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
*/ */
MaxSkillLevel: 975, MaxSkillLevel: 975,
// Milliseconds per game cycle // Milliseconds per game cycle
MilliPerCycle: 200, MilliPerCycle: 200,
@@ -218,7 +218,7 @@ export let CONSTANTS: IMap<any> = {
CrimeHeist: "pull off the ultimate heist", CrimeHeist: "pull off the ultimate heist",
// Coding Contract // Coding Contract
// TODO Move this into Coding contract impelmentation? // TODO: Move this into Coding contract implementation?
CodingContractBaseFactionRepGain: 2500, CodingContractBaseFactionRepGain: 2500,
CodingContractBaseCompanyRepGain: 4000, CodingContractBaseCompanyRepGain: 4000,
CodingContractBaseMoneyGain: 75e6, CodingContractBaseMoneyGain: 75e6,
@@ -228,25 +228,61 @@ export let CONSTANTS: IMap<any> = {
LatestUpdate: LatestUpdate:
` `
v0.51.0 - 2021-03-31 Formulas (hydroflame) v0.51.7 - 2021-04-28 n00dles
------- -------
Formulas API Tutorial servers
* A new API is introduced, this gives players access to various formulas used in the game.
It'll help you make more informed decisions. * 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 Netscript
* 'getServer' is a new function meant to be used with the formulas API.
* 'getPlayer' is a new function meant to be used with the formulas API.
* 'getStats' and 'getCharacterInformation' are deprecated in favor of 'getPlayer'
* 'getCurrentServer' is a new function that returns the server the player is currently connected.
Display * Deprecated 'getServerRam'.
* All money should now consistently be orange. * 'getServerMaxRam' added to replace 'getServerRam'
* All rep should now consistently be light-yellow. * 'getServerUsedRam' added to replace 'getServerRam'
* Most numbers should display consistently now (aka all money is formatted the same). * '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.
Click to copy Donation
* Certain UI elements are now 'click-to-copy'
` * 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.
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"
`,
}

View File

@@ -5,7 +5,6 @@ import { CorporationUpgrades } from "./data/Corporation
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
import { Industries, import { Industries,
IndustryStartingCosts, IndustryStartingCosts,
IndustryDescriptions,
IndustryResearchTrees } from "./IndustryData"; IndustryResearchTrees } from "./IndustryData";
import { IndustryUpgrades } from "./IndustryUpgrades"; import { IndustryUpgrades } from "./IndustryUpgrades";
import { Material } from "./Material"; import { Material } from "./Material";
@@ -15,11 +14,8 @@ import { ResearchMap } from "./ResearchMap";
import { Warehouse } from "./Warehouse"; import { Warehouse } from "./Warehouse";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { Factions } from "../Faction/Factions";
import { showLiterature } from "../Literature/LiteratureHelpers"; import { showLiterature } from "../Literature/LiteratureHelpers";
import { LiteratureNames } from "../Literature/data/LiteratureNames"; import { LiteratureNames } from "../Literature/data/LiteratureNames";
import { createCityMap } from "../Locations/Cities";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
import { Player } from "../Player"; import { Player } from "../Player";
@@ -29,7 +25,6 @@ import { Page, routing } from "../ui/navigationTr
import { calculateEffectWithFactors } from "../utils/calculateEffectWithFactors"; import { calculateEffectWithFactors } from "../utils/calculateEffectWithFactors";
import { dialogBoxCreate } from "../../utils/DialogBox"; import { dialogBoxCreate } from "../../utils/DialogBox";
import { clearSelector } from "../../utils/uiHelpers/clearSelector";
import { Reviver, import { Reviver,
Generic_toJSON, Generic_toJSON,
Generic_fromJSON } from "../../utils/JSONReviver"; Generic_fromJSON } from "../../utils/JSONReviver";
@@ -99,7 +94,6 @@ export const BaseMaxProducts = 3; // Initial value for maximum
let researchTreeBoxOpened = false; let researchTreeBoxOpened = false;
let researchTreeBox = null; let researchTreeBox = null;
$(document).mousedown(function(event) { $(document).mousedown(function(event) {
const boxId = "corporation-research-popup-box";
const contentId = "corporation-research-popup-box-content"; const contentId = "corporation-research-popup-box-content";
if (researchTreeBoxOpened) { if (researchTreeBoxOpened) {
if ( $(event.target).closest("#" + contentId).get(0) == null ) { if ( $(event.target).closest("#" + contentId).get(0) == null ) {
@@ -111,7 +105,6 @@ $(document).mousedown(function(event) {
} }
}); });
var empManualAssignmentModeActive = false;
function Industry(params={}) { function Industry(params={}) {
this.offices = { //Maps locations to offices. 0 if no office at that location this.offices = { //Maps locations to offices. 0 if no office at that location
[CityName.Aevum]: 0, [CityName.Aevum]: 0,
@@ -122,7 +115,7 @@ function Industry(params={}) {
}), }),
[CityName.NewTokyo]: 0, [CityName.NewTokyo]: 0,
[CityName.Ishima]: 0, [CityName.Ishima]: 0,
[CityName.Volhaven]: 0 [CityName.Volhaven]: 0,
}; };
this.name = params.name ? params.name : 0; this.name = params.name ? params.name : 0;
@@ -183,7 +176,7 @@ function Industry(params={}) {
}), }),
[CityName.NewTokyo]: 0, [CityName.NewTokyo]: 0,
[CityName.Ishima]: 0, [CityName.Ishima]: 0,
[CityName.Volhaven]: 0 [CityName.Volhaven]: 0,
}; };
this.init(); this.init();
@@ -378,7 +371,7 @@ Industry.prototype.init = function() {
"Metal": 5, "Metal": 5,
"Energy": 5, "Energy": 5,
"Water": 2, "Water": 2,
"Hardware": 4 "Hardware": 4,
} }
this.prodMats = ["RealEstate"]; this.prodMats = ["RealEstate"];
this.makesProducts = true; this.makesProducts = true;
@@ -441,8 +434,7 @@ Industry.prototype.calculateProductionFactors = function() {
continue; continue;
} }
var materials = warehouse.materials, var materials = warehouse.materials;
office = this.offices[city];
var cityMult = Math.pow(0.002 * materials.RealEstate.qty+1, this.reFac) * var cityMult = Math.pow(0.002 * materials.RealEstate.qty+1, this.reFac) *
Math.pow(0.002 * materials.Hardware.qty+1, this.hwFac) * Math.pow(0.002 * materials.Hardware.qty+1, this.hwFac) *
@@ -535,7 +527,7 @@ Industry.prototype.process = function(marketCycles=1, state, company) {
} }
// Process change in demand and competition for this industry's materials // Process change in demand and competition for this industry's materials
Industry.prototype.processMaterialMarket = function(marketCycles=1) { Industry.prototype.processMaterialMarket = function() {
//References to prodMats and reqMats //References to prodMats and reqMats
var reqMats = this.reqMats, prodMats = this.prodMats; var reqMats = this.reqMats, prodMats = this.prodMats;
@@ -589,7 +581,7 @@ Industry.prototype.processProductMarket = function(marketCycles=1) {
//Process production, purchase, and import/export of materials //Process production, purchase, and import/export of materials
Industry.prototype.processMaterials = function(marketCycles=1, company) { Industry.prototype.processMaterials = function(marketCycles=1, company) {
var revenue = 0, expenses = 0, industry = this; var revenue = 0, expenses = 0;
this.calculateProductionFactors(); this.calculateProductionFactors();
//At the start of the export state, set the imports of everything to 0 //At the start of the export state, set the imports of everything to 0
@@ -642,7 +634,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
mat.qty += buyAmt; mat.qty += buyAmt;
expenses += (buyAmt * mat.bCost); expenses += (buyAmt * mat.bCost);
} }
})(matName, industry); })(matName, this);
this.updateWarehouseSizeUsed(warehouse); this.updateWarehouseSizeUsed(warehouse);
} }
} //End process purchase of materials } //End process purchase of materials
@@ -1003,7 +995,7 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
if (warehouse instanceof Warehouse) { if (warehouse instanceof Warehouse) {
switch(this.state) { switch(this.state) {
case "PRODUCTION": case "PRODUCTION": {
//Calculate the maximum production of this material based //Calculate the maximum production of this material based
//on the office's productivity //on the office's productivity
var maxProd = this.getOfficeProductivity(office, {forProduct:true}) var maxProd = this.getOfficeProductivity(office, {forProduct:true})
@@ -1065,8 +1057,8 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
//Keep track of production Per second //Keep track of production Per second
product.data[city][1] = prod * producableFrac / (SecsPerMarketCycle * marketCycles); product.data[city][1] = prod * producableFrac / (SecsPerMarketCycle * marketCycles);
break; break;
}
case "SALE": case "SALE": {
//Process sale of Products //Process sale of Products
product.pCost = 0; //Estimated production cost product.pCost = 0; //Estimated production cost
for (var reqMatName in product.reqMats) { for (var reqMatName in product.reqMats) {
@@ -1174,7 +1166,7 @@ Industry.prototype.processProduct = function(marketCycles=1, product, corporatio
product.data[city][2] = 0; //data[2] is sell property product.data[city][2] = 0; //data[2] is sell property
} }
break; break;
}
case "START": case "START":
case "PURCHASE": case "PURCHASE":
case "EXPORT": case "EXPORT":
@@ -1199,10 +1191,9 @@ Industry.prototype.discontinueProduct = function(product) {
} }
Industry.prototype.upgrade = function(upgrade, refs) { Industry.prototype.upgrade = function(upgrade, refs) {
var corporation = refs.corporation, division = refs.division, var corporation = refs.corporation;
office = refs.office; var office = refs.office;
var upgN = upgrade[0], basePrice = upgrade[1], priceMult = upgrade[2], var upgN = upgrade[0];
upgradeBenefit = upgrade[3];
while (this.upgrades.length <= upgN) {this.upgrades.push(0);} while (this.upgrades.length <= upgN) {this.upgrades.push(0);}
++this.upgrades[upgN]; ++this.upgrades[upgN];
@@ -1374,9 +1365,6 @@ Industry.prototype.createResearchBox = function() {
}, },
} }
// Construct the tree with Treant
const treantTree = new Treant(markup);
// Add Event Listeners for all Nodes // Add Event Listeners for all Nodes
const allResearch = researchTree.getAllNodes(); const allResearch = researchTree.getAllNodes();
for (let i = 0; i < allResearch.length; ++i) { for (let i = 0; i < allResearch.length; ++i) {
@@ -1620,7 +1608,7 @@ var OfficeSpaceTiers = {
Basic: "Basic", Basic: "Basic",
Enhanced: "Enhanced", Enhanced: "Enhanced",
Luxurious: "Luxurious", Luxurious: "Luxurious",
Extravagant: "Extravagant" Extravagant: "Extravagant",
} }
function OfficeSpace(params={}) { function OfficeSpace(params={}) {
@@ -1658,7 +1646,7 @@ OfficeSpace.prototype.atCapacity = function() {
} }
OfficeSpace.prototype.process = function(marketCycles=1, parentRefs) { OfficeSpace.prototype.process = function(marketCycles=1, parentRefs) {
var corporation = parentRefs.corporation, industry = parentRefs.industry; var industry = parentRefs.industry;
// HRBuddy AutoRecruitment and training // HRBuddy AutoRecruitment and training
if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) { if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) {
@@ -1741,7 +1729,6 @@ OfficeSpace.prototype.calculateEmployeeProductivity = function(parentRefs) {
//Takes care of UI as well //Takes care of UI as well
OfficeSpace.prototype.findEmployees = function(parentRefs) { OfficeSpace.prototype.findEmployees = function(parentRefs) {
var company = parentRefs.corporation, division = parentRefs.industry;
if (this.atCapacity()) { return; } if (this.atCapacity()) { return; }
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) {return;} if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) {return;}
@@ -1800,7 +1787,7 @@ OfficeSpace.prototype.findEmployees = function(parentRefs) {
office.hireEmployee(employee, parentRefs); office.hireEmployee(employee, parentRefs);
removeElementById("cmpy-mgmt-hire-employee-popup"); removeElementById("cmpy-mgmt-hire-employee-popup");
return false; return false;
} },
}); });
return div; return div;
}; };
@@ -1812,7 +1799,7 @@ OfficeSpace.prototype.findEmployees = function(parentRefs) {
clickListener:() => { clickListener:() => {
removeElementById("cmpy-mgmt-hire-employee-popup"); removeElementById("cmpy-mgmt-hire-employee-popup");
return false; return false;
} },
}); });
var elems = [text, var elems = [text,
@@ -1825,7 +1812,7 @@ OfficeSpace.prototype.findEmployees = function(parentRefs) {
} }
OfficeSpace.prototype.hireEmployee = function(employee, parentRefs) { OfficeSpace.prototype.hireEmployee = function(employee, parentRefs) {
var company = parentRefs.corporation, division = parentRefs.industry; var company = parentRefs.corporation;
var yesBtn = yesNoTxtInpBoxGetYesButton(), var yesBtn = yesNoTxtInpBoxGetYesButton(),
noBtn = yesNoTxtInpBoxGetNoButton(); noBtn = yesNoTxtInpBoxGetNoButton();
yesBtn.innerHTML = "Hire"; yesBtn.innerHTML = "Hire";
@@ -1958,15 +1945,14 @@ Corporation.prototype.storeCycles = function(numCycles=1) {
} }
Corporation.prototype.process = function() { Corporation.prototype.process = function() {
var corp = this;
if (this.storedCycles >= CyclesPerIndustryStateCycle) { if (this.storedCycles >= CyclesPerIndustryStateCycle) {
const state = this.getState(); const state = this.getState();
const marketCycles = 1; const marketCycles = 1;
const gameCycles = (marketCycles * CyclesPerIndustryStateCycle); const gameCycles = (marketCycles * CyclesPerIndustryStateCycle);
this.storedCycles -= gameCycles; this.storedCycles -= gameCycles;
this.divisions.forEach(function(ind) { this.divisions.forEach((ind) => {
ind.process(marketCycles, state, corp); ind.process(marketCycles, state, this);
}); });
// Process cooldowns // Process cooldowns
@@ -2111,7 +2097,7 @@ Corporation.prototype.goPublic = function() {
onkeyup:(e) => { onkeyup:(e) => {
e.preventDefault(); e.preventDefault();
if (e.keyCode === KEY.ENTER) {yesBtn.click();} if (e.keyCode === KEY.ENTER) {yesBtn.click();}
} },
}); });
var br = createElement("br", {}); var br = createElement("br", {});
yesBtn = createElement("a", { yesBtn = createElement("a", {
@@ -2138,7 +2124,7 @@ Corporation.prototype.goPublic = function() {
dialogBoxCreate(`You took your ${this.name} public and earned ` + dialogBoxCreate(`You took your ${this.name} public and earned ` +
`${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`); `${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`);
return false; return false;
} },
}); });
var noBtn = createElement("a", { var noBtn = createElement("a", {
class:"a-link-button", class:"a-link-button",
@@ -2146,7 +2132,7 @@ Corporation.prototype.goPublic = function() {
clickListener:() => { clickListener:() => {
removeElementById(goPublicPopupId); removeElementById(goPublicPopupId);
return false; return false;
} },
}); });
createPopup(goPublicPopupId, [txt, br, input, yesBtn, noBtn]); createPopup(goPublicPopupId, [txt, br, input, yesBtn, noBtn]);
} }
@@ -2208,7 +2194,6 @@ Corporation.prototype.calculateShareSale = function(numShares) {
Corporation.prototype.convertCooldownToString = function(cd) { Corporation.prototype.convertCooldownToString = function(cd) {
// The cooldown value is based on game cycles. Convert to a simple string // The cooldown value is based on game cycles. Convert to a simple string
const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle;
const seconds = cd / 5; const seconds = cd / 5;
const SecondsPerMinute = 60; const SecondsPerMinute = 60;
@@ -2351,7 +2336,7 @@ Corporation.prototype.createUI = function() {
companyManagementDiv = createElement("div", { companyManagementDiv = createElement("div", {
id:"cmpy-mgmt-container", id:"cmpy-mgmt-container",
position:"fixed", position:"fixed",
class:"generic-menupage-container" class:"generic-menupage-container",
}); });
document.getElementById("entire-game-container").appendChild(companyManagementDiv); document.getElementById("entire-game-container").appendChild(companyManagementDiv);

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