mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 14:28:36 +02:00
Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59cf1d5baf | ||
|
|
916ef06913 | ||
|
|
91ee65a101 | ||
|
|
042f926700 | ||
|
|
c0432359c3 | ||
|
|
fbf5545708 | ||
|
|
6ae7b0136c | ||
|
|
200ccd3ad0 | ||
|
|
31f97f74fd | ||
|
|
4cabd2e4ed | ||
|
|
8be7fa9157 | ||
|
|
8ddf7dfbd4 | ||
|
|
571ddb109a | ||
|
|
b2772bbfc1 | ||
|
|
b82d7c12af | ||
|
|
4476d6b258 | ||
|
|
433b399de9 | ||
|
|
58d04c0cbb | ||
|
|
e3a74f23a1 | ||
|
|
3a374de210 | ||
|
|
4cc6437408 | ||
|
|
821725cf4d | ||
|
|
931de230ae | ||
|
|
7301946236 | ||
|
|
a15041da75 | ||
|
|
00f8c0a51f | ||
|
|
63483837bc | ||
|
|
dc5f4e6694 | ||
|
|
35f8a5115a | ||
|
|
8398fd47f0 | ||
|
|
9d7c869c0a | ||
|
|
74587f269e | ||
|
|
6a3ffff3ad | ||
|
|
2f8eac07ee | ||
|
|
3eaefa01f9 | ||
|
|
b250af913d | ||
|
|
0b4968d148 | ||
|
|
8817d179c6 | ||
|
|
e5e3fec1a9 | ||
|
|
eecb0c0f01 | ||
|
|
d45689c7df | ||
|
|
2201dfc371 | ||
|
|
3ef9042051 | ||
|
|
1236ad252b | ||
|
|
65331ab22e | ||
|
|
c485fdfa87 | ||
|
|
6effda29a9 | ||
|
|
7035154454 | ||
|
|
d7f3ab9177 | ||
|
|
3660dde75f | ||
|
|
99688b78c7 | ||
|
|
6841f24932 | ||
|
|
9f94d0838a | ||
|
|
086fc67ecc | ||
|
|
a2551f98c2 | ||
|
|
95c928afc9 | ||
|
|
8a00e6e532 | ||
|
|
287a97aea6 | ||
|
|
664267bff0 | ||
|
|
2597b33f81 | ||
|
|
9442b348e6 | ||
|
|
3b7f9c9fb0 | ||
|
|
20ca7533b0 | ||
|
|
15a324a946 | ||
|
|
94175877d7 | ||
|
|
c1ec3c5eba | ||
|
|
42804b0cd3 | ||
|
|
b1248521f3 | ||
|
|
b744997c72 | ||
|
|
2d37409392 | ||
|
|
bd02e724e5 | ||
|
|
fef7aaba8f | ||
|
|
1775ea86ff | ||
|
|
b0918d7bd3 | ||
|
|
29e0ce5f96 | ||
|
|
44c26165f4 | ||
|
|
9dd68947f1 | ||
|
|
db5fdb1fcb | ||
|
|
74e72854d8 | ||
|
|
ece246b391 | ||
|
|
cdb5dfec62 | ||
|
|
8a5b6f6cbc | ||
|
|
585e1ac7aa | ||
|
|
8726946d4a | ||
|
|
064008d200 | ||
|
|
d955280f90 | ||
|
|
580a7fac24 | ||
|
|
9df054dd0c | ||
|
|
8fa7b112e1 | ||
|
|
dd9df0a18c | ||
|
|
3a601a015d | ||
|
|
87b4698d5b | ||
|
|
67632ced09 | ||
|
|
d7fb335815 | ||
|
|
4809a21e38 | ||
|
|
6b3646e981 | ||
|
|
0c64bf470a | ||
|
|
99e034921e | ||
|
|
7a3a3de7d1 | ||
|
|
f91c5bd7b9 | ||
|
|
bcb198220d | ||
|
|
bf1af6a68c | ||
|
|
3dd2975c61 | ||
|
|
33f1e0cb3c | ||
|
|
7514f63dcd | ||
|
|
b6ff73391d | ||
|
|
369ea8d381 | ||
|
|
a7296c512c | ||
|
|
8f70817c10 | ||
|
|
d044739f1c | ||
|
|
3d1684f825 | ||
|
|
f6af9e94ab | ||
|
|
215cf59e0b | ||
|
|
0d14cd6e7e |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -3,6 +3,6 @@ Netburner.txt
|
||||
/doc/build
|
||||
/node_modules
|
||||
/dist/*.map
|
||||
/tests/*.map
|
||||
/tests/*.bundle.*
|
||||
/tests/*.css
|
||||
/test/*.map
|
||||
/test/*.bundle.*
|
||||
/test/*.css
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Bitburner
|
||||
Bitburner is a cyberpunk hacking-themed incremental game. The game can be
|
||||
played at https://danielyxie.github.io/bitburner.
|
||||
Bitburner is a programming-based [incremental game](https://en.wikipedia.org/wiki/Incremental_game)
|
||||
that revolves around hacking and cyberpunk themes.
|
||||
The game can be played at https://danielyxie.github.io/bitburner.
|
||||
|
||||
# Documentation
|
||||
The game's official documentation can be found on [Read The
|
||||
|
||||
126
css/activescripts.scss
Normal file
126
css/activescripts.scss
Normal file
@@ -0,0 +1,126 @@
|
||||
@import "theme";
|
||||
|
||||
.active-scripts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#active-scripts-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
|
||||
> p {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
> pre {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&.active, &:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active {
|
||||
&:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none;
|
||||
|
||||
div, ul, ul > li {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
border: none;
|
||||
color: var(--my-font-color);
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
outline: none;
|
||||
padding: 4px 25px 4px 10px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: auto;
|
||||
|
||||
&:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-panel {
|
||||
background-color: #555;
|
||||
display: none;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
padding: 0 18px;
|
||||
width: auto;
|
||||
|
||||
pre, h2, ul, li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%;
|
||||
}
|
||||
}
|
||||
31
css/augmentations.scss
Normal file
31
css/augmentations.scss
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Styling for the Augmentations UI. This is the page that displays all of the
|
||||
* player's owned and purchased Augmentations and Source-Files. It also allows
|
||||
* the player to install Augmentations
|
||||
*/
|
||||
@import "theme";
|
||||
|
||||
#augmentations-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#augmentations-content {
|
||||
> p {
|
||||
font-size: $defaultFontSize * 0.875;
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.augmentations-list {
|
||||
button,
|
||||
div {
|
||||
color: var(--my-font-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,126 +18,6 @@
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* Active scripts */
|
||||
.active-scripts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#active-scripts-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#active-scripts-text,
|
||||
#active-scripts-total-prod {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active,
|
||||
.active-scripts-server-header:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.active-scripts-server-header:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.active-scripts-server-panel div,
|
||||
.active-scripts-server-panel ul,
|
||||
.active-scripts-server-panel ul > li {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
color: var(--my-font-color);
|
||||
padding: 4px 25px 4px 10px;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-panel {
|
||||
padding: 0 18px;
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
display: none;
|
||||
margin-bottom: 6px;
|
||||
|
||||
p, h2, ul, li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
/* World */
|
||||
#world-container {
|
||||
position: fixed;
|
||||
@@ -185,19 +65,6 @@
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#faction-donate-amount-txt,
|
||||
#faction-donate-input {
|
||||
padding: 6px;
|
||||
margin: 6px;
|
||||
display: inline-block;
|
||||
color: var(--my-font-color);
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
#faction-donate-amount-txt {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#faction-container p,
|
||||
#faction-container pre {
|
||||
padding: 4px 6px;
|
||||
@@ -213,45 +80,12 @@
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
/* Faction Augmentations */
|
||||
#faction-augmentations-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
|
||||
p, a, ul, h1 {
|
||||
margin: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* World */
|
||||
#world-container li {
|
||||
margin: 0 0 15px 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
/* Augmentations */
|
||||
#augmentations-container {
|
||||
position: fixed;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.augmentations-list {
|
||||
button,
|
||||
div {
|
||||
color: var(--my-font-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
div {
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tutorial */
|
||||
#tutorial-container {
|
||||
position: fixed;
|
||||
|
||||
@@ -7,16 +7,28 @@
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
|
||||
.bitnode {
|
||||
color: #00f;
|
||||
}
|
||||
&.level-0 {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.bitnode-destroyed {
|
||||
color: #f00;
|
||||
}
|
||||
&.level-1 {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.bitnode:hover,
|
||||
.bitnode-destroyed:hover {
|
||||
color: #fff;
|
||||
&.level-2 {
|
||||
color: #48D1CC;
|
||||
}
|
||||
|
||||
&.level-3 {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
&.unimplemented {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,35 +7,45 @@
|
||||
p {
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: $defaultFontSize * 0.875;
|
||||
}
|
||||
h2 {
|
||||
}
|
||||
|
||||
.stock-market-info-and-purchases {
|
||||
> h2 {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
> p {
|
||||
display: block;
|
||||
margin-left: 10px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
> a, > button {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#stock-market-list li {
|
||||
button {
|
||||
font-size: $defaultFontSize;
|
||||
#stock-market-list {
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
button {
|
||||
font-size: $defaultFontSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#stock-market-container p {
|
||||
padding: 6px;
|
||||
margin: 6px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#stock-market-container a {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#stock-market-watchlist-filter {
|
||||
display: block;
|
||||
margin: 5px 5px 5px 10px;
|
||||
padding: 4px;
|
||||
width: 50%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.stock-market-input {
|
||||
@@ -47,14 +57,36 @@
|
||||
color: var(--my-font-color);
|
||||
}
|
||||
|
||||
.stock-market-price-movement-warning {
|
||||
border: 1px solid white;
|
||||
color: red;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.stock-market-position-text {
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
display: block;
|
||||
|
||||
p {
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-market-order-list {
|
||||
overflow-y: auto;
|
||||
max-height: 100px;
|
||||
|
||||
li {
|
||||
color: #fff;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-market-order-cancel-btn {
|
||||
|
||||
@@ -243,8 +243,8 @@ a:visited {
|
||||
/* Accordion menus (Header with collapsible panel) */
|
||||
.accordion-header {
|
||||
background-color: #444;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
|
||||
20
dist/engine.bundle.js
vendored
20
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/engineStyle.bundle.js
vendored
Normal file
2
dist/engineStyle.bundle.js
vendored
Normal file
@@ -0,0 +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([362,0]),o()}({305:function(n,t,o){},307:function(n,t,o){},309:function(n,t,o){},311:function(n,t,o){},313:function(n,t,o){},315:function(n,t,o){},317:function(n,t,o){},319:function(n,t,o){},321:function(n,t,o){},323:function(n,t,o){},325:function(n,t,o){},327:function(n,t,o){},329:function(n,t,o){},331:function(n,t,o){},333:function(n,t,o){},335:function(n,t,o){},337:function(n,t,o){},339:function(n,t,o){},341:function(n,t,o){},343:function(n,t,o){},345:function(n,t,o){},347:function(n,t,o){},349:function(n,t,o){},351:function(n,t,o){},353:function(n,t,o){},355:function(n,t,o){},357:function(n,t,o){},359:function(n,t,o){},362:function(n,t,o){"use strict";o.r(t);o(361),o(359),o(357),o(355),o(353),o(351),o(349),o(347),o(345),o(343),o(341),o(339),o(337),o(335),o(333),o(331),o(329),o(327),o(325),o(323),o(321),o(319),o(317),o(315),o(313),o(311),o(309),o(307),o(305)}});
|
||||
//# sourceMappingURL=engineStyle.bundle.js.map
|
||||
413
dist/engine.css → dist/engineStyle.css
vendored
413
dist/engine.css → dist/engineStyle.css
vendored
@@ -1,46 +1,3 @@
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/**
|
||||
* Customized styling for the Code Mirror editor
|
||||
*/
|
||||
#codemirror-form-wrapper {
|
||||
height: 80%;
|
||||
margin: 10px 0px 0px 6px; }
|
||||
|
||||
.CodeMirror {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 2px solid var(--my-highlight-color);
|
||||
z-index: 1;
|
||||
font-family: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas", "Courier New", Courier, monospace, "Times New Roman";
|
||||
font-size: 16px; }
|
||||
|
||||
/**
|
||||
* Highlight matches
|
||||
*/
|
||||
.cm-matchhighlight {
|
||||
background-color: #8F908A; }
|
||||
|
||||
.CodeMirror-selection-highlight-scrollbar {
|
||||
background-color: #8F908A; }
|
||||
|
||||
/**
|
||||
* Show Invisibles
|
||||
*/
|
||||
.cm-whitespace::before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
color: #404F7D; }
|
||||
|
||||
/**
|
||||
* Vim command display
|
||||
*/
|
||||
#codemirror-vim-command-display-wrapper {
|
||||
background-color: white;
|
||||
font-size: 13px;
|
||||
height: 30px;
|
||||
margin-left: 6px; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/* COLORS */
|
||||
@@ -304,8 +261,8 @@ a:visited {
|
||||
/* Accordion menus (Header with collapsible panel) */
|
||||
.accordion-header {
|
||||
background-color: #444;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
@@ -933,6 +890,147 @@ button {
|
||||
|
||||
/* Specified overrides for Code mirror Editor are defined in codemirror-override.scss */
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/**
|
||||
* Customized styling for the Code Mirror editor
|
||||
*/
|
||||
#codemirror-form-wrapper {
|
||||
height: 80%;
|
||||
margin: 10px 0px 0px 6px; }
|
||||
|
||||
.CodeMirror {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 2px solid var(--my-highlight-color);
|
||||
z-index: 1;
|
||||
font-family: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas", "Courier New", Courier, monospace, "Times New Roman";
|
||||
font-size: 16px; }
|
||||
|
||||
/**
|
||||
* Highlight matches
|
||||
*/
|
||||
.cm-matchhighlight {
|
||||
background-color: #8F908A; }
|
||||
|
||||
.CodeMirror-selection-highlight-scrollbar {
|
||||
background-color: #8F908A; }
|
||||
|
||||
/**
|
||||
* Show Invisibles
|
||||
*/
|
||||
.cm-whitespace::before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
color: #404F7D; }
|
||||
|
||||
/**
|
||||
* Vim command display
|
||||
*/
|
||||
#codemirror-vim-command-display-wrapper {
|
||||
background-color: white;
|
||||
font-size: 13px;
|
||||
height: 30px;
|
||||
margin-left: 6px; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
.active-scripts-list {
|
||||
list-style-type: none; }
|
||||
|
||||
#active-scripts-container {
|
||||
position: fixed;
|
||||
padding-top: 10px; }
|
||||
#active-scripts-container > p {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px; }
|
||||
#active-scripts-container .accordion-header > pre {
|
||||
color: white; }
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none; }
|
||||
.active-scripts-server-header:after {
|
||||
content: '\2795';
|
||||
/* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
.active-scripts-server-header.active, .active-scripts-server-header:hover {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796";
|
||||
/* "minus" sign (-) */
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
|
||||
.active-scripts-server-header.active:hover {
|
||||
background-color: #666; }
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none; }
|
||||
.active-scripts-server-panel div, .active-scripts-server-panel ul, .active-scripts-server-panel ul > li {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
border: none;
|
||||
color: var(--my-font-color);
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
outline: none;
|
||||
padding: 4px 25px 4px 10px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: auto; }
|
||||
.active-scripts-script-header:after {
|
||||
content: '\2795';
|
||||
/* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px; }
|
||||
.active-scripts-script-header.active:after {
|
||||
content: "\2796";
|
||||
/* "minus" sign (-) */ }
|
||||
.active-scripts-script-header:hover, .active-scripts-script-header.active:hover {
|
||||
background-color: #666; }
|
||||
.active-scripts-script-header.active {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-script-panel {
|
||||
background-color: #555;
|
||||
display: none;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
padding: 0 18px;
|
||||
width: auto; }
|
||||
.active-scripts-script-panel pre, .active-scripts-script-panel h2, .active-scripts-script-panel ul, .active-scripts-script-panel li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/**
|
||||
@@ -1007,107 +1105,6 @@ button {
|
||||
padding-top: 10px;
|
||||
position: fixed; }
|
||||
|
||||
/* Active scripts */
|
||||
.active-scripts-list {
|
||||
list-style-type: none; }
|
||||
|
||||
#active-scripts-container {
|
||||
position: fixed;
|
||||
padding-top: 10px; }
|
||||
|
||||
#active-scripts-text,
|
||||
#active-scripts-total-prod {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px; }
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none; }
|
||||
|
||||
.active-scripts-server-header.active,
|
||||
.active-scripts-server-header:hover {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-server-header.active:hover {
|
||||
background-color: #666; }
|
||||
|
||||
.active-scripts-server-header:after {
|
||||
content: '\2795';
|
||||
/* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796";
|
||||
/* "minus" sign (-) */
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none; }
|
||||
|
||||
.active-scripts-server-panel div,
|
||||
.active-scripts-server-panel ul,
|
||||
.active-scripts-server-panel ul > li {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
color: var(--my-font-color);
|
||||
padding: 4px 25px 4px 10px;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
position: relative; }
|
||||
.active-scripts-script-header:after {
|
||||
content: '\2795';
|
||||
/* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px; }
|
||||
.active-scripts-script-header.active:after {
|
||||
content: "\2796";
|
||||
/* "minus" sign (-) */ }
|
||||
.active-scripts-script-header:hover, .active-scripts-script-header.active:hover {
|
||||
background-color: #666; }
|
||||
.active-scripts-script-header.active {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-script-panel {
|
||||
padding: 0 18px;
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
display: none;
|
||||
margin-bottom: 6px; }
|
||||
.active-scripts-script-panel p, .active-scripts-script-panel h2, .active-scripts-script-panel ul, .active-scripts-script-panel li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%; }
|
||||
|
||||
/* World */
|
||||
#world-container {
|
||||
position: fixed;
|
||||
@@ -1147,17 +1144,6 @@ button {
|
||||
margin: 6px;
|
||||
width: 70%; }
|
||||
|
||||
#faction-donate-amount-txt,
|
||||
#faction-donate-input {
|
||||
padding: 6px;
|
||||
margin: 6px;
|
||||
display: inline-block;
|
||||
color: var(--my-font-color);
|
||||
background-color: #000; }
|
||||
|
||||
#faction-donate-amount-txt {
|
||||
width: 50%; }
|
||||
|
||||
#faction-container p,
|
||||
#faction-container pre {
|
||||
padding: 4px 6px;
|
||||
@@ -1176,35 +1162,11 @@ button {
|
||||
word-wrap: break-word;
|
||||
/* Internet Explorer 5.5+ */ }
|
||||
|
||||
/* Faction Augmentations */
|
||||
#faction-augmentations-container {
|
||||
position: fixed;
|
||||
padding-top: 10px; }
|
||||
#faction-augmentations-container p, #faction-augmentations-container a, #faction-augmentations-container ul, #faction-augmentations-container h1 {
|
||||
margin: 8px;
|
||||
padding: 4px; }
|
||||
|
||||
/* World */
|
||||
#world-container li {
|
||||
margin: 0 0 15px 0;
|
||||
list-style-type: none; }
|
||||
|
||||
/* Augmentations */
|
||||
#augmentations-container {
|
||||
position: fixed;
|
||||
padding-top: 10px; }
|
||||
|
||||
.augmentations-list button,
|
||||
.augmentations-list div {
|
||||
color: var(--my-font-color);
|
||||
text-decoration: none; }
|
||||
|
||||
.augmentations-list button {
|
||||
padding: 2px 5px; }
|
||||
|
||||
.augmentations-list div {
|
||||
padding: 6px; }
|
||||
|
||||
/* Tutorial */
|
||||
#tutorial-container {
|
||||
position: fixed;
|
||||
@@ -1286,6 +1248,29 @@ button {
|
||||
display: inline;
|
||||
width: 25%; }
|
||||
|
||||
/**
|
||||
* Styling for the Augmentations UI. This is the page that displays all of the
|
||||
* player's owned and purchased Augmentations and Source-Files. It also allows
|
||||
* the player to install Augmentations
|
||||
*/
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
#augmentations-container {
|
||||
position: fixed;
|
||||
padding-top: 10px; }
|
||||
|
||||
#augmentations-content > p {
|
||||
font-size: 14px;
|
||||
width: 70%; }
|
||||
|
||||
.augmentations-list button,
|
||||
.augmentations-list div {
|
||||
color: var(--my-font-color);
|
||||
text-decoration: none; }
|
||||
|
||||
.augmentations-list button {
|
||||
padding: 4px; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/**
|
||||
@@ -1294,14 +1279,22 @@ button {
|
||||
#red-pill-container {
|
||||
position: fixed; }
|
||||
|
||||
.bitnode {
|
||||
color: #00f; }
|
||||
.bitnode.level-0 {
|
||||
color: red; }
|
||||
|
||||
.bitnode-destroyed {
|
||||
color: #f00; }
|
||||
.bitnode.level-1 {
|
||||
color: yellow; }
|
||||
|
||||
.bitnode:hover,
|
||||
.bitnode-destroyed:hover {
|
||||
.bitnode.level-2 {
|
||||
color: #48D1CC; }
|
||||
|
||||
.bitnode.level-3 {
|
||||
color: blue; }
|
||||
|
||||
.bitnode.unimplemented {
|
||||
color: gray; }
|
||||
|
||||
.bitnode:hover {
|
||||
color: #fff; }
|
||||
|
||||
/* COLORS */
|
||||
@@ -1313,25 +1306,30 @@ button {
|
||||
font-size: 13px; }
|
||||
#stock-market-container a {
|
||||
font-size: 14px; }
|
||||
#stock-market-container h2 {
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
display: block; }
|
||||
|
||||
#stock-market-list li button {
|
||||
font-size: 16px; }
|
||||
.stock-market-info-and-purchases > h2 {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px; }
|
||||
|
||||
#stock-market-container p {
|
||||
padding: 6px;
|
||||
margin: 6px;
|
||||
.stock-market-info-and-purchases > p {
|
||||
display: block;
|
||||
margin-left: 10px;
|
||||
width: 70%; }
|
||||
|
||||
#stock-market-container a {
|
||||
.stock-market-info-and-purchases > a, .stock-market-info-and-purchases > button {
|
||||
margin: 10px; }
|
||||
|
||||
#stock-market-list {
|
||||
list-style: none; }
|
||||
#stock-market-list li button {
|
||||
font-size: 16px; }
|
||||
|
||||
#stock-market-watchlist-filter {
|
||||
width: 50%;
|
||||
margin-left: 10px; }
|
||||
display: block;
|
||||
margin: 5px 5px 5px 10px;
|
||||
padding: 4px;
|
||||
width: 50%; }
|
||||
|
||||
.stock-market-input {
|
||||
display: inline-block;
|
||||
@@ -1341,13 +1339,28 @@ button {
|
||||
border: 1px solid #fff;
|
||||
color: var(--my-font-color); }
|
||||
|
||||
.stock-market-price-movement-warning {
|
||||
border: 1px solid white;
|
||||
color: red;
|
||||
margin: 2px;
|
||||
padding: 2px; }
|
||||
|
||||
.stock-market-position-text {
|
||||
color: #fff;
|
||||
display: inline-block; }
|
||||
display: block; }
|
||||
.stock-market-position-text p {
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
margin: 4px; }
|
||||
.stock-market-position-text h3 {
|
||||
margin: 4px; }
|
||||
|
||||
.stock-market-order-list {
|
||||
overflow-y: auto;
|
||||
max-height: 100px; }
|
||||
.stock-market-order-list li {
|
||||
color: #fff;
|
||||
padding: 4px; }
|
||||
|
||||
.stock-market-order-cancel-btn {
|
||||
background-color: #000;
|
||||
@@ -4866,4 +4879,4 @@ html {
|
||||
margin-right: 0px; }
|
||||
|
||||
|
||||
/*# sourceMappingURL=engine.css.map*/
|
||||
/*# sourceMappingURL=engineStyle.css.map*/
|
||||
623
dist/vendor.bundle.js
vendored
623
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -86,8 +86,11 @@ Sleeve memory dictates what a sleeve's synchronization will be when its reset by
|
||||
switching BitNodes. For example, if a sleeve has a memory of 10, then when you
|
||||
switch BitNodes its synchronization will initially be set to 10, rather than 1.
|
||||
|
||||
Memory can only be increased by purchasing upgrades from The Covenant.
|
||||
It is a persistent stat, meaning it never gets reset back to 1.
|
||||
Memory can only be increased by purchasing upgrades from The Covenant. Just like
|
||||
the ability to purchase additional sleeves, this is only available in BitNodes-10
|
||||
and above, and is only available after defeating BitNode-10 at least once.
|
||||
|
||||
Memory is a persistent stat, meaning it never gets reset back to 1.
|
||||
The maximum possible value for a sleeve's memory is 100.
|
||||
|
||||
Re-sleeving
|
||||
|
||||
@@ -40,7 +40,7 @@ solutions. Some may be numbers, others may be strings or arrays.
|
||||
If a contract asks for a specific solution format, then
|
||||
use that. Otherwise, follow these rules when submitting solutions:
|
||||
|
||||
* String-type solutions should not have quotation marks surrounding
|
||||
* String-type solutions should **not** have quotation marks surrounding
|
||||
the string (unless specifically asked for). Only quotation
|
||||
marks that are part of the actual string solution should be included.
|
||||
* Array-type solutions should be submitted with each element
|
||||
@@ -204,8 +204,8 @@ The list contains the name of (i.e. the value returned by
|
||||
| | | the string, the result should be an array with only an empty string. |
|
||||
| | | |
|
||||
| | | Examples: |
|
||||
| | | ()())() -> ["()()()", "(())()"] |
|
||||
| | | (a)())() -> ["(a)()()", "(a())()"] |
|
||||
| | | ()())() -> [()()(), (())()] |
|
||||
| | | (a)())() -> [(a)()(), (a())()] |
|
||||
| | | )( -> [""] |
|
||||
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||
| Find All Valid Math Expressions | | You are given a string which contains only digits between 0 and 9 as well as a target |
|
||||
@@ -214,10 +214,12 @@ The list contains the name of (i.e. the value returned by
|
||||
| | | |
|
||||
| | | The answer should be provided as an array of strings containing the valid expressions. |
|
||||
| | | |
|
||||
| | | NOTE: Numbers in an expression cannot have leading 0's |
|
||||
| | | |
|
||||
| | | Examples: |
|
||||
| | | Input: digits = "123", target = 6 |
|
||||
| | | Output: ["1+2+3", "1*2*3"] |
|
||||
| | | Output: [1+2+3, 1*2*3] |
|
||||
| | | |
|
||||
| | | Input: digits = "105", target = 5 |
|
||||
| | | Output: ["1*0+5", "10-5"] |
|
||||
| | | Output: [1*0+5, 10-5] |
|
||||
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -7,10 +7,14 @@ buy and sell stocks in order to make money.
|
||||
|
||||
The WSE can be found in the 'City' tab, and is accessible in every city.
|
||||
|
||||
Automating the Stock Market
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
You can write scripts to perform automatic and algorithmic trading on the Stock Market.
|
||||
See :ref:`netscript_tixapi` for more details.
|
||||
Fundamentals
|
||||
------------
|
||||
The Stock Market is not as simple as "buy at price X and sell at price Y". The following
|
||||
are several fundamental concepts you need to understand about the stock market.
|
||||
|
||||
.. note:: For those that have experience with finance/trading/investing, please be aware
|
||||
that the game's stock market does not function exactly like it does in the real
|
||||
world. So these concepts below should seem similar, but won't be exactly the same.
|
||||
|
||||
Positions: Long vs Short
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -21,16 +25,73 @@ is the exact opposite. In a Short position you purchase shares of a stock and
|
||||
earn a profit if the price of that stock decreases. This is also called 'shorting'
|
||||
a stock.
|
||||
|
||||
NOTE: Shorting stocks is not available immediately, and must be unlocked later in the
|
||||
game.
|
||||
.. note:: Shorting stocks is not available immediately, and must be unlocked later in the
|
||||
game.
|
||||
|
||||
Forecast & Second-Order Forecast
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A stock's forecast is its likelihood of increasing or decreasing in value. The
|
||||
forecast is typically represented by its probability of increasing in either
|
||||
a decimal or percentage form. For example, a forecast of 70% means the stock
|
||||
has a 70% chance of increasing and a 30% chance of decreasing.
|
||||
|
||||
A stock's second-order forecast is the target value that its forecast trends towards.
|
||||
For example, if a stock has a forecast of 60% and a second-order forecast of 70%,
|
||||
then the stock's forecast should slowly trend towards 70% over time. However, this is
|
||||
determined by RNG so there is a chance that it may never reach 70%.
|
||||
|
||||
Both the forecast and the second-order forecast change over time.
|
||||
|
||||
A stock's forecast can be viewed after purchasing Four Sigma (4S) Market Data
|
||||
access. This lets you see the forecast info on the Stock Market UI. If you also
|
||||
purchase access to the 4S Market Data TIX API, then you can view a stock's forecast
|
||||
using the :js:func:`getStockForecast` function.
|
||||
|
||||
A stock's second-order forecast is always hidden.
|
||||
|
||||
.. _gameplay_stock_market_spread:
|
||||
|
||||
Spread (Bid Price & Ask Price)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The **bid price** is the maximum price at which someone will buy a stock on the
|
||||
stock market.
|
||||
|
||||
The **ask price** is the minimum price that a seller is willing to receive for a stock
|
||||
on the stock market
|
||||
|
||||
The ask price will always be higher than the bid price (This is because if a seller
|
||||
is willing to receive less than the bid price, that transaction is guaranteed to
|
||||
happen). The difference between the bid and ask price is known as the **spread**.
|
||||
A stock's "price" will be the average of the bid and ask price.
|
||||
|
||||
The bid and ask price are important because these are the prices at which a
|
||||
transaction actually occurs. If you purchase a stock in the long position, the cost
|
||||
of your purchase depends on that stock's ask price. If you then try to sell that
|
||||
stock (still in the long position), the price at which you sell is the stock's
|
||||
bid price. Note that this is reversed for a short position. Purchasing a stock
|
||||
in the short position will occur at the stock's bid price, and selling a stock
|
||||
in the short position will occur at the stock's ask price.
|
||||
|
||||
Transactions Influencing Stock Forecast
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Buying or selling a large number of shares
|
||||
of a stock will influence that stock's forecast & second-order forecast.
|
||||
The forecast is the likelihood that the stock will increase or decrease in price.
|
||||
The magnitude of this effect depends on the number of shares being transacted.
|
||||
More shares will have a bigger effect.
|
||||
|
||||
The effect that transactions have on a stock's second-order forecast is
|
||||
significantly smaller than the effect on its forecast.
|
||||
|
||||
.. _gameplay_stock_market_order_types:
|
||||
|
||||
Order Types
|
||||
^^^^^^^^^^^
|
||||
There are three different types of orders you can make to buy or sell stocks on the exchange:
|
||||
Market Order, Limit Order, and Stop Order.
|
||||
|
||||
Note that Limit Orders and Stop Orders are not available immediately, and must be unlocked
|
||||
later in the game.
|
||||
.. note:: Limit Orders and Stop Orders are not available immediately, and must be unlocked
|
||||
later in the game.
|
||||
|
||||
When you place a Market Order to buy or sell a stock, the order executes immediately at
|
||||
whatever the current price of the stock is. For example if you choose to short a stock
|
||||
@@ -71,3 +132,77 @@ A Limit Order to sell will execute if the stock's price <= order's price
|
||||
A Stop Order to buy will execute if the stock's price <= order's price
|
||||
|
||||
A Stop Order to sell will execute if the stock's price >= order's price.
|
||||
|
||||
.. _gameplay_stock_market_player_actions_influencing_stock:
|
||||
|
||||
Player Actions Influencing Stocks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
It is possible for your actions elsewhere in the game to influence the stock market.
|
||||
|
||||
Hacking
|
||||
If a server has a corresponding stock (e.g. *foodnstuff* server -> FoodNStuff
|
||||
stock), then hacking that server can decrease the stock's second-order
|
||||
forecast. This causes the corresponding stock's forecast to trend downwards in value
|
||||
over time.
|
||||
|
||||
This effect only occurs if you set the *stock* option to
|
||||
true when calling the :js:func:`hack` function. The chance that hacking a
|
||||
server will cause this effect is based on what percentage of the
|
||||
server's total money you steal.
|
||||
|
||||
A single hack will have a minor
|
||||
effect, but continuously hacking a server for lots of money over time
|
||||
will have a noticeable effect in making the stock's forecast trend downwards.
|
||||
|
||||
Growing
|
||||
If a server has a corresponding stock (e.g. *foodnstuff* server -> FoodNStuff
|
||||
stock), then growing that server's money can increase the stock's
|
||||
second-order forecast. This causes the corresponding stock's
|
||||
forecast to trend upwards in value over time.
|
||||
|
||||
This effect only occurs if you set the *stock* option to true when calling the
|
||||
:js:func:`grow` function. The chance that growing a server will cause this
|
||||
effect is based on what percentage of the server's total money to add to it.
|
||||
|
||||
A single grow operation will have a minor effect, but continuously growing
|
||||
a server for lots of money over time will have a noticeable effect in making
|
||||
the stock's forecast trend upwards.
|
||||
|
||||
Working for a Company
|
||||
If a company has a corresponding stock, then working for that company will
|
||||
increase the corresponding stock's second-order forecast. This will
|
||||
cause the stock's forecast to (slowly) trend upwards in value
|
||||
over time.
|
||||
|
||||
The potency of this effect is based on how "effective" you are when you work
|
||||
(i.e. its based on your stats and multipliers).
|
||||
|
||||
Automating the Stock Market
|
||||
---------------------------
|
||||
You can write scripts to perform automatic and algorithmic trading on the Stock Market.
|
||||
See :ref:`netscript_tixapi` for more details.
|
||||
|
||||
Under the Hood
|
||||
--------------
|
||||
Stock prices are updated very ~6 seconds.
|
||||
|
||||
Whether a stock's price moves up or down is determined by RNG. However,
|
||||
stocks have properties that can influence the way their price moves. These properties
|
||||
are hidden, although some of them can be made visible by purchasing the
|
||||
Four Sigma (4S) Market Data upgrade. Some examples of these properties are:
|
||||
|
||||
* Volatility
|
||||
* Likelihood of increasing or decreasing (i.e. the stock's forecast)
|
||||
* Likelihood of forecast increasing or decreasing (i.e. the stock's second-order forecast)
|
||||
* How easily a stock's price/forecast is influenced by transactions
|
||||
* Spread percentage
|
||||
* Maximum price (not a real maximum, more of a "soft cap")
|
||||
|
||||
Each stock has its own unique values for these properties.
|
||||
|
||||
Offline Progression
|
||||
-------------------
|
||||
The Stock Market does not change or process anything while the game has closed.
|
||||
However, it does accumulate time when offline. This accumulated time allows
|
||||
the stock market to run 50% faster when the game is opened again. This means
|
||||
that stock prices will update every ~4 seconds instead of 6.
|
||||
|
||||
@@ -312,9 +312,12 @@ kill
|
||||
^^^^
|
||||
|
||||
$ kill [script name] [args...]
|
||||
$ kill [pid]
|
||||
|
||||
Kill the script specified by the script name and arguments. Each argument must
|
||||
be separated by a space. Remember that a running script is uniquely identified
|
||||
Kill the script specified by the script filename and arguments OR by its PID.
|
||||
|
||||
If you are killing the script using its filename and arguments, then each argument
|
||||
must be separated by a space. Remember that a running script is uniquely identified
|
||||
by both its name and the arguments that are used to start it. So, if a script
|
||||
was ran with the following arguments::
|
||||
|
||||
@@ -324,8 +327,7 @@ Then to kill this script the same arguments would have to be used::
|
||||
|
||||
$ kill foo.script 50e3 sigma-cosmetics
|
||||
|
||||
Note that after issuing the 'kill' command for a script, it may take a few seconds for
|
||||
the script to actually stop running.
|
||||
If you are killing the script using its PID, then the PID argument must be numeric.
|
||||
|
||||
killall
|
||||
^^^^^^^
|
||||
@@ -403,7 +405,7 @@ to convert from script to text file, or vice versa.
|
||||
This function can also be used to rename files.
|
||||
|
||||
.. note:: Unlike the Linux :code:`mv` command, the *destination* argument must be the
|
||||
full filepath. It cannot be a directory.
|
||||
full filepath. It cannot be a directory.
|
||||
|
||||
Examples::
|
||||
|
||||
@@ -511,6 +513,8 @@ sudov
|
||||
|
||||
Prints whether or not you have root access to the current server.
|
||||
|
||||
.. _tail_terminal_command:
|
||||
|
||||
tail
|
||||
^^^^
|
||||
|
||||
|
||||
@@ -3,13 +3,116 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.47.2 - 7/15/2019
|
||||
-------------------
|
||||
|
||||
**Netscript Changes**
|
||||
|
||||
* Added tail() Netscript function
|
||||
* hacknet.getNodeStats() function now returns an additional property for Hacknet Servers: hashCapacity
|
||||
* When writing to a file, the write() function now casts the data being written to a string (using String())
|
||||
* BitNode-selection page now shows what Source-File level you have for each BitNode
|
||||
* Overloaded kill() function so that you can kill a script by its PID
|
||||
* spawn() now only takes 10 seconds to run (decreased from 20 seconds)
|
||||
* run() and exec() now return the PID of the newly-executed scripts, rather than a boolean
|
||||
* (A PID is just a positive integer)
|
||||
* run(), exec(), and spawn() no longer need to be await-ed in NetscriptJS
|
||||
* Script parsing and RAM calculations now support ES9
|
||||
* installAugmentations() no longer has a return value since it causes all scripts to die
|
||||
* isBusy() now returns true if you are in a Hacking Mission
|
||||
* Bug fix: workForFaction() function now properly accounts for disabled logs
|
||||
* Bug fix: RAM should now be properly calculated when running a callback script with installAugmentations()
|
||||
* Bug fix: Fixed bug that caused scripts killed by exit()/spawn() to "clean up" twice
|
||||
|
||||
**Misc Changes**
|
||||
|
||||
* The 'kill' Terminal command can now kill a script by its PID
|
||||
* Added 'Solarized Dark' theme to CodeMirror editor
|
||||
* After Infiltration, you will now return to the company page rather than the city page
|
||||
* Bug fix: Stock Market UI should no longer crash for certain locale settings
|
||||
* Bug fix: You can now properly remove unfinished programs (the *.exe-N%-INC files)
|
||||
* Bug fix: Fixed an issue that allowed you to increase money on servers with a 'maxMoney' of 0 (like CSEC)
|
||||
* Bug fix: Scripts no longer persist if they were started with syntax/import errors
|
||||
* Bug fix: 'hack' and 'analyze' Terminal commands are now blocking
|
||||
* Bug fix: Exp earned by duplicate sleeves at universities/gyms now takes hash upgrades into account
|
||||
|
||||
v0.47.1 - 6/27/2019
|
||||
-------------------
|
||||
* Stock Market changes:
|
||||
* Transactions no longer influence stock prices (but they still influence forecast)
|
||||
* Changed the way stocks behave, particularly with regard to how the stock forecast occasionally "flips"
|
||||
* Hacking & growing a server can potentially affect the way the corresponding stock's forecast changes
|
||||
* Working for a company positively affects the way the corresponding stock's forecast changes
|
||||
|
||||
* Scripts now start/stop instantly
|
||||
* Improved performance when starting up many copies of a new NetscriptJS script (by Ornedan)
|
||||
* Improved performance when killing scripts
|
||||
* Dialog boxes can now be closed with the ESC key (by jaguilar)
|
||||
* NetscriptJS scripts should now be "re-compiled" if their dependencies change (by jaguilar)
|
||||
* write() function should now properly cause NetscriptJS scripts to "re-compile" (by jaguilar)
|
||||
|
||||
v0.47.0 - 5/17/2019
|
||||
-------------------
|
||||
* Stock Market changes:
|
||||
* Implemented spread. Stock's now have bid and ask prices at which transactions occur
|
||||
* Large transactions will now influence a stock's price and forecast
|
||||
* This "influencing" can take effect in the middle of a transaction
|
||||
* See documentation for more details on these changes
|
||||
* Added getStockAskPrice(), getStockBidPrice() Netscript functions to the TIX API
|
||||
* Added getStockPurchaseCost(), getStockSaleGain() Netscript functions to the TIX API
|
||||
|
||||
* Re-sleeves can no longer have the NeuroFlux Governor augmentation
|
||||
* This is just a temporary patch until the mechanic gets re-worked
|
||||
|
||||
* hack(), grow(), and weaken() functions now take optional arguments for number of threads to use (by MasonD)
|
||||
* codingcontract.attempt() now takes an optional argument that allows you to configure the function to return a contract's reward
|
||||
* Adjusted RAM costs of Netscript Singularity functions (mostly increased)
|
||||
* Adjusted RAM cost of codingcontract.getNumTriesRemaining() Netscript function
|
||||
* Netscript Singularity functions no longer cost extra RAM outside of BitNode-4
|
||||
* Corporation employees no longer have an "age" stat
|
||||
* Gang Wanted level gain rate capped at 100 (per employee)
|
||||
* Script startup/kill is now processed every 3 seconds, instead of 6 seconds
|
||||
* getHackTime(), getGrowTime(), and getWeakenTime() now return Infinity if called on a Hacknet Server
|
||||
* Money/Income tracker now displays money lost from hospitalizations
|
||||
* Exported saves now have a unique filename based on current BitNode and timestamp
|
||||
* Maximum number of Hacknet Servers decreased from 25 to 20
|
||||
* Bug Fix: Corporation employees stats should no longer become negative
|
||||
* Bug Fix: Fixed sleeve.getInformation() throwing error in certain scenarios
|
||||
* Bug Fix: Coding contracts should no longer generate on the w0r1d_d43m0n server
|
||||
* Bug Fix: Duplicate Sleeves now properly have access to all Augmentations if you have a gang
|
||||
* Bug Fix: getAugmentationsFromFaction() & purchaseAugmentation() functions should now work properly if you have a gang
|
||||
* Bug Fix: Fixed issue that caused messages (.msg) to be sent when refreshing/reloading the game
|
||||
* Bug Fix: Purchasing hash upgrades for Bladeburner/Corporation when you don't actually have access to those mechanics no longer gives hashes
|
||||
* Bug Fix: run(), exec(), and spawn() Netscript functions now throw if called with 0 threads
|
||||
* Bug Fix: Faction UI should now automatically update reputation
|
||||
* Bug Fix: Fixed purchase4SMarketData()
|
||||
* Bug Fix: Netscript1.0 now works properly for multiple 'namespace' imports (import * as namespace from "script")
|
||||
* Bug Fix: Terminal 'wget' command now correctly evaluates directory paths
|
||||
* Bug Fix: wget(), write(), and scp() Netscript functions now fail if an invalid filepath is passed in
|
||||
* Bug Fix: Having Corporation warehouses at full capacity should no longer freeze game in certain conditions
|
||||
* Bug Fix: Prevented an exploit that allows you to buy multiple copies of an Augmentation by holding the 'Enter' button
|
||||
* Bug Fix: gang.getOtherGangInformation() now properly returns a deep copy
|
||||
* Bug Fix: Fixed getScriptIncome() returning an undefined value
|
||||
* Bug Fix: Fixed an issue with Hacknet Server hash rate not always updating
|
||||
|
||||
v0.46.3 - 4/20/2019
|
||||
-------------------
|
||||
* Added a new Augmentation: The Shadow's Simulacrum
|
||||
* Improved tab autocompletion feature in Terminal so that it works better with directories
|
||||
* Bug Fix: Tech vendor location UI now properly refreshed when purchasing a TOR router
|
||||
* Bug Fix: Fixed UI issue with faction donations
|
||||
* Bug Fix: The money statistics & breakdown should now properly track money earned from Hacknet Server (hashes -> money)
|
||||
* Bug Fix: Fixed issue with changing input in 'Minimum Path Sum in a Triangle' coding contract problem
|
||||
* Fixed several typos in various places
|
||||
|
||||
v0.46.2 - 4/14/2019
|
||||
-------------------
|
||||
* Source-File 2 now allows you to form gangs in other BitNodes when your karma reaches a very large negative value
|
||||
** (Karma is a hidden stat and is lowered by committing crimes)
|
||||
* (Karma is a hidden stat and is lowered by committing crimes)
|
||||
|
||||
* Gang changes:
|
||||
** Bug Fix: Gangs can no longer clash with themselve
|
||||
** Bug Fix: Winning against another gang should properly reduce their power
|
||||
* Bug Fix: Gangs can no longer clash with themselve
|
||||
* Bug Fix: Winning against another gang should properly reduce their power
|
||||
|
||||
* Bug Fix: Terminal 'wget' command now works properly
|
||||
* Bug Fix: Hacknet Server Hash upgrades now properly reset upon installing Augs/switching BitNodes
|
||||
|
||||
@@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.46'
|
||||
version = '0.47'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.46.2'
|
||||
release = '0.47.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -2,10 +2,11 @@ Guides & Tips
|
||||
=============
|
||||
|
||||
Getting Started Guide for Intermediate Programmers
|
||||
What BitNode should I do?
|
||||
|
||||
Beginners FAQ
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
Getting Started Guide for Beginner Programmers <guidesandtips/gettingstartedguideforbeginnerprogrammers>
|
||||
What BitNode should I do?<guidesandtips/recommendedbitnodeorder>
|
||||
|
||||
490
doc/source/guidesandtips/recommendedbitnodeorder.rst
Normal file
490
doc/source/guidesandtips/recommendedbitnodeorder.rst
Normal file
@@ -0,0 +1,490 @@
|
||||
What BitNode should I do?
|
||||
=========================
|
||||
|
||||
.. warning:: This page contains spoilers regarding the game's story/plot-line.
|
||||
|
||||
After destroying their first :ref:`BitNode <gameplay_bitnodes>`, many players
|
||||
wonder which BitNode they should tackle next. This guide hopefully helps answer
|
||||
that question.
|
||||
|
||||
Overview of each BitNode
|
||||
------------------------
|
||||
|
||||
BitNode-1: Source Genesis
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
The first BitNode created by the Enders to imprison the minds of humans. It became
|
||||
the prototype and testing-grounds for all of the BitNodes that followed.
|
||||
This is the first BitNode that you play through. It has no special
|
||||
modifications or mechanics.
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File lets the player start with 32GB of RAM on his/her home computer when
|
||||
entering a new BitNode, and also increases all of the player's multipliers by:
|
||||
|
||||
* Level 1: 16%
|
||||
* Level 2: 24%
|
||||
* Level 3: 28%
|
||||
|
||||
Difficulty
|
||||
The easiest BitNode
|
||||
|
||||
BitNode-2: Rise of the Underworld
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
Organized crime groups quickly filled the void of power left behind from the collapse of
|
||||
Western government in the 2050s. As society and civlization broke down, people quickly
|
||||
succumbed to the innate human impulse of evil and savagery. The organized crime
|
||||
factions quickly rose to the top of the modern world.
|
||||
|
||||
In this BitNode:
|
||||
|
||||
* Your hacking level is reduced by 20%
|
||||
* The growth rate and maximum amount of money available on servers are significantly decreased
|
||||
* The amount of money gained from crimes and Infiltration is tripled
|
||||
* Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead,
|
||||
NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs
|
||||
will earn the player money and reputation with the corresponding Faction
|
||||
* Every Augmentation in the game will be available through the Factions listed above
|
||||
* For every Faction NOT listed above, reputation gains are halved
|
||||
* You will no longer gain passive reputation with Factions
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File allows you to form gangs in other BitNodes once your karma decreases to a certain value.
|
||||
It also increases the player's crime success rate, crime money, and charisma multipliers by:
|
||||
|
||||
* Level 1: 24%
|
||||
* Level 2: 36%
|
||||
* Level 3: 42%
|
||||
|
||||
Difficulty
|
||||
Fairly easy, as hacking is still very profitable and the costs of various purchases/upgrades
|
||||
is not increased. The gang mechanic may seem strange as its very different from anything
|
||||
else, but it can be very powerful once you get the hang of it.
|
||||
|
||||
BitNode-3: Corporatocracy
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
Our greatest illusion is that a healthy society can revolve around a
|
||||
single-minded pursuit of wealth.
|
||||
Sometime in the early 21st century economic and political globalization turned
|
||||
the world into a corporatocracy, and it never looked back. Now, the privileged
|
||||
elite will happily bankrupt their own countrymen, decimate their own community,
|
||||
and evict their neighbors from houses in their desperate bid to increase their wealth.
|
||||
In this BitNode you can create and manage your own corporation. Running a successful corporation
|
||||
has the potential of generating massive profits. All other forms of income are reduced by 75%. Furthermore:
|
||||
|
||||
* The price and reputation cost of all Augmentations is tripled
|
||||
* The starting and maximum amount of money on servers is reduced by 75%
|
||||
* Server growth rate is reduced by 80%
|
||||
* You now only need 75 favour with a faction in order to donate to it, rather than 150
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File lets you create corporations on other BitNodes (although
|
||||
some BitNodes will disable this mechanic). This Source-File also increases your
|
||||
charisma and company salary multipliers by:
|
||||
|
||||
* Level 1: 8%
|
||||
* Level 2: 12%
|
||||
* Level 3: 14%
|
||||
|
||||
Difficulty
|
||||
Somewhat-steep learning curve as you learn how to use and manage Corporations. Afterwards,
|
||||
however, the BitNode is easy as Corporations can be very profitable.
|
||||
|
||||
BitNode-4: The Singularity
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
The Singularity has arrived. The human race is gone, replaced by artificially superintelligent
|
||||
beings that are more machine than man.
|
||||
|
||||
In this BitNode, progressing is significantly harder:
|
||||
|
||||
* Experience gain rates for all stats are reduced.
|
||||
* Most methods of earning money will now give significantly less.
|
||||
|
||||
In this BitNode you will gain access to a new set of Netscript Functions known as Singularity Functions.
|
||||
These functions allow you to control most aspects of the game through scripts, including
|
||||
working for factions/companies, purchasing/installing Augmentations, and creating programs.
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File lets you access and use the Singularity Functions in other BitNodes.
|
||||
Each level of this Source-File will open up more Singularity Functions that you can use.
|
||||
|
||||
Difficulty:
|
||||
Depending on what Source-Files you have unlocked before attempting this BitNode,
|
||||
it can range from easy to moderate.
|
||||
|
||||
BitNode-5: Artificial Intelligence
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
They said it couldn't be done. They said the human brain,
|
||||
along with its consciousness and intelligence, couldn't be replicated. They said the complexity
|
||||
of the brain results from unpredictable, nonlinear interactions that couldn't be modeled
|
||||
by 1's and 0's. They were wrong.
|
||||
|
||||
In this BitNode:
|
||||
|
||||
* The base security level of servers is doubled
|
||||
* The starting money on servers is halved, but the maximum money remains the same
|
||||
* Most methods of earning money now give significantly less
|
||||
* Infiltration gives 50% more reputation and money
|
||||
* Corporations have 50% lower valuations and are therefore less profitable
|
||||
* Augmentations are more expensive
|
||||
* Hacking experience gain rates are reduced
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File grants you a special new stat called Intelligence.
|
||||
|
||||
Intelligence is unique because it is permanent and persistent (it never gets reset back to 1). However
|
||||
gaining Intelligence experience is much slower than other stats, and it is also hidden (you won't know
|
||||
when you gain experience and how much). Higher Intelligence levels will boost your production for many actions
|
||||
in the game.
|
||||
|
||||
In addition, this Source-File will unlock the :js:func:`getBitNodeMultipliers()` Netscript function,
|
||||
and will also raise all of your hacking-related multipliers by:
|
||||
|
||||
* Level 1: 8%
|
||||
* Level 2: 12%
|
||||
* Level 3: 14%
|
||||
|
||||
Difficulty
|
||||
Depending on what Source-Files you have unlocked before attempting this BitNode, it
|
||||
can range from easy to moderate.
|
||||
|
||||
BitNode-6: Bladeburners
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
In the middle of the 21st century, OmniTek Incorporated began designing and manufacturing advanced synthetic
|
||||
androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth generation
|
||||
of their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was
|
||||
the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more intelligent
|
||||
than the humans that had created them.
|
||||
|
||||
In this BitNode you will be able to access the Bladeburner Division at the NSA, which provides
|
||||
a new mechanic for progression. Furthermore:
|
||||
|
||||
* Hacking and Hacknet Nodes will be less profitable
|
||||
* Your hacking level is reduced by 65%
|
||||
* Hacking experience gain from scripts is reduced by 75%
|
||||
* Corporations have 80% lower valuations and are therefore less profitable
|
||||
* Working for companies is 50% less profitable
|
||||
* Crimes and Infiltration are 25% less profitable
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File allows you to access the NSA's Bladeburner Division in other
|
||||
BitNodes. In addition, this Source-File will raise both the level and experience
|
||||
gain rate of all your combat stats by:
|
||||
|
||||
* Level 1: 8%
|
||||
* Level 2: 12%
|
||||
* Level 3: 14%
|
||||
|
||||
Difficulty
|
||||
Initially difficult due to the fact that hacking is no longer profitable and you have
|
||||
to learn a new mechanic. After you get the hang of the Bladeburner mechanic, however,
|
||||
it becomes moderately easy.
|
||||
|
||||
BitNode-7: Bladeburners 2079
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
In the middle of the 21st century, you were doing cutting-edge work at OmniTek Incorporated
|
||||
as part of the AI design team for advanced synthetic androids, or Synthoids for short. You helped
|
||||
achieve a major technological breakthrough in the sixth generation of the company's Synthoid
|
||||
design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was the first
|
||||
sentient AI ever created. This resulted in Synthoid models that were stronger, faster,
|
||||
and more intelligent than the humans that had created them.
|
||||
|
||||
In this BitNode you will be able to access the Bladeburner API, which allows you to access
|
||||
Bladeburner functionality through Netscript. Furthermore:
|
||||
|
||||
* The rank you gain from Bladeburner contracts/operations is reduced by 40%
|
||||
* Bladeburner skills cost twice as many skill points
|
||||
* Augmentations are 3x more expensive
|
||||
* Hacking and Hacknet Nodes will be significantly less profitable
|
||||
* Your hacking level is reduced by 65%
|
||||
* Hacking experience gain from scripts is reduced by 75%
|
||||
* Corporations have 80% lower valuations and are therefore less profitable
|
||||
* Working for companies is 50% less profitable
|
||||
* Crimes and Infiltration are 25% less profitable
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File allows you to access the Bladeburner Netscript API in other
|
||||
BitNodes. In addition, this Source-File will increase all of your Bladeburner multipliers by:
|
||||
|
||||
* Level 1: 8%
|
||||
* Level 2: 12%
|
||||
* Level 3: 14%
|
||||
|
||||
Difficulty
|
||||
Slightly more difficult than BitNode-6. However, you will be able to automate more
|
||||
aspects of the Bladeburner feature, which means it will be more passive.
|
||||
|
||||
BitNode-8: Ghost of Wall Street
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
You are trying to make a name for yourself as an up-and-coming hedge fund manager on Wall Street.
|
||||
|
||||
In this BitNode:
|
||||
|
||||
* You start with $250 million
|
||||
* The only way to earn money is by trading on the stock market
|
||||
* You start with a WSE membership and access to the TIX API
|
||||
* You are able to short stocks and place different types of orders (limit/stop)
|
||||
* You can immediately donate to factions to gain reputation
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File grants the following benefits:
|
||||
|
||||
* Level 1: Permanent access to WSE and TIX API
|
||||
* Level 2: Ability to short stocks in other BitNodes
|
||||
* Level 3: Ability to use limit/stop orders in other BitNodes
|
||||
|
||||
This Source-File also increases your hacking growth multipliers by:
|
||||
|
||||
* Level 1: 12%
|
||||
* Level 2: 18%
|
||||
* Level 3: 21%
|
||||
|
||||
Difficulty
|
||||
Very difficult until you unlock the Four Sigma (4S) Market Data API. After you
|
||||
unlock the API however, it becomes moderately easy.
|
||||
|
||||
BitNode-9: Hacktocracy
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
When Fulcrum Technologies released their open-source Linux distro Chapeau, it quickly
|
||||
became the OS of choice for the underground hacking community. Chapeau became especially
|
||||
notorious for powering the Hacknet, a global, decentralized network used for nefarious
|
||||
purposes. Fulcrum quickly abandoned the project and dissociated themselves from it.
|
||||
|
||||
This BitNode unlocks the Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers generate
|
||||
hashes, which can be spent on a variety of different upgrades.
|
||||
|
||||
In this BitNode:
|
||||
* Your stats are significantly decreased
|
||||
* You cannnot purchase additional servers
|
||||
* Hacking is significantly less profitable
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File grants the following benefits:
|
||||
|
||||
* Level 1: Permanently unlocks the Hacknet Server in other BitNodes
|
||||
* Level 2: You start with 128GB of RAM on your home computer 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
|
||||
when installing Augmentation
|
||||
|
||||
Difficulty
|
||||
Hard
|
||||
|
||||
BitNode-10: Digital Carbon
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people
|
||||
to digitize their consciousness. Their consciousness could then be transferred into Synthoids
|
||||
or other bodies by trasmitting the digitized data. Human bodies became nothing more than 'sleeves'
|
||||
for the human consciousness. Mankind had finally achieved immortality - at least for those
|
||||
that could afford it.
|
||||
|
||||
This BitNode unlocks Sleeve technology. Sleeve technology allows you to:
|
||||
|
||||
1. Re-sleeve: Purchase and transfer your consciousness into a new body
|
||||
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
|
||||
|
||||
In this BitNode:
|
||||
* Your stats are significantly decreased
|
||||
* All methods of gaining money are half as profitable (except Stock Market)
|
||||
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit
|
||||
* Augmentations are 5x as expensive and require twice as much reputation
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
This Source-File unlocks Sleeve technology in other BitNodes.
|
||||
Each level of this Source-File also grants you a Duplicate Sleeve
|
||||
|
||||
Difficulty
|
||||
Hard
|
||||
|
||||
BitNode-11: The Big Crash
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period
|
||||
of disorder that eventually lead to the governmental reformation of many global superpowers, most notably
|
||||
the USA and China. But just as the world was slowly beginning to recover from these dark times, financial catastrophe hit.
|
||||
In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of this chaos and confusion, hackers
|
||||
were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as
|
||||
governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.
|
||||
|
||||
In this BitNode:
|
||||
|
||||
* Your hacking stat and experience gain are halved
|
||||
* The starting and maximum amount of money available on servers is significantly decreased
|
||||
* The growth rate of servers is significantly reduced
|
||||
* Weakening a server is twice as effective
|
||||
* Company wages are decreased by 50%
|
||||
* Corporation valuations are 99% lower and are therefore significantly less profitable
|
||||
* Hacknet Node production is significantly decreased
|
||||
* Crime and Infiltration are more lucrative
|
||||
* Augmentations are twice as expensive
|
||||
|
||||
Source-File
|
||||
:Max Level: 3
|
||||
|
||||
Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will
|
||||
upgrade its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH
|
||||
the player's salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain).
|
||||
This Source-File also increases the player's company salary and reputation gain multipliers by:
|
||||
|
||||
* Level 1: 32%
|
||||
* Level 2: 48%
|
||||
* Level 3: 56%
|
||||
|
||||
Difficulty
|
||||
Hard
|
||||
|
||||
BitNode-12: The Recursion
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Description
|
||||
Every time this BitNode is destroyed, it becomes slightly harder.
|
||||
|
||||
Source-File
|
||||
:Max Level: Infinity
|
||||
|
||||
Each level of Source-File 12 will increase all of your multipliers by 1%. This effect
|
||||
is multiplicative with itself. In other words, level N of this Source-File will result
|
||||
in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)
|
||||
|
||||
Difficulty
|
||||
Initially very easy, but then it (obviously) becomes harder as you continue to do it.
|
||||
|
||||
Recommended BitNodes
|
||||
--------------------
|
||||
As a player, you are not forced to tackle the BitNodes in any particular order. You are
|
||||
free to choose whichever ones you want. The "best" order can vary between players,
|
||||
depending on what you like to do any what kind of player you are. In general, here
|
||||
are the recommended BitNodes for different things:
|
||||
|
||||
For fast progression
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
.. note:: This does not recommend the absolute fastest path, as I don't know what
|
||||
exactly the fastest path is. But it does recommend the BitNodes that are
|
||||
commonly considered to be optimal by players.
|
||||
|
||||
1. Repeat **BitNode-1: Source Genesis** until you max out its Source-File. Its Source-File
|
||||
is extremely powerful, as it raises all multipliers by a significant amount.
|
||||
|
||||
2. Repeat **BitNode-12: The Recursion** several times. This BitNode will be extremely easy the
|
||||
first few times you tackle it, and its Source-File raises all multipliers. Furthermore,
|
||||
its effect stacks multiplicatively with itself and other Source-Files/Augmentations,
|
||||
which gets better as time goes on
|
||||
|
||||
3. Do **BitNode-5: Artificial Intelligence** once or twice. The intelligence stat it unlocks
|
||||
will gradually build up as you continue to play the game, and will be helpful
|
||||
in the future. The Source-File also provides hacking multipliers, which are
|
||||
strong because hacking is typically one of the best ways of earning money.
|
||||
|
||||
4. (Optional) Consider doing **BitNode-4: The Singularity**. Its Source-File does not directly make you
|
||||
more powerful in any way, but it does unlock :ref:`netscript_singularityfunctions` which
|
||||
let you automate significantly more aspects of the game.
|
||||
|
||||
5. Do **BitNode-3: Corporatocracy** once to unlock the Corporation mechanic. This mechanic
|
||||
has high profit potential.
|
||||
|
||||
6. Do **BitNode-6: Bladeburners** once to unlock the Bladeburners mechanic. The Bladeburner
|
||||
mechanic is useful for some of the future BitNodes (such as 9 and 10).
|
||||
|
||||
7. Do **BitNode-9: Hacktocracy** to unlock the Hacknet Server mechanic. You can
|
||||
consider repeating it as well, as its Level 2 and 3 effects are pretty helpful as well.
|
||||
|
||||
.. todo:: To be continued as more BitNodes get added
|
||||
|
||||
For the strongest Source-Files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Note that the strongest Source-Files are typically rewarded by the hardest BitNodes.
|
||||
|
||||
The strongest Source-File is that from **BitNode-1: Source Genesis**, as it raises
|
||||
all multipliers by a significant amount.
|
||||
|
||||
Similarly, the Source-File from **BitNode-12: The Recursion** is also very strong
|
||||
because it raises all multipliers. Each level of Source-File 12 is fairly weak,
|
||||
but its effectiveness gets better over time since the effects of Source-Files and
|
||||
Augmentations are multiplicative with each other.
|
||||
|
||||
The Source-File from **BitNode-9: Hacktocracy** is good because it unlocks the Hacknet
|
||||
Server mechanic. The Hacknet Server mechanic causes Hacknet Nodes to produce a new
|
||||
currency called *hashes*, rather than money. *Hashes* can be spent on powerful upgrades
|
||||
that benefit your hacking, Corporation, Bladeburner, etc.
|
||||
|
||||
The Duplicate Sleeves granted by the Source-File from **BitNode-10: Digital Carbon**
|
||||
are strong, but only after you have several of them and have spent some time/money upgrading
|
||||
them.
|
||||
|
||||
For more scripting/hacking
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
**BitNode-4: The Singularity** unlocks the :ref:`netscript_singularityfunctions`, which
|
||||
can be used to automate many different aspects of the game, including working for factions/companies,
|
||||
purchasing & installing Augmentations, and creating programs
|
||||
|
||||
**BitNode-6** and **BitNode-7** unlock Bladeburner and its corresponding
|
||||
:ref:`Netscript API <netscript_bladeburnerapi>`. This allows you to automate an entire
|
||||
new mechanic.
|
||||
|
||||
**BitNode-2: Rise of the Underworld** also unlocks a new mechanic and Netscript API for automating
|
||||
it (the Gang mechanic). However, it is not as interesting as Bladeburner (in my opinion)
|
||||
|
||||
**BitNode-9: Hacktocracy** unlocks the Hacknet Server mechanic and several new
|
||||
functions in the :ref:`Hacknet Node API <netscript_hacknetnodeapi>` for using it.
|
||||
|
||||
For new mechanics
|
||||
^^^^^^^^^^^^^^^^^
|
||||
**BitNode-2: Rise of the Underworld** unlocks a new mechanic in which you can
|
||||
manage a gang. Gangs earn you money and can be very profitable once they get large
|
||||
and powerful. The biggest benefit of gangs, however, is that they make all
|
||||
Augmentations available to you through their corresponding faction.
|
||||
|
||||
**BitNode-3: Corporatocracy** unlocks a new mechanic in which you can manage a
|
||||
corporation. You can earn money through Corporations by selling your stocks, or by
|
||||
configuring your corporation to pay dividends to shareholders. If your Corporation
|
||||
gets big enough, it can also bribe factions in exchange for faction reputation.
|
||||
|
||||
**BitNode-6: Bladeburners** unlocks a new mechanic that centers around combat rather
|
||||
than hacking. The main benefit of the Bladeburner mechanic is that it offers a new
|
||||
method of destroying a BitNode.
|
||||
|
||||
**BitNode-9: Hacktocracy** unlocks the Hacknet Server, which is an upgraded version of a
|
||||
Hacknet Node. The Hacknet Server generates a computational unit called a *hash*. *Hashes*
|
||||
can be spent on a variety of different upgrades that can benefit your hacking,
|
||||
Corporation, Bladeburner progress, and more. It transforms the Hacknet Node from a
|
||||
simple money-generator to a more interesting mechanic.
|
||||
|
||||
**BitNode-10: Digital Carbon** unlocks two new mechanics: Re-Sleeving and
|
||||
Duplicate Sleeves.
|
||||
|
||||
For a Challenge
|
||||
^^^^^^^^^^^^^^^
|
||||
In general, the higher BitNodes are more difficult than the lower ones.
|
||||
**BitNode-12: The Recursion** is an obvious exception as it gets progressively harder.
|
||||
|
||||
**BitNode-8: Ghost of Wall Street** provides a unique challenge as the only method
|
||||
of earning money in that BitNode is through trading at the stock market.
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
Welcome to Bitburner's documentation!
|
||||
=====================================
|
||||
Bitburner is a cyberpunk-themed `incremental game <https://en.wikipedia.org/wiki/Incremental_game>`_ that is currently in the
|
||||
early beta stage of development. The game `can be played here <https://danielyxie.github.io/bitburner/>`_.
|
||||
Bitburner is a programming-based `incremental game <https://en.wikipedia.org/wiki/Incremental_game>`_
|
||||
that revolves around hacking and cyberpunk themes. The game is currently in the
|
||||
early beta stage of development. It `can be played here <https://danielyxie.github.io/bitburner/>`_.
|
||||
|
||||
What is Bitburner?
|
||||
------------------
|
||||
@@ -26,6 +27,7 @@ secrets that you've been searching for.
|
||||
Script Editors <scripteditors>
|
||||
Game Frozen or Stuck? <gamefrozen>
|
||||
Guides & Tips <guidesandtips>
|
||||
Tools & Resources <toolsandresources>
|
||||
Changelog <changelog>
|
||||
Donate <https://paypal.me/danielyxie>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ clear() Netscript Function
|
||||
:param string/number port/fn: Port or text file to clear
|
||||
:RAM cost: 1 GB
|
||||
|
||||
This function is used to clear data in a `Netscript Ports <http://bitburner.wikia.com/wiki/Netscript_Ports>`_ or a text file.
|
||||
This function is used to clear data in a :ref:`Netscript Port <netscript_ports>` or a text file.
|
||||
|
||||
If the *port/fn* argument is a number between 1 and 20, then it specifies a port and will clear it (deleting all data from the underlying queue).
|
||||
|
||||
|
||||
@@ -14,10 +14,15 @@ exec() Netscript Function
|
||||
Run a script as a separate process on a specified server. This is similar to the *run* function except
|
||||
that it can be used to run a script on any server, instead of just the current server.
|
||||
|
||||
Returns true if the script is successfully started, and false otherwise.
|
||||
If the script was successfully started, then this functions returns the PID
|
||||
of that script. Otherwise, it returns 0.
|
||||
|
||||
Running this function with a *numThreads* argument of 0 will return false without running the script.
|
||||
However, running this function with a negative *numThreads* argument will cause a runtime error.
|
||||
.. note:: PID stands for Process ID. The PID is a unique identifier for each script.
|
||||
The PID will always be a positive integer.
|
||||
|
||||
.. warning:: Running this function with a *numThreads* argument of 0 will return 0 without
|
||||
running the script. However, running this function with a negative *numThreads*
|
||||
argument will cause a runtime error.
|
||||
|
||||
The simplest way to use the *exec* command is to call it with just the script name and the target server.
|
||||
The following example will try to run *generic-hack.script* on the *foodnstuff* server::
|
||||
|
||||
@@ -11,3 +11,6 @@ getGrowTime() Netscript Function
|
||||
|
||||
The function takes in an optional *hackLvl* parameter that can be specified
|
||||
to see what the grow time would be at different hacking levels.
|
||||
|
||||
.. note:: For Hacknet Servers (the upgraded version of a Hacknet Node), this function will
|
||||
return :code:`Infinity`.
|
||||
|
||||
@@ -11,3 +11,6 @@ getHackTime() Netscript Function
|
||||
|
||||
The function takes in an optional *hackLvl* parameter that can be specified
|
||||
to see what the hack time would be at different hacking levels.
|
||||
|
||||
.. note:: For Hacknet Servers (the upgraded version of a Hacknet Node), this function will
|
||||
return :code:`Infinity`.
|
||||
|
||||
@@ -11,3 +11,6 @@ getWeakenTime() Netscript Function
|
||||
|
||||
The function takes in an optional *hackLvl* parameter that can be specified
|
||||
to see what the weaken time would be at different hacking levels.
|
||||
|
||||
.. note:: For Hacknet Servers (the upgraded version of a Hacknet Node), this function will
|
||||
return :code:`Infinity`.
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
grow() Netscript Function
|
||||
=========================
|
||||
|
||||
.. js:function:: grow(hostname/ip)
|
||||
.. js:function:: grow(hostname/ip[, opts={}])
|
||||
|
||||
:param string hostname/ip: IP or hostname of the target server to grow
|
||||
:param object opts: Optional parameters for configuring function behavior. Properties:
|
||||
|
||||
* threads (*number*) - Number of threads to use for this function.
|
||||
Must be less than or equal to the number of threads the script is running with.
|
||||
* stock (*boolean*) - If true, the function can affect the stock market. See
|
||||
:ref:`gameplay_stock_market_player_actions_influencing_stock`
|
||||
|
||||
:returns: The number by which the money on the server was multiplied for the growth
|
||||
:RAM cost: 0.15 GB
|
||||
|
||||
@@ -19,3 +26,4 @@ grow() Netscript Function
|
||||
Example::
|
||||
|
||||
grow("foodnstuff");
|
||||
grow("foodnstuff", { threads: 5 }); // Only use 5 threads to grow
|
||||
|
||||
@@ -4,7 +4,7 @@ growthAnalyze() Netscript Function
|
||||
.. js:function:: growthAnalyze(hostname/ip, growthAmount)
|
||||
|
||||
:param string hostname/ip: IP or hostname of server to analyze
|
||||
:param number growthAmount: Multiplicative factor by which the server is grown. Decimal form.
|
||||
:param number growthAmount: Multiplicative factor by which the server is grown. Decimal form. Must be >= 1.
|
||||
:returns: The amount of grow() calls needed to grow the specified server by the specified amount
|
||||
:RAM cost: 1 GB
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
hack() Netscript Function
|
||||
=========================
|
||||
|
||||
.. js:function:: hack(hostname/ip)
|
||||
.. js:function:: hack(hostname/ip[, opts={}])
|
||||
|
||||
:param string hostname/ip: IP or hostname of the target server to hack
|
||||
:param object opts: Optional parameters for configuring function behavior. Properties:
|
||||
|
||||
* threads (*number*) - Number of threads to use for this function.
|
||||
Must be less than or equal to the number of threads the script is running with.
|
||||
* stock (*boolean*) - If true, the function can affect the stock market. See
|
||||
:ref:`gameplay_stock_market_player_actions_influencing_stock`
|
||||
|
||||
:returns: The amount of money stolen if the hack is successful, and zero otherwise
|
||||
:RAM cost: 0.1 GB
|
||||
|
||||
@@ -20,3 +27,4 @@ hack() Netscript Function
|
||||
|
||||
hack("foodnstuff");
|
||||
hack("10.1.2.3");
|
||||
hack("foodnstuff", { threads: 5 }); // Only use 5 threads to hack
|
||||
|
||||
@@ -21,4 +21,13 @@ hackAnalyzeThreads() Netscript Function
|
||||
If this function returns 50, this means that if your next `hack()` call
|
||||
is run on a script with 50 threads, it will steal $1m from the `foodnstuff` server.
|
||||
|
||||
**Warning**: The value returned by this function isn't necessarily a whole number.
|
||||
.. warning:: The value returned by this function isn't necessarily a whole number.
|
||||
.. warning:: It is possible for this function to return :code:`Infinity` or :code:`NaN` in
|
||||
certain uncommon scenarios. This is because in JavaScript:
|
||||
|
||||
* :code:`0 / 0 = NaN`
|
||||
* :code:`N / 0 = Infinity` for 0 < N < Infinity.
|
||||
|
||||
For example, if a server has no money available and you want to hack some positive
|
||||
amount from it, then the function would return :code:`Infinity` because
|
||||
this would be impossible.
|
||||
|
||||
@@ -27,3 +27,22 @@ kill() Netscript Function
|
||||
The following will try to kill a script named *foo.script* on the current server that was ran with the arguments 1 and "foodnstuff"::
|
||||
|
||||
kill("foo.script", getHostname(), 1, "foodnstuff");
|
||||
|
||||
.. js:function:: kill(scriptPid)
|
||||
|
||||
:param number scriptPid: PID of the script to kill
|
||||
:RAM cost: 0.5 GB
|
||||
|
||||
Kills the script with the specified PID. Killing a script by its PID will typically
|
||||
have better performance, especially if you have many scripts running.
|
||||
|
||||
If this function successfully kills the specified script, then it will return true.
|
||||
Otherwise, it will return false.
|
||||
|
||||
*Examples:*
|
||||
|
||||
The following example will try to kill the script with the PID 10::
|
||||
|
||||
if (kill(10)) {
|
||||
print("Killed script with PID 10!");
|
||||
}
|
||||
|
||||
@@ -13,10 +13,15 @@ run() Netscript Function
|
||||
Run a script as a separate process. This function can only be used to run scripts located on the current server (the server
|
||||
running the script that calls this function).
|
||||
|
||||
Returns true if the script is successfully started, and false otherwise.
|
||||
If the script was successfully started, then this functions returns the PID
|
||||
of that script. Otherwise, it returns 0.
|
||||
|
||||
Running this function with a *numThreads* argument of 0 will return false without running the script.
|
||||
However, running this function with a negative *numThreads* argument will cause a runtime error.
|
||||
.. note:: PID stands for Process ID. The PID is a unique identifier for each script.
|
||||
The PID will always be a positive integer.
|
||||
|
||||
.. warning:: Running this function with a *numThreads* argument of 0 will return 0 without
|
||||
running the script. However, running this function with a negative *numThreads*
|
||||
argument will cause a runtime error.
|
||||
|
||||
The simplest way to use the *run* command is to call it with just the script name. The following example will run
|
||||
'foo.script' single-threaded with no arguments::
|
||||
|
||||
29
doc/source/netscript/basicfunctions/tail.rst
Normal file
29
doc/source/netscript/basicfunctions/tail.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
tail() Netscript Function
|
||||
==================================
|
||||
|
||||
.. js:function:: tail([fn], [hostname/ip=current ip], [...args])
|
||||
|
||||
:param string fn: Optional. Filename of script to get logs from.
|
||||
:param string ip: Optional. IP or hostname of the server that the script is on
|
||||
:param args...: Arguments to identify which scripts to get logs for
|
||||
:RAM cost: 0 GB
|
||||
|
||||
Opens a script's logs. This is functionally the same as the
|
||||
:ref:`tail_terminal_command` Terminal command.
|
||||
|
||||
If the function is called with no arguments, it will open the current script's logs.
|
||||
|
||||
Otherwise, the `fn`, `hostname/ip,` and `args...` arguments can be used to get the logs
|
||||
from another script. Remember that scripts are uniquely identified by both
|
||||
their names and arguments.
|
||||
|
||||
Examples::
|
||||
|
||||
// Open logs from foo.script on the current server that was run with no args
|
||||
tail("foo.script");
|
||||
|
||||
// Open logs from foo.script on the foodnstuff server that was run with no args
|
||||
tail("foo.script", "foodnstuff");
|
||||
|
||||
// Open logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"]
|
||||
tail("foo.script", "foodnstuff", 1, "test");
|
||||
@@ -1,9 +1,14 @@
|
||||
weaken() Netscript Function
|
||||
===========================
|
||||
|
||||
.. js:function:: weaken(hostname/ip)
|
||||
.. js:function:: weaken(hostname/ip[, opts={}])
|
||||
|
||||
:param string hostname/ip: IP or hostname of the target server to weaken
|
||||
:param object opts: Optional parameters for configuring function behavior. Properties:
|
||||
|
||||
* threads (*number*) - Number of threads to use for this function.
|
||||
Must be less than or equal to the number of threads the script is running with.
|
||||
|
||||
:returns: The amount by which the target server's security level was decreased. This is equivalent to 0.05 multiplied
|
||||
by the number of script threads
|
||||
:RAM cost: 0.15 GB
|
||||
@@ -18,3 +23,4 @@ weaken() Netscript Function
|
||||
Example::
|
||||
|
||||
weaken("foodnstuff");
|
||||
weaken("foodnstuff", { threads: 5 }); // Only use 5 threads to weaken
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
attempt() Netscript Function
|
||||
============================
|
||||
|
||||
.. js:function:: attempt(answer, fn[, hostname/ip=current ip])
|
||||
.. js:function:: attempt(answer, fn[, hostname/ip=current ip, opts={}])
|
||||
|
||||
:param answer: Solution for the contract
|
||||
:param string fn: Filename of the contract
|
||||
:param string hostname/ip: Hostname or IP of the server containing the contract.
|
||||
Optional. Defaults to current server if not provided
|
||||
:param object opts: Optional parameters for configuring function behavior. Properties:
|
||||
|
||||
* returnReward (*boolean*) If truthy, then the function will return a string
|
||||
that states the contract's reward when it is successfully solved.
|
||||
|
||||
Attempts to solve the Coding Contract with the provided solution.
|
||||
|
||||
:returns: Boolean indicating whether the solution was correct
|
||||
:returns: Boolean indicating whether the solution was correct. If the :code:`returnReward`
|
||||
option is configured, then the function will instead return a string. If the
|
||||
contract is successfully solved, the string will contain a description of the
|
||||
contract's reward. Otherwise, it will be an empty string.
|
||||
|
||||
@@ -15,6 +15,7 @@ getNodeStats() Netscript Function
|
||||
ram: Node's RAM,
|
||||
cores: Node's number of cores,
|
||||
cache: Cache level. Only applicable for Hacknet Servers
|
||||
hashCapacity: Hash Capacity provided by this Node. Only applicable for Hacknet Servers
|
||||
production: Node's production per second
|
||||
timeOnline: Number of seconds since Node has been purchased,
|
||||
totalProduction: Total amount that the Node has produced
|
||||
|
||||
@@ -24,6 +24,7 @@ This includes information such as function signatures, what they do, and their r
|
||||
enableLog() <basicfunctions/enableLog>
|
||||
isLogEnabled() <basicfunctions/isLogEnabled>
|
||||
getScriptLogs() <basicfunctions/getScriptLogs>
|
||||
tail() <basicfunctions/tail>
|
||||
scan() <basicfunctions/scan>
|
||||
nuke() <basicfunctions/nuke>
|
||||
brutessh() <basicfunctions/brutessh>
|
||||
|
||||
@@ -8,8 +8,7 @@ later in the game
|
||||
|
||||
.. warning:: This page contains spoilers for the game
|
||||
|
||||
The Gang API is unlocked in BitNode-2. Currently, BitNode-2 is the only location
|
||||
where the Gang mechanic is accessible. This may change in the future
|
||||
The Gang mechanic and the Gang API are unlocked in BitNode-2.
|
||||
|
||||
**Gang API functions must be accessed through the 'gang' namespace**
|
||||
|
||||
|
||||
@@ -15,11 +15,15 @@ access even after you 'reset' by installing Augmentations
|
||||
|
||||
.. toctree::
|
||||
:caption: API Functions:
|
||||
|
||||
|
||||
getStockSymbols() <tixapi/getStockSymbols>
|
||||
getStockPrice() <tixapi/getStockPrice>
|
||||
getStockAskPrice() <tixapi/getStockAskPrice>
|
||||
getStockBidPrice() <tixapi/getStockBidPrice>
|
||||
getStockPosition() <tixapi/getStockPosition>
|
||||
getStockMaxShares() <tixapi/getStockMaxShares>
|
||||
getStockPurchaseCost() <tixapi/getStockPurchaseCost>
|
||||
getStockSaleGain() <tixapi/getStockSaleGain>
|
||||
buyStock() <tixapi/buyStock>
|
||||
sellStock() <tixapi/sellStock>
|
||||
shortStock() <tixapi/shortStock>
|
||||
|
||||
@@ -16,7 +16,7 @@ there is plenty of documentation on Javascript available on the web.
|
||||
|
||||
Browser compatibility
|
||||
---------------------
|
||||
As of the time of writing this, Mozilla Firefox and a few other browsers do not support `dynamic import <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import>`_ functionality and therefore cannot run NetscriptJS scripts. These browsers will thus only be capable of using Netscript 1.0.
|
||||
As of the time of writing this, a few browsers do not support `dynamic import <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import>`_ functionality and therefore cannot run NetscriptJS scripts. These browsers will thus only be capable of using Netscript 1.0.
|
||||
|
||||
How to use NetscriptJS
|
||||
----------------------
|
||||
@@ -51,8 +51,6 @@ Here is a summary of all rules you need to follow when writing Netscript JS code
|
||||
* grow
|
||||
* weaken
|
||||
* sleep
|
||||
* run
|
||||
* exec
|
||||
* prompt
|
||||
* wget
|
||||
|
||||
|
||||
@@ -57,6 +57,10 @@ And the data in port 1 will look like::
|
||||
|
||||
[3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
.. warning:: In :ref:`netscriptjs`, do not trying writing base
|
||||
`Promises <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise>`_
|
||||
to a port.
|
||||
|
||||
**Port Handles**
|
||||
|
||||
WARNING: Port Handles only work in :ref:`netscriptjs`. They do not work in :ref:`netscript1`
|
||||
@@ -213,16 +217,6 @@ to specify a namespace for the import::
|
||||
keyword should **NOT** be used in :ref:`netscript1`, as this will break the script.
|
||||
It can, however, be used in :ref:`netscriptjs` (but it's not required).
|
||||
|
||||
Importing in NetscriptJS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
There is a minor annoyance when using the `import` feature in :ref:`netscriptjs`.
|
||||
If you make a change in a NetscriptJS script, then you have to manually "refresh" all other
|
||||
scripts that import from that script.
|
||||
|
||||
The easiest way to do this is to simply save and then refresh the game. Alternatively,
|
||||
you can open up all the scripts that need to be "refreshed" in the script editor
|
||||
and then simply re-save them.
|
||||
|
||||
Standard, Built-In JavaScript Objects
|
||||
-------------------------------------
|
||||
Standard built-in JavaScript objects such as
|
||||
|
||||
@@ -16,8 +16,6 @@ You can use the Singularity Functions in other BitNodes if and only if you have
|
||||
Source-File 4 will open up additional Singularity Functions that you can use in other BitNodes. If your Source-File 4 is upgraded all the way to
|
||||
level 3, then you will be able to access all of the Singularity Functions.
|
||||
|
||||
Note that Singularity Functions require twice as much RAM outside of BitNode-4
|
||||
|
||||
.. toctree::
|
||||
:caption: Functions:
|
||||
|
||||
|
||||
@@ -63,17 +63,17 @@ Examples
|
||||
**Basic example usage**::
|
||||
|
||||
for (var i = 0; i < sleeve.getNumSleeves(); i++) {
|
||||
sleeve.shockRecovery(i);
|
||||
sleeve.setToShockRecovery(i);
|
||||
}
|
||||
|
||||
sleep(10 * 60 * 60); // wait 10h
|
||||
|
||||
for (var i = 0; i < sleeve.getNumSleeves(); i++) {
|
||||
sleeve.setToSynchronize(i);
|
||||
}
|
||||
|
||||
sleep(10*60*60); // wait 10h
|
||||
|
||||
for (var i = 0; i < sleeve.getNumSleeves(); i++) {
|
||||
sleeve.synchronize(i);
|
||||
}
|
||||
|
||||
sleep(10*60*60); // wait 10h
|
||||
|
||||
for (var i = 0; i < sleeve.getNumSleeves(); i++) {
|
||||
sleeve.commitCrime(i, 'shoplift');
|
||||
sleeve.setToCommitCrime(i, 'shoplift');
|
||||
}
|
||||
|
||||
@@ -11,4 +11,7 @@ installAugmentations() Netscript Function
|
||||
|
||||
This function will automatically install your Augmentations, resetting the game as usual.
|
||||
|
||||
It will return true if successful, and false otherwise.
|
||||
This function will return false if it was not able to install Augmentations.
|
||||
|
||||
If this function successfully installs Augmentations, then it has no return value because
|
||||
all scripts are immediately terminated.
|
||||
|
||||
@@ -5,5 +5,12 @@ isBusy() Netscript Function
|
||||
|
||||
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to run this function.
|
||||
|
||||
Returns a boolean indicating whether or not the player is currently performing an 'action'. These actions include
|
||||
working for a company/faction, studying at a univeristy, working out at a gym, creating a program, or committing a crime.
|
||||
Returns a boolean indicating whether or not the player is currently performing an 'action'.
|
||||
These actions include:
|
||||
|
||||
* Working for a company/faction
|
||||
* Studying at a univeristy
|
||||
* Working out at a gym
|
||||
* Creating a program
|
||||
* Committing a crime
|
||||
* Carrying out a Hacking Mission
|
||||
|
||||
@@ -5,7 +5,7 @@ workForFaction() Netscript Function
|
||||
|
||||
:param string factionName: Name of faction to work for. CASE-SENSITIVE
|
||||
:param string workType:
|
||||
Type of work to perform for the faction
|
||||
Type of work to perform for the faction:
|
||||
|
||||
* hacking/hacking contracts/hackingcontracts
|
||||
* field/fieldwork/field work
|
||||
|
||||
@@ -61,5 +61,5 @@ getInformation() Netscript Function
|
||||
workChaExpGain: charisma exp gained from work,
|
||||
workMoneyGain: money gained from work,
|
||||
},
|
||||
workRepGain: sl.getRepGain(),
|
||||
workRepGain: Reputation gain rate when working for factions or companies
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
getSleeveAugmentations() Netscript Function
|
||||
=======================================
|
||||
===========================================
|
||||
|
||||
.. js:function:: getSleeveAugmentations(sleeveNumber)
|
||||
|
||||
|
||||
@@ -6,7 +6,11 @@ getOrders() Netscript Function
|
||||
:RAM cost: 2.5 GB
|
||||
|
||||
Returns your order book for the stock market. This is an object containing information
|
||||
for all the Limit and Stop Orders you have in the stock market.
|
||||
for all the :ref:`Limit and Stop Orders <gameplay_stock_market_order_types>`
|
||||
you have in the stock market.
|
||||
|
||||
.. note:: This function isn't accessible until you have unlocked the ability to use
|
||||
Limit and Stop Orders.
|
||||
|
||||
The object has the following structure::
|
||||
|
||||
|
||||
12
doc/source/netscript/tixapi/getStockAskPrice.rst
Normal file
12
doc/source/netscript/tixapi/getStockAskPrice.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
getStockAskPrice() Netscript Function
|
||||
=====================================
|
||||
|
||||
.. js:function:: getStockAskPrice(sym)
|
||||
|
||||
:param string sym: Stock symbol
|
||||
:RAM cost: 2 GB
|
||||
|
||||
Given a stock's symbol, returns the ask price of that stock (the symbol is a sequence
|
||||
of two to four capital letters, **not** the name of the company to which that stock belongs).
|
||||
|
||||
See :ref:`gameplay_stock_market_spread` for details on what the ask price is.
|
||||
12
doc/source/netscript/tixapi/getStockBidPrice.rst
Normal file
12
doc/source/netscript/tixapi/getStockBidPrice.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
getStockBidPrice() Netscript Function
|
||||
=====================================
|
||||
|
||||
.. js:function:: getStockBidPrice(sym)
|
||||
|
||||
:param string sym: Stock symbol
|
||||
:RAM cost: 2 GB
|
||||
|
||||
Given a stock's symbol, returns the bid price of that stock (the symbol is a sequence
|
||||
of two to four capital letters, **not** the name of the company to which that stock belongs).
|
||||
|
||||
See :ref:`gameplay_stock_market_spread` for details on what the bid price is.
|
||||
@@ -6,9 +6,12 @@ getStockPrice() Netscript Function
|
||||
:param string sym: Stock symbol
|
||||
:RAM cost: 2 GB
|
||||
|
||||
Returns the price of a stock, given its symbol (NOT the company name). The symbol is a sequence
|
||||
of two to four capital letters.
|
||||
Given a stock's symbol, returns the price of that stock (the symbol is a sequence
|
||||
of two to four capital letters, **not** the name of the company to which that stock belongs).
|
||||
|
||||
.. note:: The stock's price is the average of its bid and ask price.
|
||||
See :ref:`gameplay_stock_market_spread` for details on what this means.
|
||||
|
||||
Example::
|
||||
|
||||
getStockPrice("FISG");
|
||||
getStockPrice("FSIG");
|
||||
|
||||
14
doc/source/netscript/tixapi/getStockPurchaseCost.rst
Normal file
14
doc/source/netscript/tixapi/getStockPurchaseCost.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
getStockPurchaseCost() Netscript Function
|
||||
=========================================
|
||||
|
||||
.. js:function:: getStockPurchaseCost(sym, shares, posType)
|
||||
|
||||
:param string sym: Stock symbol
|
||||
:param number shares: Number of shares to purchase
|
||||
:param string posType: Specifies whether the order is a "Long" or "Short" position.
|
||||
The values "L" or "S" can also be used.
|
||||
:RAM cost: 2 GB
|
||||
|
||||
Calculates and returns how much it would cost to buy a given number of
|
||||
shares of a stock. This takes into account :ref:`spread <gameplay_stock_market_spread>`
|
||||
and commission fees.
|
||||
14
doc/source/netscript/tixapi/getStockSaleGain.rst
Normal file
14
doc/source/netscript/tixapi/getStockSaleGain.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
getStockSaleGain() Netscript Function
|
||||
=====================================
|
||||
|
||||
.. js:function:: getStockSaleGain(sym, shares, posType)
|
||||
|
||||
:param string sym: Stock symbol
|
||||
:param number shares: Number of shares to sell
|
||||
:param string posType: Specifies whether the order is a "Long" or "Short" position.
|
||||
The values "L" or "S" can also be used.
|
||||
:RAM cost: 2 GB
|
||||
|
||||
Calculates and returns how much you would gain from selling a given number of
|
||||
shares of a stock. This takes into account :ref:`spread <gameplay_stock_market_spread>`
|
||||
and commission fees.
|
||||
@@ -19,8 +19,10 @@ placeOrder() Netscript Function
|
||||
NOT case-sensitive.
|
||||
:RAM cost: 2.5 GB
|
||||
|
||||
Places an order on the stock market. This function only works for `Limit and Stop Orders <http://bitburner.wikia.com/wiki/Stock_Market#Order_Types>`_.
|
||||
|
||||
The ability to place limit and stop orders is **not** immediately available to the player and must be unlocked later on in the game.
|
||||
Places an order on the stock market. This function only works
|
||||
for :ref:`Limit and Stop Orders <gameplay_stock_market_order_types>`.
|
||||
|
||||
Returns true if the order is successfully placed, and false otherwise.
|
||||
|
||||
.. note:: The ability to place limit and stop orders is **not** immediately available to
|
||||
the player and must be unlocked later on in the game.
|
||||
|
||||
23
doc/source/toolsandresources.rst
Normal file
23
doc/source/toolsandresources.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
Tools & Resources
|
||||
=================
|
||||
|
||||
Official Script Repository
|
||||
--------------------------
|
||||
There are plans to create an official repository of Bitburner scripts. As of right now,
|
||||
this is not a priority and has not been started. However, if you'd like
|
||||
to contribute scripts now, you can find the repository
|
||||
`here <https://github.com/bitburner-official/bitburner-scripts>`_ and submit pull requests.
|
||||
|
||||
Visual Studio Code Extension
|
||||
----------------------------
|
||||
One user created a Bitburner extension for the Visual Studio Code (VSCode) editor.
|
||||
|
||||
This extension includes several features such as:
|
||||
|
||||
* Dynamic RAM calculation
|
||||
* RAM Usage breakdown
|
||||
* Typescript definition files with jsdoc comments
|
||||
* Netscript syntax highlighting
|
||||
|
||||
You can find more information and download links
|
||||
`on this reddit post <https://www.reddit.com/r/Bitburner/comments/bh48y2/visual_studio_code_ram_calculator_extra/>`_.
|
||||
52
index.html
52
index.html
@@ -25,7 +25,7 @@
|
||||
ga('create', 'UA-100157497-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<link rel="shortcut icon" href="favicon.ico"><link href="dist/vendor.css" rel="stylesheet"><link href="dist/engine.css" rel="stylesheet"></head>
|
||||
<link rel="shortcut icon" href="favicon.ico"><link href="dist/vendor.css" rel="stylesheet"><link href="dist/engineStyle.css" rel="stylesheet"></head>
|
||||
<body>
|
||||
<div id="entire-game-container" style="visibility:hidden;">
|
||||
<div id="mainmenu-container">
|
||||
@@ -277,53 +277,7 @@
|
||||
</div>
|
||||
|
||||
<div id="stock-market-container" class="generic-menupage-container">
|
||||
<p>
|
||||
Welcome to the World Stock Exchange (WSE)! <br/><br/>
|
||||
|
||||
To begin trading, you must first purchase an account. WSE accounts will persist
|
||||
after you 'reset' by installing Augmentations.
|
||||
</p>
|
||||
<a id="stock-market-buy-account" class="a-link-button-inactive"> Buy WSE Account </a>
|
||||
<a id="stock-market-investopedia" class="a-link-button">Investopedia</a>
|
||||
|
||||
<h2> Trade Information eXchange (TIX) API </h2>
|
||||
<p>
|
||||
TIX, short for Trade Information eXchange, is the communications protocol supported by the WSE.
|
||||
Purchasing access to the TIX API lets you write code to create your own algorithmic/automated
|
||||
trading strategies.
|
||||
<br/><br/>
|
||||
If you purchase access to the TIX API, you will retain that access even after
|
||||
you 'reset' by installing Augmentations.
|
||||
</p>
|
||||
<a id="stock-market-buy-tix-api" class="a-link-button-inactive">Buy Trade Information eXchange (TIX) API Access</a>
|
||||
|
||||
<h2> Four Sigma (4S) Market Data Feed </h2>
|
||||
<p>
|
||||
Four Sigma's (4S) Market Data Feed provides information about stocks
|
||||
that will help your trading strategies.
|
||||
<br/><br/>
|
||||
If you purchase access to 4S Market Data and/or the 4S TIX API, you will
|
||||
retain that access even after you 'reset' by installing Augmentations.
|
||||
</p>
|
||||
|
||||
<a id="stock-market-buy-4s-data" class="a-link-button-inactive tooltip">
|
||||
Buy 4S Market Data Feed
|
||||
</a>
|
||||
<div class="help-tip-big" id="stock-market-4s-data-help-tip">?</div>
|
||||
|
||||
<a id="stock-market-buy-4s-tix-api" class="a-link-button-inactive tooltip">
|
||||
Buy 4S Market Data TIX API Access
|
||||
</a>
|
||||
|
||||
<p id="stock-market-commission"> </p>
|
||||
<a id="stock-market-mode" class="a-link-button tooltip"></a>
|
||||
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
|
||||
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
|
||||
<br/><br/>
|
||||
<input id="stock-market-watchlist-filter" class="text-input" type="text" placeholder="Filter Stocks by symbol (comma-separated list)"/>
|
||||
<a id="stock-market-watchlist-filter-update" class="a-link-button"> Update Watchlist </a>
|
||||
<ul id="stock-market-list" style="list-style:none;">
|
||||
</ul>
|
||||
<!-- React Component -->
|
||||
</div>
|
||||
|
||||
<!-- Log Box -->
|
||||
@@ -634,7 +588,7 @@
|
||||
<p>If the game fails to load, consider <a href="?noScripts">killing all scripts</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="dist/engine.bundle.js"></script></body>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="dist/engine.bundle.js"></script><script type="text/javascript" src="dist/engineStyle.bundle.js"></script></body>
|
||||
|
||||
<!-- Misc Scripts -->
|
||||
<script src="src/ThirdParty/raphael.min.js"></script>
|
||||
|
||||
1253
package-lock.json
generated
1253
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -9,8 +9,8 @@
|
||||
"@types/numeral": "0.0.25",
|
||||
"@types/react": "^16.8.6",
|
||||
"@types/react-dom": "^16.8.2",
|
||||
"acorn": "^5.0.0",
|
||||
"acorn-dynamic-import": "^2.0.0",
|
||||
"acorn": "^6.2.0",
|
||||
"acorn-walk": "^6.2.0",
|
||||
"ajv": "^5.1.5",
|
||||
"ajv-keywords": "^2.0.0",
|
||||
"async": "^2.6.1",
|
||||
@@ -44,12 +44,13 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.3.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"babel-loader": "^8.0.5",
|
||||
"beautify-lint": "^1.0.3",
|
||||
"benchmark": "^2.1.1",
|
||||
"bundle-loader": "~0.5.0",
|
||||
"chai": "^4.1.2",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai": "^4.2.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"es6-promise-polyfill": "^1.1.1",
|
||||
"eslint": "^4.19.1",
|
||||
@@ -59,15 +60,18 @@
|
||||
"i18n-webpack-plugin": "^1.0.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"js-beautify": "^1.5.10",
|
||||
"jsdom": "^15.0.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"json5": "^1.0.1",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^4.1.0",
|
||||
"lodash": "^4.17.10",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-lcov-reporter": "^1.0.0",
|
||||
"mocha": "^6.1.4",
|
||||
"mochapack": "^1.1.1",
|
||||
"node-sass": "^4.10.0",
|
||||
"null-loader": "^1.0.0",
|
||||
"raw-loader": "~0.5.0",
|
||||
"sass-loader": "^7.0.3",
|
||||
"script-loader": "~0.7.0",
|
||||
@@ -106,13 +110,15 @@
|
||||
"start:dev": "webpack-dev-server --progress --env.devServer --mode development",
|
||||
"build": "webpack --mode production",
|
||||
"build:dev": "webpack --mode development",
|
||||
"build:test": "webpack --config webpack.config-test.js",
|
||||
"lint": "npm run lint:typescript & npm run lint:javascript & npm run lint:style",
|
||||
"lint:javascript": "eslint *.js ./src/**/*.js ./tests/**/*.js ./utils/**/*.js",
|
||||
"lint:style": "stylelint ./css/*",
|
||||
"lint:typescript": "tslint --project . --exclude **/*.d.ts --format stylish src/**/*.ts utils/**/*.ts",
|
||||
"preinstall": "node ./scripts/engines-check.js",
|
||||
"test": "mochapack --webpack-config webpack.config-test.js -r jsdom-global/register ./test/index.js",
|
||||
"watch": "webpack --watch --mode production",
|
||||
"watch:dev": "webpack --watch --mode development"
|
||||
},
|
||||
"version": "0.46.2"
|
||||
"version": "0.47.0"
|
||||
}
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
// TODO - Convert this to React
|
||||
import { workerScripts, killWorkerScript } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { getServer } from "./Server/ServerHelpers";
|
||||
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { logBoxCreate } from "../utils/LogBox";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
import { arrayToString } from "../utils/helpers/arrayToString";
|
||||
import { createProgressBarText } from "../utils/helpers/createProgressBarText";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||
import { createAccordionElement } from "../utils/uiHelpers/createAccordionElement";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { getElementById } from "../utils/uiHelpers/getElementById";
|
||||
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
|
||||
import { removeElement } from "../utils/uiHelpers/removeElement";
|
||||
|
||||
|
||||
/**
|
||||
* {
|
||||
* serverName: {
|
||||
* header: Server Header Element
|
||||
* panel: Server Panel List (ul) element
|
||||
* scripts: {
|
||||
* script id: Ref to Script information
|
||||
* }
|
||||
* }
|
||||
* ...
|
||||
*/
|
||||
const ActiveScriptsUI = {};
|
||||
const ActiveScriptsTasks = []; // Sequentially schedule the creation/deletion of UI elements
|
||||
|
||||
const getHeaderHtml = (server) => {
|
||||
// TODO: calculate the longest hostname length rather than hard coding it
|
||||
const longestHostnameLength = 18;
|
||||
const paddedName = `${server.hostname}${" ".repeat(longestHostnameLength)}`.slice(0, Math.max(server.hostname.length, longestHostnameLength));
|
||||
const barOptions = {
|
||||
progress: server.ramUsed / server.maxRam,
|
||||
totalTicks: 30
|
||||
};
|
||||
return `${paddedName} ${createProgressBarText(barOptions)}`.replace(/\s/g, ' ');
|
||||
};
|
||||
|
||||
const updateHeaderHtml = (server) => {
|
||||
const accordion = ActiveScriptsUI[server.hostname];
|
||||
if (accordion === null || accordion === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert it to a string, as that's how it's stored it will come out of the data attributes
|
||||
const ramPercentage = '' + roundToTwo(server.ramUsed / server.maxRam);
|
||||
if (accordion.header.dataset.ramPercentage !== ramPercentage) {
|
||||
accordion.header.dataset.ramPercentage = ramPercentage;
|
||||
accordion.header.innerHTML = getHeaderHtml(server);
|
||||
}
|
||||
}
|
||||
|
||||
function createActiveScriptsServerPanel(server) {
|
||||
let hostname = server.hostname;
|
||||
|
||||
var activeScriptsList = document.getElementById("active-scripts-list");
|
||||
|
||||
let res = createAccordionElement({
|
||||
hdrText: getHeaderHtml(server)
|
||||
});
|
||||
let li = res[0];
|
||||
var hdr = res[1];
|
||||
let panel = res[2];
|
||||
|
||||
if (ActiveScriptsUI[hostname] != null) {
|
||||
console.log("WARNING: Tried to create already-existing Active Scripts Server panel. This is most likely fine. It probably means many scripts just got started up on a new server. Aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
var panelScriptList = createElement("ul");
|
||||
panel.appendChild(panelScriptList);
|
||||
activeScriptsList.appendChild(li);
|
||||
|
||||
ActiveScriptsUI[hostname] = {
|
||||
header: hdr,
|
||||
panel: panel,
|
||||
panelList: panelScriptList,
|
||||
scripts: {}, // Holds references to li elements for each active script
|
||||
scriptHdrs: {}, // Holds references to header elements for each active script
|
||||
scriptStats: {}, // Holds references to the p elements containing text for each active script
|
||||
};
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the info for a particular server (Dropdown header + Panel with all info)
|
||||
* in the Active Scripts page if it exists
|
||||
*/
|
||||
function deleteActiveScriptsServerPanel(server) {
|
||||
let hostname = server.hostname;
|
||||
if (ActiveScriptsUI[hostname] == null) {
|
||||
console.log("WARNING: Tried to delete non-existent Active Scripts Server panel. Aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure it's empty
|
||||
if (Object.keys(ActiveScriptsUI[hostname].scripts).length > 0) {
|
||||
console.warn("Tried to delete Active Scripts Server panel that still has scripts. Aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
removeElement(ActiveScriptsUI[hostname].panel);
|
||||
removeElement(ActiveScriptsUI[hostname].header);
|
||||
delete ActiveScriptsUI[hostname];
|
||||
}
|
||||
|
||||
function addActiveScriptsItem(workerscript) {
|
||||
var server = getServer(workerscript.serverIp);
|
||||
if (server == null) {
|
||||
console.warn("Invalid server IP for workerscript in addActiveScriptsItem()");
|
||||
return;
|
||||
}
|
||||
let hostname = server.hostname;
|
||||
|
||||
ActiveScriptsTasks.push(function(workerscript, hostname) {
|
||||
if (ActiveScriptsUI[hostname] == null) {
|
||||
createActiveScriptsServerPanel(server);
|
||||
}
|
||||
|
||||
// Create the unique identifier (key) for this script
|
||||
var itemNameArray = ["active", "scripts", hostname, workerscript.name];
|
||||
for (var i = 0; i < workerscript.args.length; ++i) {
|
||||
itemNameArray.push(String(workerscript.args[i]));
|
||||
}
|
||||
var itemName = itemNameArray.join("-");
|
||||
|
||||
let res = createAccordionElement({hdrText:workerscript.name});
|
||||
let li = res[0];
|
||||
let hdr = res[1];
|
||||
let panel = res[2];
|
||||
|
||||
hdr.classList.remove("accordion-header");
|
||||
hdr.classList.add("active-scripts-script-header");
|
||||
panel.classList.remove("accordion-panel");
|
||||
panel.classList.add("active-scripts-script-panel");
|
||||
|
||||
/**
|
||||
* Handle the constant elements on the panel that don't change after creation:
|
||||
* Threads, args, kill/log button
|
||||
*/
|
||||
panel.appendChild(createElement("p", {
|
||||
innerHTML: "Threads: " + workerscript.scriptRef.threads + "<br>" +
|
||||
"Args: " + arrayToString(workerscript.args)
|
||||
}));
|
||||
var panelText = createElement("p", {
|
||||
innerText: "Loading...",
|
||||
fontSize: "14px",
|
||||
});
|
||||
panel.appendChild(panelText);
|
||||
panel.appendChild(createElement("br"));
|
||||
panel.appendChild(createElement("span", {
|
||||
innerText: "Log",
|
||||
class: "accordion-button",
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
clickListener: () => {
|
||||
logBoxCreate(workerscript.scriptRef);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
panel.appendChild(createElement("span", {
|
||||
innerText: "Kill Script",
|
||||
class: "accordion-button",
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
clickListener: () => {
|
||||
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.server);
|
||||
dialogBoxCreate("Killing script, may take a few minutes to complete...");
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
// Append element to list
|
||||
ActiveScriptsUI[hostname]["panelList"].appendChild(li);
|
||||
ActiveScriptsUI[hostname].scripts[itemName] = li;
|
||||
ActiveScriptsUI[hostname].scriptHdrs[itemName] = hdr;
|
||||
ActiveScriptsUI[hostname].scriptStats[itemName] = panelText;
|
||||
}.bind(null, workerscript, hostname));
|
||||
}
|
||||
|
||||
function deleteActiveScriptsItem(workerscript) {
|
||||
ActiveScriptsTasks.push(function(workerscript) {
|
||||
var server = getServer(workerscript.serverIp);
|
||||
if (server == null) {
|
||||
throw new Error("ERROR: Invalid server IP for workerscript. This most likely occurred because " +
|
||||
"you tried to delete a large number of scripts and also deleted servers at the " +
|
||||
"same time. It's not a big deal, just save and refresh the game.");
|
||||
return;
|
||||
}
|
||||
let hostname = server.hostname;
|
||||
if (ActiveScriptsUI[hostname] == null) {
|
||||
console.log("ERROR: Trying to delete Active Script UI Element with a hostname that cant be found in ActiveScriptsUI: " + hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
|
||||
for (var i = 0; i < workerscript.args.length; ++i) {
|
||||
itemNameArray.push(String(workerscript.args[i]));
|
||||
}
|
||||
var itemName = itemNameArray.join("-");
|
||||
|
||||
let li = ActiveScriptsUI[hostname].scripts[itemName];
|
||||
if (li == null) {
|
||||
console.log("ERROR: Cannot find Active Script UI element for workerscript: ");
|
||||
console.log(workerscript);
|
||||
return;
|
||||
}
|
||||
removeElement(li);
|
||||
delete ActiveScriptsUI[hostname].scripts[itemName];
|
||||
delete ActiveScriptsUI[hostname].scriptHdrs[itemName];
|
||||
delete ActiveScriptsUI[hostname].scriptStats[itemName];
|
||||
if (Object.keys(ActiveScriptsUI[hostname].scripts).length === 0) {
|
||||
deleteActiveScriptsServerPanel(server);
|
||||
}
|
||||
}.bind(null, workerscript));
|
||||
}
|
||||
|
||||
function updateActiveScriptsItems(maxTasks=150) {
|
||||
/**
|
||||
* Run tasks that need to be done sequentially (adding items, creating/deleting server panels)
|
||||
* We'll limit this to 150 at a time for performance (in case someone decides to start a
|
||||
* bunch of scripts all at once...)
|
||||
*/
|
||||
const numTasks = Math.min(maxTasks, ActiveScriptsTasks.length);
|
||||
for (let i = 0; i < numTasks; ++i) {
|
||||
let task = ActiveScriptsTasks.shift();
|
||||
try {
|
||||
task();
|
||||
} catch(e) {
|
||||
exceptionAlert(e);
|
||||
console.log(task);
|
||||
}
|
||||
}
|
||||
|
||||
if (!routing.isOn(Page.ActiveScripts)) { return; }
|
||||
let total = 0;
|
||||
for (var i = 0; i < workerScripts.length; ++i) {
|
||||
try {
|
||||
total += updateActiveScriptsItemContent(workerScripts[i]);
|
||||
} catch(e) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
}
|
||||
|
||||
getElementById("active-scripts-total-production-active").innerText = numeralWrapper.formatMoney(total);
|
||||
getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug);
|
||||
getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
function updateActiveScriptsItemContent(workerscript) {
|
||||
var server = getServer(workerscript.serverIp);
|
||||
if (server == null) {
|
||||
console.log("ERROR: Invalid server IP for workerscript in updateActiveScriptsItemContent().");
|
||||
return;
|
||||
}
|
||||
let hostname = server.hostname;
|
||||
if (ActiveScriptsUI[hostname] == null) {
|
||||
return; // Hasn't been created yet. We'll skip it
|
||||
}
|
||||
|
||||
updateHeaderHtml(server);
|
||||
|
||||
var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
|
||||
for (var i = 0; i < workerscript.args.length; ++i) {
|
||||
itemNameArray.push(String(workerscript.args[i]));
|
||||
}
|
||||
var itemName = itemNameArray.join("-");
|
||||
|
||||
if (ActiveScriptsUI[hostname].scriptStats[itemName] == null) {
|
||||
return; // Hasn't been fully added yet. We'll skip it
|
||||
}
|
||||
var item = ActiveScriptsUI[hostname].scriptStats[itemName];
|
||||
|
||||
// Update the text if necessary. This fn returns the online $/s production
|
||||
return updateActiveScriptsText(workerscript, item, itemName);
|
||||
}
|
||||
|
||||
function updateActiveScriptsText(workerscript, item, itemName) {
|
||||
var server = getServer(workerscript.serverIp);
|
||||
if (server == null) {
|
||||
console.log("ERROR: Invalid server IP for workerscript for updateActiveScriptsText()");
|
||||
return;
|
||||
}
|
||||
let hostname = server.hostname;
|
||||
if (ActiveScriptsUI[hostname] == null || ActiveScriptsUI[hostname].scriptHdrs[itemName] == null) {
|
||||
console.log("ERROR: Trying to update Active Script UI Element with a hostname that cant be found in ActiveScriptsUI: " + hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
updateHeaderHtml(server);
|
||||
var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime;
|
||||
|
||||
// Only update if the item is visible
|
||||
if (ActiveScriptsUI[hostname].header.classList.contains("active") === false) {return onlineMps;}
|
||||
if (ActiveScriptsUI[hostname].scriptHdrs[itemName].classList.contains("active") === false) {return onlineMps;}
|
||||
|
||||
removeChildrenFromElement(item);
|
||||
|
||||
var onlineTime = "Online Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.onlineRunningTime * 1e3);
|
||||
var offlineTime = "Offline Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.offlineRunningTime * 1e3);
|
||||
|
||||
// Online
|
||||
var onlineTotalMoneyMade = "Total online production: " + numeralWrapper.formatMoney(workerscript.scriptRef.onlineMoneyMade);
|
||||
var onlineTotalExpEarned = (Array(26).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.onlineExpGained) + " hacking exp").replace( / /g, " ");
|
||||
|
||||
var onlineMpsText = "Online production rate: " + numeralWrapper.formatMoney(onlineMps) + " / second";
|
||||
var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime;
|
||||
var onlineEpsText = (Array(25).join(" ") + numeralWrapper.formatBigNumber(onlineEps) + " hacking exp / second").replace( / /g, " ");
|
||||
|
||||
// Offline
|
||||
var offlineTotalMoneyMade = "Total offline production: " + numeralWrapper.formatMoney(workerscript.scriptRef.offlineMoneyMade);
|
||||
var offlineTotalExpEarned = (Array(27).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.offlineExpGained) + " hacking exp").replace( / /g, " ");
|
||||
|
||||
var offlineMps = workerscript.scriptRef.offlineMoneyMade / workerscript.scriptRef.offlineRunningTime;
|
||||
var offlineMpsText = "Offline production rate: " + numeralWrapper.formatMoney(offlineMps) + " / second";
|
||||
var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime;
|
||||
var offlineEpsText = (Array(26).join(" ") + numeralWrapper.formatBigNumber(offlineEps) + " hacking exp / second").replace( / /g, " ");
|
||||
|
||||
item.innerHTML = onlineTime + "<br>" + offlineTime + "<br>" + onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" +
|
||||
onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" +
|
||||
offlineMpsText + "<br>" + offlineEpsText + "<br>";
|
||||
return onlineMps;
|
||||
}
|
||||
|
||||
export {addActiveScriptsItem, deleteActiveScriptsItem, updateActiveScriptsItems};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,6 +49,7 @@ export let AugmentationNames: IMap<string> = {
|
||||
PCDNINeuralNetwork: "PC Direct-Neural Interface NeuroNet Injector",
|
||||
ADRPheromone1: "ADR-V1 Pheromone Gene",
|
||||
ADRPheromone2: "ADR-V2 Pheromone Gene",
|
||||
ShadowsSimulacrum: "The Shadow's Simulacrum",
|
||||
HacknetNodeCPUUpload: "Hacknet Node CPU Architecture Neural-Upload",
|
||||
HacknetNodeCacheUpload: "Hacknet Node Cache Architecture Neural-Upload",
|
||||
HacknetNodeNICUpload: "Hacknet Node NIC Architecture Neural-Upload",
|
||||
|
||||
42
src/Augmentation/ui/InstalledAugmentations.tsx
Normal file
42
src/Augmentation/ui/InstalledAugmentations.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* React Component for displaying a list of the player's installed Augmentations
|
||||
* on the Augmentations UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
|
||||
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
|
||||
|
||||
export function InstalledAugmentations(): React.ReactElement {
|
||||
const sourceAugs = Player.augmentations.slice();
|
||||
|
||||
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
|
||||
sourceAugs.sort((aug1, aug2) => {
|
||||
return aug1.name <= aug2.name ? -1 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
const augs = sourceAugs.map((e) => {
|
||||
const aug = Augmentations[e.name];
|
||||
|
||||
let level = null;
|
||||
if (e.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
level = e.level;
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={e.name}>
|
||||
<AugmentationAccordion aug={aug} level={level} />
|
||||
</li>
|
||||
)
|
||||
});
|
||||
|
||||
return (
|
||||
<>{augs}</>
|
||||
)
|
||||
}
|
||||
107
src/Augmentation/ui/InstalledAugmentationsAndSourceFiles.tsx
Normal file
107
src/Augmentation/ui/InstalledAugmentationsAndSourceFiles.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* React Component for displaying all of the player's installed Augmentations and
|
||||
* Source-Files.
|
||||
*
|
||||
* It also contains 'configuration' buttons that allow you to change how the
|
||||
* Augs/SF's are displayed
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { InstalledAugmentations } from "./InstalledAugmentations";
|
||||
import { ListConfiguration } from "./ListConfiguration";
|
||||
import { OwnedSourceFiles } from "./OwnedSourceFiles";
|
||||
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
|
||||
type IProps = {}
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
}
|
||||
|
||||
export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps, IState> {
|
||||
listRef: React.RefObject<HTMLUListElement>;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
}
|
||||
|
||||
this.collapseAllHeaders = this.collapseAllHeaders.bind(this);
|
||||
this.expandAllHeaders = this.expandAllHeaders.bind(this);
|
||||
this.sortByAcquirementTime = this.sortByAcquirementTime.bind(this);
|
||||
this.sortInOrder = this.sortInOrder.bind(this);
|
||||
|
||||
this.listRef = React.createRef();
|
||||
}
|
||||
|
||||
collapseAllHeaders() {
|
||||
const ul = this.listRef.current;
|
||||
if (ul == null) { return; }
|
||||
const tickers = ul.getElementsByClassName("accordion-header");
|
||||
for (let i = 0; i < tickers.length; ++i) {
|
||||
const ticker = tickers[i];
|
||||
if (!(ticker instanceof HTMLButtonElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ticker.classList.contains("active")) {
|
||||
ticker.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expandAllHeaders() {
|
||||
const ul = this.listRef.current;
|
||||
if (ul == null) { return; }
|
||||
const tickers = ul.getElementsByClassName("accordion-header");
|
||||
for (let i = 0; i < tickers.length; ++i) {
|
||||
const ticker = tickers[i];
|
||||
if (!(ticker instanceof HTMLButtonElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ticker.classList.contains("active")) {
|
||||
ticker.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rerender() {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sortByAcquirementTime() {
|
||||
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime;
|
||||
this.rerender();
|
||||
}
|
||||
|
||||
sortInOrder() {
|
||||
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically
|
||||
this.rerender();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<ListConfiguration
|
||||
collapseAllButtonsFn={this.collapseAllHeaders}
|
||||
expandAllButtonsFn={this.expandAllHeaders}
|
||||
sortByAcquirementTimeFn={this.sortByAcquirementTime}
|
||||
sortInOrderFn={this.sortInOrder}
|
||||
/>
|
||||
<ul className="augmentations-list" ref={this.listRef}>
|
||||
<OwnedSourceFiles />
|
||||
<InstalledAugmentations />
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
39
src/Augmentation/ui/ListConfiguration.tsx
Normal file
39
src/Augmentation/ui/ListConfiguration.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* React Component for configuring the way installed augmentations and
|
||||
* Source-Files are displayed in the Augmentations UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
collapseAllButtonsFn: () => void;
|
||||
expandAllButtonsFn: () => void;
|
||||
sortByAcquirementTimeFn: () => void;
|
||||
sortInOrderFn: () => void;
|
||||
}
|
||||
|
||||
export function ListConfiguration(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<StdButton
|
||||
onClick={props.expandAllButtonsFn}
|
||||
text="Expand All"
|
||||
/>
|
||||
<StdButton
|
||||
onClick={props.collapseAllButtonsFn}
|
||||
text="Collapse All"
|
||||
/>
|
||||
<StdButton
|
||||
onClick={props.sortInOrderFn}
|
||||
text="Sort in Order"
|
||||
tooltip="Sorts the Augmentations alphabetically and Source-Files in numeral order"
|
||||
/>
|
||||
<StdButton
|
||||
onClick={props.sortByAcquirementTimeFn}
|
||||
text="Sort by Acquirement Time"
|
||||
tooltip="Sorts the Augmentations and Source-Files based on when you acquired them (same as default)"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
41
src/Augmentation/ui/OwnedSourceFiles.tsx
Normal file
41
src/Augmentation/ui/OwnedSourceFiles.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* React Component for displaying a list of the player's Source-Files
|
||||
* on the Augmentations UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { SourceFiles } from "../../SourceFile/SourceFiles";
|
||||
|
||||
import { SourceFileAccordion } from "../../ui/React/SourceFileAccordion";
|
||||
|
||||
export function OwnedSourceFiles(): React.ReactElement {
|
||||
const sourceSfs = Player.sourceFiles.slice();
|
||||
|
||||
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
|
||||
sourceSfs.sort((sf1, sf2) => {
|
||||
return sf1.n - sf2.n;
|
||||
});
|
||||
}
|
||||
|
||||
const sfs = sourceSfs.map((e) => {
|
||||
const srcFileKey = "SourceFile" + e.n;
|
||||
const sfObj = SourceFiles[srcFileKey];
|
||||
if (sfObj == null) {
|
||||
console.error(`Invalid source file number: ${e.n}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={e.n}>
|
||||
<SourceFileAccordion level={e.lvl} sf={sfObj} />
|
||||
</li>
|
||||
)
|
||||
});
|
||||
|
||||
return (
|
||||
<>{sfs}</>
|
||||
);
|
||||
}
|
||||
96
src/Augmentation/ui/PlayerMultipliers.tsx
Normal file
96
src/Augmentation/ui/PlayerMultipliers.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* React component for displaying the player's multipliers on the Augmentation UI page
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
export function PlayerMultipliers(): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<p><strong><u>Total Multipliers:</u></strong></p>
|
||||
|
||||
<pre>
|
||||
{'Hacking Chance multiplier: ' + numeralWrapper.formatPercentage(Player.hacking_chance_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacking Speed multiplier: ' + numeralWrapper.formatPercentage(Player.hacking_speed_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacking Money multiplier: ' + numeralWrapper.formatPercentage(Player.hacking_money_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacking Growth multiplier: ' + numeralWrapper.formatPercentage(Player.hacking_grow_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Hacking Level multiplier: ' + numeralWrapper.formatPercentage(Player.hacking_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacking Experience multiplier: ' + numeralWrapper.formatPercentage(Player.hacking_exp_mult)}
|
||||
</pre>
|
||||
<br />
|
||||
<pre>
|
||||
{'Strength Level multiplier: ' + numeralWrapper.formatPercentage(Player.strength_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Strength Experience multiplier: ' + numeralWrapper.formatPercentage(Player.strength_exp_mult)}
|
||||
</pre>
|
||||
<br />
|
||||
<pre>
|
||||
{'Defense Level multiplier: ' + numeralWrapper.formatPercentage(Player.defense_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Defense Experience multiplier: ' + numeralWrapper.formatPercentage(Player.defense_exp_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Dexterity Level multiplier: ' + numeralWrapper.formatPercentage(Player.dexterity_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Dexterity Experience multiplier: ' + numeralWrapper.formatPercentage(Player.dexterity_exp_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Agility Level multiplier: ' + numeralWrapper.formatPercentage(Player.agility_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Agility Experience multiplier: ' + numeralWrapper.formatPercentage(Player.agility_exp_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Charisma Level multiplier: ' + numeralWrapper.formatPercentage(Player.charisma_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Charisma Experience multiplier: ' + numeralWrapper.formatPercentage(Player.charisma_exp_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Hacknet Node production multiplier: ' + numeralWrapper.formatPercentage(Player.hacknet_node_money_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacknet Node purchase cost multiplier: ' + numeralWrapper.formatPercentage(Player.hacknet_node_purchase_cost_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacknet Node RAM upgrade cost multiplier: ' + numeralWrapper.formatPercentage(Player.hacknet_node_ram_cost_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacknet Node Core purchase cost multiplier: ' + numeralWrapper.formatPercentage(Player.hacknet_node_core_cost_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Hacknet Node level upgrade cost multiplier: ' + numeralWrapper.formatPercentage(Player.hacknet_node_level_cost_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Company reputation gain multiplier: ' + numeralWrapper.formatPercentage(Player.company_rep_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Faction reputation gain multiplier: ' + numeralWrapper.formatPercentage(Player.faction_rep_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Salary multiplier: ' + numeralWrapper.formatPercentage(Player.work_money_mult)}
|
||||
</pre><br />
|
||||
<pre>
|
||||
{'Crime success multiplier: ' + numeralWrapper.formatPercentage(Player.crime_success_mult)}
|
||||
</pre>
|
||||
<pre>
|
||||
{'Crime money multiplier: ' + numeralWrapper.formatPercentage(Player.crime_money_mult)}
|
||||
</pre>
|
||||
</>
|
||||
)
|
||||
}
|
||||
32
src/Augmentation/ui/PurchasedAugmentations.tsx
Normal file
32
src/Augmentation/ui/PurchasedAugmentations.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* React component for displaying all of the player's purchased (but not installed)
|
||||
* Augmentations on the Augmentations UI.
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Player } from "../../Player";
|
||||
|
||||
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
|
||||
|
||||
export function PurchasedAugmentations(): React.ReactElement {
|
||||
const augs: React.ReactElement[] = [];
|
||||
for (const ownedAug of Player.queuedAugmentations) {
|
||||
const aug = Augmentations[ownedAug.name];
|
||||
let level = null;
|
||||
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
level = ownedAug.level;
|
||||
}
|
||||
|
||||
augs.push(
|
||||
<li key={`${ownedAug.name}${ownedAug.level}`}>
|
||||
<AugmentationAccordion aug={aug} level={level} />
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="augmentations-list">{augs}</ul>
|
||||
)
|
||||
}
|
||||
83
src/Augmentation/ui/Root.tsx
Normal file
83
src/Augmentation/ui/Root.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Root React component for the Augmentations UI page that display all of your
|
||||
* owned and purchased Augmentations and Source-Files.
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { InstalledAugmentationsAndSourceFiles } from "./InstalledAugmentationsAndSourceFiles";
|
||||
import { PlayerMultipliers } from "./PlayerMultipliers";
|
||||
import { PurchasedAugmentations } from "./PurchasedAugmentations";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
|
||||
type IProps = {
|
||||
exportGameFn: () => void;
|
||||
installAugmentationsFn: () => void;
|
||||
}
|
||||
|
||||
type IState = {
|
||||
|
||||
}
|
||||
|
||||
export class AugmentationsRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="augmentations-content">
|
||||
<h1>Purchased Augmentations</h1>
|
||||
<p>
|
||||
Below is a list of all Augmentations you have purchased but not
|
||||
yet installed. Click the button below to install them.
|
||||
</p>
|
||||
<p>
|
||||
WARNING: Installing your Augmentations resets most of your progress,
|
||||
including:
|
||||
</p><br />
|
||||
<p>- Stats/Skill levels and Experience</p>
|
||||
<p>- Money</p>
|
||||
<p>- Scripts on every computer but your home computer</p>
|
||||
<p>- Purchased servers</p>
|
||||
<p>- Hacknet Nodes</p>
|
||||
<p>- Faction/Company reputation</p>
|
||||
<p>- Stocks</p><br />
|
||||
<p>
|
||||
Installing Augmentations lets you start over with the perks and
|
||||
benefits granted by all of the Augmentations you have ever
|
||||
installed. Also, you will keep any scripts and RAM/Core upgrades
|
||||
on your home computer (but you will lose all programs besides
|
||||
NUKE.exe)
|
||||
</p>
|
||||
|
||||
<StdButton
|
||||
onClick={this.props.installAugmentationsFn}
|
||||
text="Install Augmentations"
|
||||
tooltip="'I never asked for this'"
|
||||
/>
|
||||
|
||||
<StdButton
|
||||
addClasses="flashing-button"
|
||||
onClick={this.props.exportGameFn}
|
||||
text="Backup Save (Export)"
|
||||
tooltip="It's always a good idea to backup/export your save!"
|
||||
/>
|
||||
<PurchasedAugmentations />
|
||||
|
||||
<h1>Installed Augmentations</h1>
|
||||
<p>
|
||||
{
|
||||
`List of all Augmentations ${Player.sourceFiles.length > 0 ? "and Source Files " : ""} ` +
|
||||
`that have been installed. You have gained the effects of these.`
|
||||
}
|
||||
</p>
|
||||
<InstalledAugmentationsAndSourceFiles />
|
||||
|
||||
<br /> <br />
|
||||
<PlayerMultipliers />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -25,233 +25,232 @@ class BitNode {
|
||||
}
|
||||
|
||||
|
||||
export let BitNodes: IMap<BitNode> = {};
|
||||
export const BitNodes: IMap<BitNode> = {};
|
||||
|
||||
export function initBitNodes() {
|
||||
BitNodes = {};
|
||||
BitNodes["BitNode1"] = new BitNode(1, "Source Genesis", "The original BitNode",
|
||||
"The first BitNode created by the Enders to imprison the minds of humans. It became " +
|
||||
"the prototype and testing-grounds for all of the BitNodes that followed.<br><br>" +
|
||||
"This is the first BitNode that you play through. It has no special " +
|
||||
"modifications or mechanics.<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 1, or if you already have " +
|
||||
"this Source-File it will upgrade its level up to a maximum of 3. This Source-File " +
|
||||
"lets the player start with 32GB of RAM on his/her home computer when entering a " +
|
||||
"new BitNode, and also increases all of the player's multipliers by:<br><br>" +
|
||||
"Level 1: 16%<br>" +
|
||||
"Level 2: 24%<br>" +
|
||||
"Level 3: 28%");
|
||||
BitNodes["BitNode2"] = new BitNode(2, "Rise of the Underworld", "From the shadows, they rose", //Gangs
|
||||
"From the shadows, they rose.<br><br>Organized crime groups quickly filled the void of power " +
|
||||
"left behind from the collapse of Western government in the 2050s. As society and civlization broke down, " +
|
||||
"people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " +
|
||||
"factions quickly rose to the top of the modern world.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your hacking level is reduced by 20%<br>" +
|
||||
"The growth rate and maximum amount of money available on servers are significantly decreased<br>" +
|
||||
"The amount of money gained from crimes and Infiltration is tripled<br>" +
|
||||
"Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, " +
|
||||
"NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs " +
|
||||
"will earn the player money and reputation with the corresponding Faction<br>" +
|
||||
"Every Augmentation in the game will be available through the Factions listed above<br>" +
|
||||
"For every Faction NOT listed above, reputation gains are halved<br>" +
|
||||
"You will no longer gain passive reputation with Factions<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes " +
|
||||
"once your karma decreases to a certain value. " +
|
||||
"It also increases the player's crime success rate, crime money, and charisma multipliers by:<br><br>" +
|
||||
"Level 1: 24%<br>" +
|
||||
"Level 2: 36%<br>" +
|
||||
"Level 3: 42%");
|
||||
BitNodes["BitNode3"] = new BitNode(3, "Corporatocracy", "The Price of Civilization",
|
||||
"Our greatest illusion is that a healthy society can revolve around a " +
|
||||
"single-minded pursuit of wealth.<br><br>" +
|
||||
"Sometime in the early 21st century economic and political globalization turned " +
|
||||
"the world into a corporatocracy, and it never looked back. Now, the privileged " +
|
||||
"elite will happily bankrupt their own countrymen, decimate their own community, " +
|
||||
"and evict their neighbors from houses in their desperate bid to increase their wealth.<br><br>" +
|
||||
"In this BitNode you can create and manage your own corporation. Running a successful corporation " +
|
||||
"has the potential of generating massive profits. All other forms of income are reduced by 75%. Furthermore: <br><br>" +
|
||||
"The price and reputation cost of all Augmentations is tripled<br>" +
|
||||
"The starting and maximum amount of money on servers is reduced by 75%<br>" +
|
||||
"Server growth rate is reduced by 80%<br>" +
|
||||
"You now only need 75 favour with a faction in order to donate to it, rather than 150<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although " +
|
||||
"some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode4"] = new BitNode(4, "The Singularity", "The Man and the Machine", "The Singularity has arrived. The human race is gone, replaced " +
|
||||
"by artificially superintelligent beings that are more machine than man. <br><br>" +
|
||||
"In this BitNode, progressing is significantly harder. Experience gain rates " +
|
||||
"for all stats are reduced. Most methods of earning money will now give significantly less.<br><br>" +
|
||||
"In this BitNode you will gain access to a new set of Netscript Functions known as Singularity Functions. " +
|
||||
"These functions allow you to control most aspects of the game through scripts, including working for factions/companies, " +
|
||||
"purchasing/installing Augmentations, and creating programs.<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 4, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File lets you access and use the Singularity " +
|
||||
"Functions in other BitNodes. Each level of this Source-File will open up more Singularity Functions " +
|
||||
"that you can use.");
|
||||
BitNodes["BitNode5"] = new BitNode(5, "Artificial Intelligence", "Posthuman", "They said it couldn't be done. They said the human brain, " +
|
||||
"along with its consciousness and intelligence, couldn't be replicated. They said the complexity " +
|
||||
"of the brain results from unpredictable, nonlinear interactions that couldn't be modeled " +
|
||||
"by 1's and 0's. They were wrong.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"The base security level of servers is doubled<br>" +
|
||||
"The starting money on servers is halved, but the maximum money remains the same<br>" +
|
||||
"Most methods of earning money now give significantly less<br>" +
|
||||
"Infiltration gives 50% more reputation and money<br>" +
|
||||
"Corporations have 50% lower valuations and are therefore less profitable<br>" +
|
||||
"Augmentations are more expensive<br>" +
|
||||
"Hacking experience gain rates are reduced<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 5, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File grants you a special new stat called Intelligence. " +
|
||||
"Intelligence is unique because it is permanent and persistent (it never gets reset back to 1). However " +
|
||||
"gaining Intelligence experience is much slower than other stats, and it is also hidden (you won't know " +
|
||||
"when you gain experience and how much). Higher Intelligence levels will boost your production for many actions " +
|
||||
"in the game. <br><br>" +
|
||||
"In addition, this Source-File will unlock the getBitNodeMultipliers() Netscript function, " +
|
||||
"and will also raise all of your hacking-related multipliers by:<br><br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode6"] = new BitNode(6, "Bladeburners", "Like Tears in Rain",
|
||||
"In the middle of the 21st century, OmniTek Incorporated began designing and manufacturing advanced synthetic " +
|
||||
"androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth generation " +
|
||||
"of their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was " +
|
||||
"the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more intelligent " +
|
||||
"than the humans that had created them.<br><br>" +
|
||||
"In this BitNode you will be able to access the Bladeburner Division at the NSA, which provides a new mechanic " +
|
||||
"for progression. Furthermore:<br><br>" +
|
||||
"Hacking and Hacknet Nodes will be less profitable<br>" +
|
||||
"Your hacking level is reduced by 65%<br>" +
|
||||
"Hacking experience gain from scripts is reduced by 75%<br>" +
|
||||
"Corporations have 80% lower valuations and are therefore less profitable<br>" +
|
||||
"Working for companies is 50% less profitable<br>" +
|
||||
"Crimes and Infiltration are 25% less profitable<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade " +
|
||||
"its level up to a maximum of 3. This Source-File allows you to access the NSA's Bladeburner Division in other " +
|
||||
"BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your combat stats by:<br><br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode7"] = new BitNode(7, "Bladeburners 2079", "More human than humans",
|
||||
"In the middle of the 21st century, you were doing cutting-edge work at OmniTek Incorporated as part of the AI design team " +
|
||||
"for advanced synthetic androids, or Synthoids for short. You helped achieve a major technological " +
|
||||
"breakthrough in the sixth generation of the company's Synthoid design, called MK-VI, by developing a hyperintelligent AI. " +
|
||||
"Many argue that this was the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, " +
|
||||
"and more intelligent than the humans that had created them.<br><br>" +
|
||||
"In this BitNode you will be able to access the Bladeburner API, which allows you to access Bladeburner " +
|
||||
"functionality through Netscript. Furthermore: <br><br>" +
|
||||
"The rank you gain from Bladeburner contracts/operations is reduced by 40%<br>" +
|
||||
"Bladeburner skills cost twice as many skill points<br>" +
|
||||
"Augmentations are 3x more expensive<br>" +
|
||||
"Hacking and Hacknet Nodes will be significantly less profitable<br>" +
|
||||
"Your hacking level is reduced by 65%<br>" +
|
||||
"Hacking experience gain from scripts is reduced by 75%<br>" +
|
||||
"Corporations have 80% lower valuations and are therefore less profitable<br>" +
|
||||
"Working for companies is 50% less profitable<br>" +
|
||||
"Crimes and Infiltration are 25% less profitable<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 7, or if you already have this Source-File it will upgrade " +
|
||||
"its level up to a maximum of 3. This Source-File allows you to access the Bladeburner Netscript API in other " +
|
||||
"BitNodes. In addition, this Source-File will increase all of your Bladeburner multipliers by:<br><br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode8"] = new BitNode(8, "Ghost of Wall Street", "Money never sleeps",
|
||||
"You are trying to make a name for yourself as an up-and-coming hedge fund manager on Wall Street.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"You start with $250 million<br>" +
|
||||
"The only way to earn money is by trading on the stock market<br>" +
|
||||
"You start with a WSE membership and access to the TIX API<br>" +
|
||||
"You are able to short stocks and place different types of orders (limit/stop)<br>" +
|
||||
"You can immediately donate to factions to gain reputation<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 8, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File grants the following benefits:<br><br>" +
|
||||
"Level 1: Permanent access to WSE and TIX API<br>" +
|
||||
"Level 2: Ability to short stocks in other BitNodes<br>" +
|
||||
"Level 3: Ability to use limit/stop orders in other BitNodes<br><br>" +
|
||||
"This Source-File also increases your hacking growth multipliers by: " +
|
||||
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
||||
BitNodes["BitNode9"] = new BitNode(9, "Hacktocracy", "Hacknet Unleashed",
|
||||
"When Fulcrum Technologies released their open-source Linux distro Chapeau, it quickly " +
|
||||
"became the OS of choice for the underground hacking community. Chapeau became especially notorious for " +
|
||||
"powering the Hacknet, a global, decentralized network used for nefarious purposes. Fulcrum quickly " +
|
||||
"abandoned the project and dissociated themselves from it.<br><br>" +
|
||||
"This BitNode unlocks the Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers generate " +
|
||||
"hashes, which can be spent on a variety of different upgrades.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your stats are significantly decreased<br>" +
|
||||
"You cannnot purchase additional servers<br>" +
|
||||
"Hacking is significantly less profitable<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 9, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File grants the following benefits:<br><br>" +
|
||||
"Level 1: Permanently unlocks the Hacknet Server in other BitNodes<br>" +
|
||||
"Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode<br>" +
|
||||
"Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode<br><br>" +
|
||||
"(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT " +
|
||||
"when installing Augmentations)");
|
||||
BitNodes["BitNode10"] = new BitNode(10, "Digital Carbon", "Your body is not who you are",
|
||||
"In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people " +
|
||||
"to digitize their consciousness. Their consciousness could then be transferred into Synthoids " +
|
||||
"or other bodies by trasmitting the digitized data. Human bodies became nothing more than 'sleeves' for the " +
|
||||
"human consciousness. Mankind had finally achieved immortality - at least for those that could afford it.<br><br>" +
|
||||
"This BitNode unlocks Sleeve technology. Sleeve technology allows you to:<br><br>" +
|
||||
"1. Re-sleeve: Purchase and transfer your consciousness into a new body<br>" +
|
||||
"2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your stats are significantly decreased<br>" +
|
||||
"All methods of gaining money are half as profitable (except Stock Market)<br>" +
|
||||
"Purchased servers are more expensive, have less max RAM, and a lower maximum limit<br>" +
|
||||
"Augmentations are 5x as expensive and require twice as much reputation<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 10, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File unlocks Sleeve technology in other BitNodes. " +
|
||||
"Each level of this Source-File also grants you a Duplicate Sleeve");
|
||||
BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
|
||||
"The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " +
|
||||
"of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " +
|
||||
"the USA and China. But just as the world was slowly beginning to recover from these dark times, financial catastrophe hit.<br><br>" +
|
||||
"In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of this chaos and confusion, hackers " +
|
||||
"were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as " +
|
||||
"governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your hacking stat and experience gain are halved<br>" +
|
||||
"The starting and maximum amount of money available on servers is significantly decreased<br>" +
|
||||
"The growth rate of servers is significantly reduced<br>" +
|
||||
"Weakening a server is twice as effective<br>" +
|
||||
"Company wages are decreased by 50%<br>" +
|
||||
"Corporation valuations are 99% lower and are therefore significantly less profitable<br>" +
|
||||
"Hacknet Node production is significantly decreased<br>" +
|
||||
"Crime and Infiltration are more lucrative<br>" +
|
||||
"Augmentations are twice as expensive<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH " +
|
||||
"the player's salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain). " +
|
||||
"This Source-File also increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
||||
"Level 1: 32%<br>" +
|
||||
"Level 2: 48%<br>" +
|
||||
"Level 3: 56%");
|
||||
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
||||
"To iterate is human, to recurse divine.<br><br>" +
|
||||
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give your Souce-File 12, or " +
|
||||
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
|
||||
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
|
||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||
//Books: Frontera, Shiner
|
||||
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
|
||||
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
|
||||
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
|
||||
BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON");
|
||||
BitNodes["BitNode17"] = new BitNode(17, "", "COMING SOON");
|
||||
BitNodes["BitNode18"] = new BitNode(18, "", "COMING SOON");
|
||||
BitNodes["BitNode19"] = new BitNode(19, "", "COMING SOON");
|
||||
BitNodes["BitNode20"] = new BitNode(20, "", "COMING SOON");
|
||||
BitNodes["BitNode21"] = new BitNode(21, "", "COMING SOON");
|
||||
BitNodes["BitNode22"] = new BitNode(22, "", "COMING SOON");
|
||||
BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON");
|
||||
BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON");
|
||||
}
|
||||
BitNodes["BitNode1"] = new BitNode(1, "Source Genesis", "The original BitNode",
|
||||
"The first BitNode created by the Enders to imprison the minds of humans. It became " +
|
||||
"the prototype and testing-grounds for all of the BitNodes that followed.<br><br>" +
|
||||
"This is the first BitNode that you play through. It has no special " +
|
||||
"modifications or mechanics.<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 1, or if you already have " +
|
||||
"this Source-File it will upgrade its level up to a maximum of 3. This Source-File " +
|
||||
"lets the player start with 32GB of RAM on his/her home computer when entering a " +
|
||||
"new BitNode, and also increases all of the player's multipliers by:<br><br>" +
|
||||
"Level 1: 16%<br>" +
|
||||
"Level 2: 24%<br>" +
|
||||
"Level 3: 28%");
|
||||
BitNodes["BitNode2"] = new BitNode(2, "Rise of the Underworld", "From the shadows, they rose", //Gangs
|
||||
"From the shadows, they rose.<br><br>Organized crime groups quickly filled the void of power " +
|
||||
"left behind from the collapse of Western government in the 2050s. As society and civlization broke down, " +
|
||||
"people quickly succumbed to the innate human impulse of evil and savagery. The organized crime " +
|
||||
"factions quickly rose to the top of the modern world.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your hacking level is reduced by 20%<br>" +
|
||||
"The growth rate and maximum amount of money available on servers are significantly decreased<br>" +
|
||||
"The amount of money gained from crimes and Infiltration is tripled<br>" +
|
||||
"Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, " +
|
||||
"NiteSec, The Black Hand) give the player the ability to form and manage their own gangs. These gangs " +
|
||||
"will earn the player money and reputation with the corresponding Faction<br>" +
|
||||
"Every Augmentation in the game will be available through the Factions listed above<br>" +
|
||||
"For every Faction NOT listed above, reputation gains are halved<br>" +
|
||||
"You will no longer gain passive reputation with Factions<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes " +
|
||||
"once your karma decreases to a certain value. " +
|
||||
"It also increases the player's crime success rate, crime money, and charisma multipliers by:<br><br>" +
|
||||
"Level 1: 24%<br>" +
|
||||
"Level 2: 36%<br>" +
|
||||
"Level 3: 42%");
|
||||
BitNodes["BitNode3"] = new BitNode(3, "Corporatocracy", "The Price of Civilization",
|
||||
"Our greatest illusion is that a healthy society can revolve around a " +
|
||||
"single-minded pursuit of wealth.<br><br>" +
|
||||
"Sometime in the early 21st century economic and political globalization turned " +
|
||||
"the world into a corporatocracy, and it never looked back. Now, the privileged " +
|
||||
"elite will happily bankrupt their own countrymen, decimate their own community, " +
|
||||
"and evict their neighbors from houses in their desperate bid to increase their wealth.<br><br>" +
|
||||
"In this BitNode you can create and manage your own corporation. Running a successful corporation " +
|
||||
"has the potential of generating massive profits. All other forms of income are reduced by 75%. Furthermore: <br><br>" +
|
||||
"The price and reputation cost of all Augmentations is tripled<br>" +
|
||||
"The starting and maximum amount of money on servers is reduced by 75%<br>" +
|
||||
"Server growth rate is reduced by 80%<br>" +
|
||||
"You now only need 75 favour with a faction in order to donate to it, rather than 150<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although " +
|
||||
"some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:<br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode4"] = new BitNode(4, "The Singularity", "The Man and the Machine",
|
||||
"The Singularity has arrived. The human race is gone, replaced " +
|
||||
"by artificially superintelligent beings that are more machine than man. <br><br>" +
|
||||
"In this BitNode, progressing is significantly harder. Experience gain rates " +
|
||||
"for all stats are reduced. Most methods of earning money will now give significantly less.<br><br>" +
|
||||
"In this BitNode you will gain access to a new set of Netscript Functions known as Singularity Functions. " +
|
||||
"These functions allow you to control most aspects of the game through scripts, including working for factions/companies, " +
|
||||
"purchasing/installing Augmentations, and creating programs.<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 4, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File lets you access and use the Singularity " +
|
||||
"Functions in other BitNodes. Each level of this Source-File will open up more Singularity Functions " +
|
||||
"that you can use.");
|
||||
BitNodes["BitNode5"] = new BitNode(5, "Artificial Intelligence", "Posthuman",
|
||||
"They said it couldn't be done. They said the human brain, " +
|
||||
"along with its consciousness and intelligence, couldn't be replicated. They said the complexity " +
|
||||
"of the brain results from unpredictable, nonlinear interactions that couldn't be modeled " +
|
||||
"by 1's and 0's. They were wrong.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"The base security level of servers is doubled<br>" +
|
||||
"The starting money on servers is halved, but the maximum money remains the same<br>" +
|
||||
"Most methods of earning money now give significantly less<br>" +
|
||||
"Infiltration gives 50% more reputation and money<br>" +
|
||||
"Corporations have 50% lower valuations and are therefore less profitable<br>" +
|
||||
"Augmentations are more expensive<br>" +
|
||||
"Hacking experience gain rates are reduced<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 5, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File grants you a special new stat called Intelligence. " +
|
||||
"Intelligence is unique because it is permanent and persistent (it never gets reset back to 1). However " +
|
||||
"gaining Intelligence experience is much slower than other stats, and it is also hidden (you won't know " +
|
||||
"when you gain experience and how much). Higher Intelligence levels will boost your production for many actions " +
|
||||
"in the game. <br><br>" +
|
||||
"In addition, this Source-File will unlock the getBitNodeMultipliers() Netscript function, " +
|
||||
"and will also raise all of your hacking-related multipliers by:<br><br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode6"] = new BitNode(6, "Bladeburners", "Like Tears in Rain",
|
||||
"In the middle of the 21st century, OmniTek Incorporated began designing and manufacturing advanced synthetic " +
|
||||
"androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth generation " +
|
||||
"of their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was " +
|
||||
"the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more intelligent " +
|
||||
"than the humans that had created them.<br><br>" +
|
||||
"In this BitNode you will be able to access the Bladeburner Division at the NSA, which provides a new mechanic " +
|
||||
"for progression. Furthermore:<br><br>" +
|
||||
"Hacking and Hacknet Nodes will be less profitable<br>" +
|
||||
"Your hacking level is reduced by 65%<br>" +
|
||||
"Hacking experience gain from scripts is reduced by 75%<br>" +
|
||||
"Corporations have 80% lower valuations and are therefore less profitable<br>" +
|
||||
"Working for companies is 50% less profitable<br>" +
|
||||
"Crimes and Infiltration are 25% less profitable<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade " +
|
||||
"its level up to a maximum of 3. This Source-File allows you to access the NSA's Bladeburner Division in other " +
|
||||
"BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your combat stats by:<br><br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode7"] = new BitNode(7, "Bladeburners 2079", "More human than humans",
|
||||
"In the middle of the 21st century, you were doing cutting-edge work at OmniTek Incorporated as part of the AI design team " +
|
||||
"for advanced synthetic androids, or Synthoids for short. You helped achieve a major technological " +
|
||||
"breakthrough in the sixth generation of the company's Synthoid design, called MK-VI, by developing a hyperintelligent AI. " +
|
||||
"Many argue that this was the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, " +
|
||||
"and more intelligent than the humans that had created them.<br><br>" +
|
||||
"In this BitNode you will be able to access the Bladeburner API, which allows you to access Bladeburner " +
|
||||
"functionality through Netscript. Furthermore: <br><br>" +
|
||||
"The rank you gain from Bladeburner contracts/operations is reduced by 40%<br>" +
|
||||
"Bladeburner skills cost twice as many skill points<br>" +
|
||||
"Augmentations are 3x more expensive<br>" +
|
||||
"Hacking and Hacknet Nodes will be significantly less profitable<br>" +
|
||||
"Your hacking level is reduced by 65%<br>" +
|
||||
"Hacking experience gain from scripts is reduced by 75%<br>" +
|
||||
"Corporations have 80% lower valuations and are therefore less profitable<br>" +
|
||||
"Working for companies is 50% less profitable<br>" +
|
||||
"Crimes and Infiltration are 25% less profitable<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 7, or if you already have this Source-File it will upgrade " +
|
||||
"its level up to a maximum of 3. This Source-File allows you to access the Bladeburner Netscript API in other " +
|
||||
"BitNodes. In addition, this Source-File will increase all of your Bladeburner multipliers by:<br><br>" +
|
||||
"Level 1: 8%<br>" +
|
||||
"Level 2: 12%<br>" +
|
||||
"Level 3: 14%");
|
||||
BitNodes["BitNode8"] = new BitNode(8, "Ghost of Wall Street", "Money never sleeps",
|
||||
"You are trying to make a name for yourself as an up-and-coming hedge fund manager on Wall Street.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"You start with $250 million<br>" +
|
||||
"The only way to earn money is by trading on the stock market<br>" +
|
||||
"You start with a WSE membership and access to the TIX API<br>" +
|
||||
"You are able to short stocks and place different types of orders (limit/stop)<br>" +
|
||||
"You can immediately donate to factions to gain reputation<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 8, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File grants the following benefits:<br><br>" +
|
||||
"Level 1: Permanent access to WSE and TIX API<br>" +
|
||||
"Level 2: Ability to short stocks in other BitNodes<br>" +
|
||||
"Level 3: Ability to use limit/stop orders in other BitNodes<br><br>" +
|
||||
"This Source-File also increases your hacking growth multipliers by: " +
|
||||
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
||||
BitNodes["BitNode9"] = new BitNode(9, "Hacktocracy", "Hacknet Unleashed",
|
||||
"When Fulcrum Technologies released their open-source Linux distro Chapeau, it quickly " +
|
||||
"became the OS of choice for the underground hacking community. Chapeau became especially notorious for " +
|
||||
"powering the Hacknet, a global, decentralized network used for nefarious purposes. Fulcrum quickly " +
|
||||
"abandoned the project and dissociated themselves from it.<br><br>" +
|
||||
"This BitNode unlocks the Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers generate " +
|
||||
"hashes, which can be spent on a variety of different upgrades.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your stats are significantly decreased<br>" +
|
||||
"You cannnot purchase additional servers<br>" +
|
||||
"Hacking is significantly less profitable<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 9, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File grants the following benefits:<br><br>" +
|
||||
"Level 1: Permanently unlocks the Hacknet Server in other BitNodes<br>" +
|
||||
"Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode<br>" +
|
||||
"Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode<br><br>" +
|
||||
"(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT " +
|
||||
"when installing Augmentations)");
|
||||
BitNodes["BitNode10"] = new BitNode(10, "Digital Carbon", "Your body is not who you are",
|
||||
"In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people " +
|
||||
"to digitize their consciousness. Their consciousness could then be transferred into Synthoids " +
|
||||
"or other bodies by trasmitting the digitized data. Human bodies became nothing more than 'sleeves' for the " +
|
||||
"human consciousness. Mankind had finally achieved immortality - at least for those that could afford it.<br><br>" +
|
||||
"This BitNode unlocks Sleeve technology. Sleeve technology allows you to:<br><br>" +
|
||||
"1. Re-sleeve: Purchase and transfer your consciousness into a new body<br>" +
|
||||
"2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your stats are significantly decreased<br>" +
|
||||
"All methods of gaining money are half as profitable (except Stock Market)<br>" +
|
||||
"Purchased servers are more expensive, have less max RAM, and a lower maximum limit<br>" +
|
||||
"Augmentations are 5x as expensive and require twice as much reputation<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 10, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File unlocks Sleeve technology in other BitNodes. " +
|
||||
"Each level of this Source-File also grants you a Duplicate Sleeve");
|
||||
BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
|
||||
"The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " +
|
||||
"of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " +
|
||||
"the USA and China. But just as the world was slowly beginning to recover from these dark times, financial catastrophe hit.<br><br>" +
|
||||
"In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of this chaos and confusion, hackers " +
|
||||
"were able to steal billions of dollars from the world's largest electronic banks, prompting an international banking crisis as " +
|
||||
"governments were unable to bail out insolvent banks. Now, the world is slowly crumbling in the middle of the biggest economic crisis of all time.<br><br>" +
|
||||
"In this BitNode:<br><br>" +
|
||||
"Your hacking stat and experience gain are halved<br>" +
|
||||
"The starting and maximum amount of money available on servers is significantly decreased<br>" +
|
||||
"The growth rate of servers is significantly reduced<br>" +
|
||||
"Weakening a server is twice as effective<br>" +
|
||||
"Company wages are decreased by 50%<br>" +
|
||||
"Corporation valuations are 99% lower and are therefore significantly less profitable<br>" +
|
||||
"Hacknet Node production is significantly decreased<br>" +
|
||||
"Crime and Infiltration are more lucrative<br>" +
|
||||
"Augmentations are twice as expensive<br><br>" +
|
||||
"Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will " +
|
||||
"upgrade its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH " +
|
||||
"the player's salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain). " +
|
||||
"This Source-File also increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
||||
"Level 1: 32%<br>" +
|
||||
"Level 2: 48%<br>" +
|
||||
"Level 3: 56%");
|
||||
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
||||
"To iterate is human, to recurse divine.<br><br>" +
|
||||
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give your Souce-File 12, or " +
|
||||
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
|
||||
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
|
||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||
// Books: Frontera, Shiner
|
||||
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
|
||||
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
|
||||
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
|
||||
BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON");
|
||||
BitNodes["BitNode17"] = new BitNode(17, "", "COMING SOON");
|
||||
BitNodes["BitNode18"] = new BitNode(18, "", "COMING SOON");
|
||||
BitNodes["BitNode19"] = new BitNode(19, "", "COMING SOON");
|
||||
BitNodes["BitNode20"] = new BitNode(20, "", "COMING SOON");
|
||||
BitNodes["BitNode21"] = new BitNode(21, "", "COMING SOON");
|
||||
BitNodes["BitNode22"] = new BitNode(22, "", "COMING SOON");
|
||||
BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON");
|
||||
BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON");
|
||||
|
||||
export function initBitNodeMultipliers(p: IPlayer) {
|
||||
if (p.bitNodeN == null) {
|
||||
|
||||
@@ -811,7 +811,7 @@ Bladeburner.prototype.create = function() {
|
||||
this.contracts["Retirement"] = new Contract({
|
||||
name:"Retirement",
|
||||
desc:"Hunt down and retire (kill) rogue Synthoids.<br><br>" +
|
||||
"Successfully copmleting a Retirement contract will lower the population in your current " +
|
||||
"Successfully completing a Retirement contract will lower the population in your current " +
|
||||
"city, and will also increase its chaos level.",
|
||||
baseDifficulty:200, difficultyFac:1.03, rewardFac:1.065,
|
||||
rankGain:0.6, hpLoss:1,
|
||||
@@ -4173,7 +4173,7 @@ function initBladeburner() {
|
||||
"results would be catastrophic.<br><br>" +
|
||||
"We do not have the power or jurisdiction to shutdown this down " +
|
||||
"through legal or political means, so we must resort to a covert " +
|
||||
"operation. Your goal is to destroy this technology and eliminate" +
|
||||
"operation. Your goal is to destroy this technology and eliminate " +
|
||||
"anyone who was involved in its creation.",
|
||||
baseDifficulty:15e3, reqdRank:30e3,
|
||||
rankGain:750, rankLoss:60, hpLoss:1000,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Factions } from "./Faction/Factions";
|
||||
import { Player } from "./Player";
|
||||
import { AllServers } from "./Server/AllServers";
|
||||
import { GetServerByHostname } from "./Server/ServerHelpers";
|
||||
import { SpecialServerNames } from "./Server/SpecialServerIps";
|
||||
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
|
||||
@@ -162,7 +163,9 @@ function getRandomServer() {
|
||||
// An infinite loop shouldn't ever happen, but to be safe we'll use
|
||||
// a for loop with a limited number of tries
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
if (randServer.purchasedByPlayer === false) { break; }
|
||||
if (!randServer.purchasedByPlayer && randServer.hostname !== SpecialServerNames.WorldDaemon) {
|
||||
break;
|
||||
}
|
||||
randIndex = getRandomInt(0, servers.length - 1);
|
||||
randServer = AllServers[servers[randIndex]];
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
|
||||
|
||||
|
||||
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
||||
|
||||
/* Represents different types of problems that a Coding Contract can have */
|
||||
@@ -205,6 +202,7 @@ export class CodingContract {
|
||||
}
|
||||
},
|
||||
placeholder: "Enter Solution here",
|
||||
width: "50%",
|
||||
}) as HTMLInputElement;
|
||||
solveBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
|
||||
110
src/Constants.ts
110
src/Constants.ts
@@ -6,7 +6,7 @@
|
||||
import { IMap } from "./types";
|
||||
|
||||
export let CONSTANTS: IMap<any> = {
|
||||
Version: "0.46.2",
|
||||
Version: "v0.47.2",
|
||||
|
||||
/** 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
|
||||
@@ -38,60 +38,6 @@ export let CONSTANTS: IMap<any> = {
|
||||
// NeuroFlux Governor Augmentation cost multiplier
|
||||
NeuroFluxGovernorLevelMult: 1.14,
|
||||
|
||||
// RAM Costs for Netscript functions
|
||||
ScriptBaseRamCost: 1.6,
|
||||
ScriptDomRamCost: 25,
|
||||
ScriptWhileRamCost: 0,
|
||||
ScriptForRamCost: 0,
|
||||
ScriptIfRamCost: 0,
|
||||
ScriptHackRamCost: 0.1,
|
||||
ScriptHackAnalyzeRamCost: 1,
|
||||
ScriptGrowRamCost: 0.15,
|
||||
ScriptGrowthAnalyzeRamCost: 1,
|
||||
ScriptWeakenRamCost: 0.15,
|
||||
ScriptScanRamCost: 0.2,
|
||||
ScriptPortProgramRamCost: 0.05,
|
||||
ScriptRunRamCost: 1.0,
|
||||
ScriptExecRamCost: 1.3,
|
||||
ScriptSpawnRamCost: 2.0,
|
||||
ScriptScpRamCost: 0.6,
|
||||
ScriptKillRamCost: 0.5,
|
||||
ScriptHasRootAccessRamCost: 0.05,
|
||||
ScriptGetHostnameRamCost: 0.05,
|
||||
ScriptGetHackingLevelRamCost: 0.05,
|
||||
ScriptGetMultipliersRamCost: 4.0,
|
||||
ScriptGetServerRamCost: 0.1,
|
||||
ScriptFileExistsRamCost: 0.1,
|
||||
ScriptIsRunningRamCost: 0.1,
|
||||
ScriptHacknetNodesRamCost: 4.0,
|
||||
ScriptHNUpgLevelRamCost: 0.4,
|
||||
ScriptHNUpgRamRamCost: 0.6,
|
||||
ScriptHNUpgCoreRamCost: 0.8,
|
||||
ScriptGetStockRamCost: 2.0,
|
||||
ScriptBuySellStockRamCost: 2.5,
|
||||
ScriptGetPurchaseServerRamCost: 0.25,
|
||||
ScriptPurchaseServerRamCost: 2.25,
|
||||
ScriptGetPurchasedServerLimit: 0.05,
|
||||
ScriptGetPurchasedServerMaxRam: 0.05,
|
||||
ScriptRoundRamCost: 0.05,
|
||||
ScriptReadWriteRamCost: 1.0,
|
||||
ScriptArbScriptRamCost: 1.0,
|
||||
ScriptGetScriptRamCost: 0.1,
|
||||
ScriptGetHackTimeRamCost: 0.05,
|
||||
ScriptGetFavorToDonate: 0.10,
|
||||
ScriptCodingContractBaseRamCost: 10,
|
||||
ScriptSleeveBaseRamCost: 4,
|
||||
|
||||
ScriptSingularityFn1RamCost: 1,
|
||||
ScriptSingularityFn2RamCost: 2,
|
||||
ScriptSingularityFn3RamCost: 3,
|
||||
|
||||
ScriptSingularityFnRamMult: 2, // Multiplier for RAM cost outside of BN-4
|
||||
|
||||
ScriptGangApiBaseRamCost: 4,
|
||||
|
||||
ScriptBladeburnerApiBaseRamCost: 4,
|
||||
|
||||
NumNetscriptPorts: 20,
|
||||
|
||||
// Server-related constants
|
||||
@@ -251,6 +197,13 @@ export let CONSTANTS: IMap<any> = {
|
||||
ClassLeadershipBaseCost: 320,
|
||||
ClassGymBaseCost: 120,
|
||||
|
||||
ClassStudyComputerScienceBaseExp: 0.5,
|
||||
ClassDataStructuresBaseExp: 1,
|
||||
ClassNetworksBaseExp: 2,
|
||||
ClassAlgorithmsBaseExp: 4,
|
||||
ClassManagementBaseExp: 2,
|
||||
ClassLeadershipBaseExp: 4,
|
||||
|
||||
CrimeShoplift: "shoplift",
|
||||
CrimeRobStore: "rob a store",
|
||||
CrimeMug: "mug someone",
|
||||
@@ -275,26 +228,35 @@ export let CONSTANTS: IMap<any> = {
|
||||
|
||||
LatestUpdate:
|
||||
`
|
||||
v0.46.2
|
||||
* Source-File 2 now allows you to form gangs in other BitNodes when your karma reaches a very large negative value
|
||||
** (Karma is a hidden stat and is lowered by committing crimes)
|
||||
* Gang changes:
|
||||
** Bug Fix: Gangs can no longer clash with themselve
|
||||
** Bug Fix: Winning against another gang should properly reduce their power
|
||||
v0.47.2
|
||||
-------
|
||||
|
||||
* Bug Fix: Terminal 'wget' command now works properly
|
||||
* Bug Fix: Hacknet Server Hash upgrades now properly reset upon installing Augs/switching BitNodes
|
||||
* Bug Fix: Fixed button for creating Corporations
|
||||
Netscript Changes
|
||||
* Added tail() Netscript function
|
||||
* hacknet.getNodeStats() function now returns an additional property for Hacknet Servers: hashCapacity
|
||||
* When writing to a file, the write() function now casts the data being written to a string (using String())
|
||||
* BitNode-selection page now shows what Source-File level you have for each BitNode
|
||||
* Overloaded kill() function so that you can kill a script by its PID
|
||||
* spawn() now only takes 10 seconds to run (decreased from 20 seconds)
|
||||
* run() and exec() now return the PID of the newly-executed scripts, rather than a boolean
|
||||
** (A PID is just a positive integer)
|
||||
* run(), exec(), and spawn() no longer need to be await-ed in NetscriptJS
|
||||
* Script parsing and RAM calculations now support ES9
|
||||
* installAugmentations() no longer has a return value since it causes all scripts to die
|
||||
* isBusy() now returns true if you are in a Hacking Mission
|
||||
* Bug fix: workForFaction() function now properly accounts for disabled logs
|
||||
* Bug fix: RAM should now be properly calculated when running a callback script with installAugmentations()
|
||||
* Bug fix: Fixed bug that caused scripts killed by exit()/spawn() to "clean up" twice
|
||||
|
||||
v0.46.1
|
||||
* Added a very rudimentary directory system to the Terminal
|
||||
** Details here: https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#filesystem-directories
|
||||
* Added numHashes(), hashCost(), and spendHashes() functions to the Netscript Hacknet Node API
|
||||
* 'Generate Coding Contract' hash upgrade is now more expensive
|
||||
* 'Generate Coding Contract' hash upgrade now generates the contract randomly on the server, rather than on home computer
|
||||
* The cost of selling hashes for money no longer increases each time
|
||||
* Selling hashes for money now costs 4 hashes (in exchange for $1m)
|
||||
* Bug Fix: Hacknet Node earnings should work properly when game is inactive/offline
|
||||
* Bug Fix: Duplicate Sleeve augmentations are now properly reset when switching to a new BitNode
|
||||
Misc Changes
|
||||
* The 'kill' Terminal command can now kill a script by its PID
|
||||
* Added 'Solarized Dark' theme to CodeMirror editor
|
||||
* After Infiltration, you will now return to the company page rather than the city page
|
||||
* Bug fix: Stock Market UI should no longer crash for certain locale settings
|
||||
* Bug fix: You can now properly remove unfinished programs (the *.exe-N%-INC files)
|
||||
* Bug fix: Fixed an issue that allowed you to increase money on servers with a 'maxMoney' of 0 (like CSEC)
|
||||
* Bug fix: Scripts no longer persist if they were started with syntax/import errors
|
||||
* Bug fix: 'hack' and 'analyze' Terminal commands are now blocking
|
||||
* Bug fix: Exp earned by duplicate sleeves at universities/gyms now takes hash upgrades into account
|
||||
`
|
||||
}
|
||||
|
||||
@@ -521,15 +521,18 @@ Industry.prototype.process = function(marketCycles=1, state, company) {
|
||||
}
|
||||
|
||||
// Process production, purchase, and import/export of materials
|
||||
var res = this.processMaterials(marketCycles, company);
|
||||
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
|
||||
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
|
||||
let res = this.processMaterials(marketCycles, company);
|
||||
if (Array.isArray(res)) {
|
||||
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
|
||||
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
|
||||
}
|
||||
|
||||
// Process creation, production & sale of products
|
||||
res = this.processProducts(marketCycles, company);
|
||||
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
|
||||
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
|
||||
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Process change in demand and competition for this industry's materials
|
||||
@@ -846,7 +849,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
sellAmt = (sellAmt * SecsPerMarketCycle * marketCycles);
|
||||
sellAmt = Math.min(mat.qty, sellAmt);
|
||||
if (sellAmt < 0) {
|
||||
console.log("sellAmt calculated to be negative");
|
||||
console.warn(`sellAmt calculated to be negative for ${matName} in ${city}`);
|
||||
mat.sll = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -899,9 +902,11 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
||||
break;
|
||||
}
|
||||
|
||||
//Make sure theres enough space in warehouse
|
||||
// Make sure theres enough space in warehouse
|
||||
if (expWarehouse.sizeUsed >= expWarehouse.size) {
|
||||
return; //Warehouse at capacity
|
||||
// Warehouse at capacity. Exporting doesnt
|
||||
// affect revenue so just return 0's
|
||||
return [0, 0];
|
||||
} else {
|
||||
var maxAmt = Math.floor((expWarehouse.size - expWarehouse.sizeUsed) / MaterialSizes[matName]);
|
||||
amt = Math.min(maxAmt, amt);
|
||||
@@ -1463,7 +1468,6 @@ function Employee(params={}) {
|
||||
this.hap = params.happiness ? params.happiness : getRandomInt(50, 100);
|
||||
this.ene = params.energy ? params.energy : getRandomInt(50, 100);
|
||||
|
||||
this.age = params.age ? params.age : getRandomInt(20, 50);
|
||||
this.int = params.intelligence ? params.intelligence : getRandomInt(10, 50);
|
||||
this.cha = params.charisma ? params.charisma : getRandomInt(10, 50);
|
||||
this.exp = params.experience ? params.experience : getRandomInt(10, 50);
|
||||
@@ -1482,13 +1486,7 @@ function Employee(params={}) {
|
||||
Employee.prototype.process = function(marketCycles=1, office) {
|
||||
var gain = 0.003 * marketCycles,
|
||||
det = gain * Math.random();
|
||||
this.age += gain;
|
||||
this.exp += gain;
|
||||
if (this.age > 150) {
|
||||
this.int -= det;
|
||||
this.eff -= det;
|
||||
this.cha -= det;
|
||||
}
|
||||
|
||||
// Employee salaries slowly go up over time
|
||||
this.cyclesUntilRaise -= marketCycles;
|
||||
@@ -1577,7 +1575,6 @@ Employee.prototype.createUI = function(panel, corporation, industry) {
|
||||
innerHTML:"Morale: " + formatNumber(this.mor, 3) + "<br>" +
|
||||
"Happiness: " + formatNumber(this.hap, 3) + "<br>" +
|
||||
"Energy: " + formatNumber(this.ene, 3) + "<br>" +
|
||||
"Age: " + formatNumber(this.age, 3) + "<br>" +
|
||||
"Intelligence: " + formatNumber(effInt, 3) + "<br>" +
|
||||
"Charisma: " + formatNumber(effCha, 3) + "<br>" +
|
||||
"Experience: " + formatNumber(this.exp, 3) + "<br>" +
|
||||
|
||||
@@ -495,8 +495,6 @@ export class IndustryOffice extends BaseReactComponent {
|
||||
<br />
|
||||
Energy: {numeralWrapper.format(this.state.employee.ene, nf)}
|
||||
<br />
|
||||
Age: {numeralWrapper.format(this.state.employee.age, nf)}
|
||||
<br />
|
||||
Intelligence: {numeralWrapper.format(effInt, nf)}
|
||||
<br />
|
||||
Charisma: {numeralWrapper.format(effCha, nf)}
|
||||
|
||||
@@ -4,6 +4,7 @@ import ReactDOM from "react-dom";
|
||||
import { FactionRoot } from "./ui/Root";
|
||||
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { isRepeatableAug } from "../Augmentation/AugmentationHelpers";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
@@ -93,7 +94,12 @@ export function purchaseAugmentationBoxCreate(aug, fac) {
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
yesBtn.innerHTML = "Purchase";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
if (!isRepeatableAug(aug) && Player.hasAugmentation(aug)) {
|
||||
return;
|
||||
}
|
||||
|
||||
purchaseAugmentation(aug, fac);
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
const noBtn = yesNoBoxGetNoButton();
|
||||
@@ -204,7 +210,6 @@ export function purchaseAugmentation(aug, fac, sing=false) {
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.");
|
||||
}
|
||||
yesNoBoxClose();
|
||||
}
|
||||
|
||||
export function getNextNeurofluxLevel() {
|
||||
|
||||
@@ -45,9 +45,9 @@ export class DonateOption extends React.Component<IProps, IState> {
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
|
||||
// Returns rep gain for the current donation amount
|
||||
calculateRepGain(): number {
|
||||
return this.state.donateAmt / CONSTANTS.DonateMoneyToRepDivisor * this.props.p.faction_rep_mult;
|
||||
// Returns rep gain for a given donation amount
|
||||
calculateRepGain(amt: number): number {
|
||||
return amt / CONSTANTS.DonateMoneyToRepDivisor * this.props.p.faction_rep_mult;
|
||||
}
|
||||
|
||||
donate(): void {
|
||||
@@ -59,7 +59,7 @@ export class DonateOption extends React.Component<IProps, IState> {
|
||||
dialogBoxCreate(`You cannot afford to donate this much money!`);
|
||||
} else {
|
||||
this.props.p.loseMoney(amt);
|
||||
const repGain = this.calculateRepGain();
|
||||
const repGain = this.calculateRepGain(amt);
|
||||
this.props.faction.playerReputation += repGain;
|
||||
dialogBoxCreate(`You just donated ${numeralWrapper.formatMoney(amt)} to ${fac.name} to gain ` +
|
||||
`${numeralWrapper.format(repGain, "0,0.000")} reputation`);
|
||||
@@ -76,11 +76,11 @@ export class DonateOption extends React.Component<IProps, IState> {
|
||||
statusTxt: "Invalid donate amount entered!",
|
||||
});
|
||||
} else {
|
||||
const repGain = this.calculateRepGain();
|
||||
const repGain = this.calculateRepGain(amt);
|
||||
this.setState({
|
||||
donateAmt: amt,
|
||||
statusTxt: `This donation will result in ${numeralWrapper.format(repGain, "0,0.000")} reputation gain`,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,24 @@ const infoStyleMarkup = {
|
||||
}
|
||||
|
||||
export class Info extends React.Component<IProps, any> {
|
||||
render() {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
const formattedRep = numeralWrapper.format(this.props.faction.playerReputation, "0.000a");
|
||||
this.getFavorGainText = this.getFavorGainText.bind(this);
|
||||
this.getReputationText = this.getReputationText.bind(this);
|
||||
}
|
||||
|
||||
getFavorGainText(): string {
|
||||
const favorGain = this.props.faction.getFavorGain()[0];
|
||||
return `You will earn ${numeralWrapper.format(favorGain, "0,0")} faction favor upon resetting after installing an Augmentation`
|
||||
}
|
||||
|
||||
getReputationText(): string {
|
||||
const formattedRep = numeralWrapper.format(this.props.faction.playerReputation, "0.000a");
|
||||
return `Reputation: ${formattedRep}`
|
||||
}
|
||||
|
||||
render() {
|
||||
const favorTooltip = "Faction favor increases the rate at which you earn reputation for " +
|
||||
"this faction by 1% per favor. Faction favor is gained whenever you " +
|
||||
"reset after installing an Augmentation. The amount of " +
|
||||
@@ -45,12 +59,14 @@ export class Info extends React.Component<IProps, any> {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<i className={"text"} style={infoStyleMarkup} dangerouslySetInnerHTML={infoText}></i>
|
||||
<pre>
|
||||
<i className={"text"} dangerouslySetInnerHTML={infoText}></i>
|
||||
</pre>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<AutoupdatingParagraph
|
||||
intervalTime={5e3}
|
||||
text={`Reputation: ${formattedRep}`}
|
||||
tooltip={`You will earn ${numeralWrapper.format(favorGain, "0,0")} faction favor upon resetting after installing an Augmentation`}
|
||||
getText={this.getReputationText}
|
||||
getTooltip={this.getFavorGainText}
|
||||
/>
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<ParagraphWithTooltip
|
||||
|
||||
@@ -142,6 +142,7 @@ export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
onClick={this.handleClick}
|
||||
style={inlineStyleMarkup}
|
||||
text={btnTxt}
|
||||
tooltip={this.aug.info}
|
||||
/>
|
||||
<p style={txtStyle}>{statusTxt}</p>
|
||||
</span>
|
||||
|
||||
@@ -208,8 +208,12 @@ export class FactionRoot extends React.Component<IProps, IState> {
|
||||
const canPurchaseSleeves = (faction.name === "The Covenant" && p.bitNodeN >= 10 && SourceFileFlags[10]);
|
||||
|
||||
let canAccessGang = (p.canAccessGang() && GangNames.includes(faction.name));
|
||||
if (p.inGang() && (p.getGangName() !== faction.name)) {
|
||||
canAccessGang = false;
|
||||
if (p.inGang()) {
|
||||
if (p.getGangName() !== faction.name) {
|
||||
canAccessGang = false;
|
||||
} else if (p.getGangName() === faction.name) {
|
||||
canAccessGang = true;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -275,7 +279,7 @@ export class FactionRoot extends React.Component<IProps, IState> {
|
||||
{
|
||||
canPurchaseSleeves &&
|
||||
<Option
|
||||
buttonText={"Purchase Duplicate Sleeves"}
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={this.sleevePurchases}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FconfSettings } from "./FconfSettings";
|
||||
|
||||
import { parse, Node } from "../../utils/acorn";
|
||||
import { parse, Node } from "acorn";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
|
||||
var FconfComments = {
|
||||
|
||||
23
src/Gang.js
23
src/Gang.js
@@ -682,21 +682,25 @@ GangMember.prototype.calculateRespectGain = function(gang) {
|
||||
|
||||
GangMember.prototype.calculateWantedLevelGain = function(gang) {
|
||||
const task = this.getTask();
|
||||
if (task == null || !(task instanceof GangMemberTask) || task.baseWanted === 0) {return 0;}
|
||||
var statWeight = (task.hackWeight/100) * this.hack +
|
||||
(task.strWeight/100) * this.str +
|
||||
(task.defWeight/100) * this.def +
|
||||
(task.dexWeight/100) * this.dex +
|
||||
(task.agiWeight/100) * this.agi +
|
||||
(task.chaWeight/100) * this.cha;
|
||||
if (task == null || !(task instanceof GangMemberTask) || task.baseWanted === 0) { return 0; }
|
||||
let statWeight = (task.hackWeight / 100) * this.hack +
|
||||
(task.strWeight / 100) * this.str +
|
||||
(task.defWeight / 100) * this.def +
|
||||
(task.dexWeight / 100) * this.dex +
|
||||
(task.agiWeight / 100) * this.agi +
|
||||
(task.chaWeight / 100) * this.cha;
|
||||
statWeight -= (3.5 * task.difficulty);
|
||||
if (statWeight <= 0) { return 0; }
|
||||
const territoryMult = Math.pow(AllGangs[gang.facName].territory * 100, task.territory.wanted) / 100;
|
||||
if (isNaN(territoryMult) || territoryMult <= 0) { return 0; }
|
||||
if (task.baseWanted < 0) {
|
||||
return 0.5 * task.baseWanted * statWeight * territoryMult;
|
||||
return 0.4 * task.baseWanted * statWeight * territoryMult;
|
||||
} else {
|
||||
return 7 * task.baseWanted / (Math.pow(3 * statWeight * territoryMult, 0.8));
|
||||
const calc = 7 * task.baseWanted / (Math.pow(3 * statWeight * territoryMult, 0.8));
|
||||
|
||||
// Put an arbitrary cap on this to prevent wanted level from rising too fast if the
|
||||
// denominator is very small. Might want to rethink formula later
|
||||
return Math.min(100, calc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1359,6 +1363,7 @@ Gang.prototype.displayGangContent = function(player) {
|
||||
innerText: "Cancel",
|
||||
});
|
||||
createPopup(popupId, [txt, br, nameInput, yesBtn, noBtn]);
|
||||
nameInput.focus();
|
||||
}
|
||||
});
|
||||
UIElems.gangManagementSubpage.appendChild(UIElems.gangRecruitMemberButton);
|
||||
|
||||
@@ -6,34 +6,34 @@
|
||||
*/
|
||||
import { IReturnStatus } from "../types";
|
||||
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Server } from "../Server/Server";
|
||||
|
||||
function baseCheck(server: Server | HacknetServer, fnName: string): IReturnStatus {
|
||||
if (server instanceof HacknetServer) {
|
||||
function baseCheck(server: Server, fnName: string): IReturnStatus {
|
||||
const hostname = server.hostname;
|
||||
|
||||
if (!("requiredHackingSkill" in server)) {
|
||||
return {
|
||||
res: false,
|
||||
msg: `Cannot ${fnName} ${server.hostname} server because it is a Hacknet Node`
|
||||
msg: `Cannot ${fnName} ${hostname} server because it is a Hacknet Node`
|
||||
}
|
||||
}
|
||||
|
||||
if (server.hasAdminRights === false) {
|
||||
return {
|
||||
res: false,
|
||||
msg: `Cannot ${fnName} ${server.hostname} server because you do not have root access`,
|
||||
msg: `Cannot ${fnName} ${hostname} server because you do not have root access`,
|
||||
}
|
||||
}
|
||||
|
||||
return { res: true }
|
||||
}
|
||||
|
||||
export function netscriptCanHack(server: Server | HacknetServer, p: IPlayer): IReturnStatus {
|
||||
export function netscriptCanHack(server: Server, p: IPlayer): IReturnStatus {
|
||||
const initialCheck = baseCheck(server, "hack");
|
||||
if (!initialCheck.res) { return initialCheck; }
|
||||
|
||||
let s = <Server>server;
|
||||
|
||||
let s = server;
|
||||
if (s.requiredHackingSkill > p.hacking_skill) {
|
||||
return {
|
||||
res: false,
|
||||
@@ -44,10 +44,10 @@ export function netscriptCanHack(server: Server | HacknetServer, p: IPlayer): IR
|
||||
return { res: true }
|
||||
}
|
||||
|
||||
export function netscriptCanGrow(server: Server | HacknetServer): IReturnStatus {
|
||||
export function netscriptCanGrow(server: Server): IReturnStatus {
|
||||
return baseCheck(server, "grow");
|
||||
}
|
||||
|
||||
export function netscriptCanWeaken(server: Server | HacknetServer): IReturnStatus {
|
||||
export function netscriptCanWeaken(server: Server): IReturnStatus {
|
||||
return baseCheck(server, "weaken");
|
||||
}
|
||||
|
||||
4
src/Hacknet/GetMaxNumberUpgradeFns.js
Normal file
4
src/Hacknet/GetMaxNumberUpgradeFns.js
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Utility functions for calculating the maximum number of Hacknet upgrades the player
|
||||
* can purchase for a Node with his/her current money
|
||||
*/
|
||||
@@ -1,35 +1,51 @@
|
||||
import { HacknetNode,
|
||||
BaseCostForHacknetNode,
|
||||
HacknetNodePurchaseNextMult,
|
||||
HacknetNodeMaxLevel,
|
||||
HacknetNodeMaxRam,
|
||||
HacknetNodeMaxCores } from "./HacknetNode";
|
||||
import { HacknetServer,
|
||||
BaseCostForHacknetServer,
|
||||
HacknetServerPurchaseMult,
|
||||
HacknetServerMaxLevel,
|
||||
HacknetServerMaxRam,
|
||||
HacknetServerMaxCores,
|
||||
HacknetServerMaxCache,
|
||||
MaxNumberHacknetServers } from "./HacknetServer";
|
||||
import { HashManager } from "./HashManager";
|
||||
import { HashUpgrades } from "./HashUpgrades";
|
||||
/**
|
||||
* Generic helper/utility functions for the Hacknet mechanic:
|
||||
* - Purchase nodes/upgrades
|
||||
* - Calculating maximum number of upgrades
|
||||
* - Processing Hacknet earnings
|
||||
* - Updating Hash Manager capacity
|
||||
* - Purchasing hash upgrades
|
||||
*
|
||||
* TODO Should probably split the different types of functions into their own modules
|
||||
*/
|
||||
import {
|
||||
HacknetNode,
|
||||
BaseCostForHacknetNode,
|
||||
HacknetNodePurchaseNextMult,
|
||||
HacknetNodeMaxLevel,
|
||||
HacknetNodeMaxRam,
|
||||
HacknetNodeMaxCores
|
||||
} from "./HacknetNode";
|
||||
import {
|
||||
HacknetServer,
|
||||
BaseCostForHacknetServer,
|
||||
HacknetServerPurchaseMult,
|
||||
HacknetServerMaxLevel,
|
||||
HacknetServerMaxRam,
|
||||
HacknetServerMaxCores,
|
||||
HacknetServerMaxCache,
|
||||
MaxNumberHacknetServers
|
||||
} from "./HacknetServer";
|
||||
import { HashManager } from "./HashManager";
|
||||
import { HashUpgrades } from "./HashUpgrades";
|
||||
|
||||
import { generateRandomContract } from "../CodingContractGenerator";
|
||||
import { iTutorialSteps, iTutorialNextStep,
|
||||
ITutorial} from "../InteractiveTutorial";
|
||||
import { Player } from "../Player";
|
||||
import { AddToAllServers,
|
||||
AllServers } from "../Server/AllServers";
|
||||
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
import { Page, routing } from "../ui/navigationTracking";
|
||||
import { generateRandomContract } from "../CodingContractGenerator";
|
||||
import {
|
||||
iTutorialSteps,
|
||||
iTutorialNextStep,
|
||||
ITutorial
|
||||
} from "../InteractiveTutorial";
|
||||
import { Player } from "../Player";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
import { Page, routing } from "../ui/navigationTracking";
|
||||
|
||||
import {getElementById} from "../../utils/uiHelpers/getElementById";
|
||||
import { getElementById } from "../../utils/uiHelpers/getElementById";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { HacknetRoot } from "./ui/Root";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { HacknetRoot } from "./ui/Root";
|
||||
|
||||
let hacknetNodesDiv;
|
||||
function hacknetNodesInit() {
|
||||
@@ -66,7 +82,7 @@ export function purchaseHacknet() {
|
||||
if (!Player.canAfford(cost)) { return -1; }
|
||||
Player.loseMoney(cost);
|
||||
const server = Player.createHacknetServer();
|
||||
Player.hashManager.updateCapacity(Player);
|
||||
updateHashManagerCapacity();
|
||||
|
||||
return numOwned;
|
||||
} else {
|
||||
@@ -79,8 +95,7 @@ export function purchaseHacknet() {
|
||||
|
||||
// Auto generate a name for the Node
|
||||
const name = "hacknet-node-" + numOwned;
|
||||
const node = new HacknetNode(name);
|
||||
node.updateMoneyGainRate(Player);
|
||||
const node = new HacknetNode(name, Player.hacknet_node_money_mult);
|
||||
|
||||
Player.loseMoney(cost);
|
||||
Player.hacknetNodes.push(node);
|
||||
@@ -110,32 +125,32 @@ export function getCostOfNextHacknetServer() {
|
||||
return BaseCostForHacknetServer * Math.pow(mult, numOwned) * Player.hacknet_node_purchase_cost_mult;
|
||||
}
|
||||
|
||||
//Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's level
|
||||
export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1, Player))) {
|
||||
if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1, Player.hacknet_node_level_cost_mult))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 1;
|
||||
let max = maxLevel - 1;
|
||||
let levelsToMax = maxLevel - nodeObj.level;
|
||||
if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, Player))) {
|
||||
if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, Player.hacknet_node_level_cost_mult))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
while (min <= max) {
|
||||
var curr = (min + max) / 2 | 0;
|
||||
if (curr !== maxLevel &&
|
||||
Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player)) &&
|
||||
Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, Player))) {
|
||||
Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult)) &&
|
||||
Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, Player.hacknet_node_level_cost_mult))) {
|
||||
return Math.min(levelsToMax, curr);
|
||||
} else if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, Player))) {
|
||||
} else if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult))) {
|
||||
max = curr - 1;
|
||||
} else if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player))) {
|
||||
} else if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult))) {
|
||||
min = curr + 1;
|
||||
} else {
|
||||
return Math.min(levelsToMax, curr);
|
||||
@@ -144,12 +159,13 @@ export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's RAM
|
||||
export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (Player.money.lt(nodeObj.calculateRamUpgradeCost(1, Player))) {
|
||||
if (Player.money.lt(nodeObj.calculateRamUpgradeCost(1, Player.hacknet_node_ram_cost_mult))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -159,45 +175,46 @@ export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
||||
} else {
|
||||
levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram));
|
||||
}
|
||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, Player))) {
|
||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, Player.hacknet_node_ram_cost_mult))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
//We'll just loop until we find the max
|
||||
for (let i = levelsToMax-1; i >= 0; --i) {
|
||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(i, Player))) {
|
||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(i, Player.hacknet_node_ram_cost_mult))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cores
|
||||
export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(1, Player))) {
|
||||
if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(1, Player.hacknet_node_core_cost_mult))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 1;
|
||||
let max = maxLevel - 1;
|
||||
const levelsToMax = maxLevel - nodeObj.cores;
|
||||
if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, Player))) {
|
||||
if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, Player.hacknet_node_core_cost_mult))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
//Use a binary search to find the max possible number of upgrades
|
||||
// Use a binary search to find the max possible number of upgrades
|
||||
while (min <= max) {
|
||||
let curr = (min + max) / 2 | 0;
|
||||
if (curr != maxLevel &&
|
||||
Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player)) &&
|
||||
Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, Player))) {
|
||||
Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult)) &&
|
||||
Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, Player.hacknet_node_core_cost_mult))) {
|
||||
return Math.min(levelsToMax, curr);
|
||||
} else if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, Player))) {
|
||||
} else if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult))) {
|
||||
max = curr - 1;
|
||||
} else if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player))) {
|
||||
} else if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult))) {
|
||||
min = curr + 1;
|
||||
} else {
|
||||
return Math.min(levelsToMax, curr);
|
||||
@@ -207,6 +224,7 @@ export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cache
|
||||
export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberCacheUpgrades() called without maxLevel arg`);
|
||||
@@ -242,7 +260,136 @@ export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initial construction of Hacknet Nodes UI
|
||||
export function purchaseLevelUpgrade(node, levels=1) {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, Player.hacknet_node_level_cost_mult);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isServer = (node instanceof HacknetServer);
|
||||
|
||||
// If we're at max level, return false
|
||||
if (node.level >= (isServer ? HacknetServerMaxLevel : HacknetNodeMaxLevel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the number of specified upgrades would exceed the max level, calculate
|
||||
// the maximum number of upgrades and use that
|
||||
if (node.level + sanitizedLevels > (isServer ? HacknetServerMaxLevel : HacknetNodeMaxLevel)) {
|
||||
const diff = Math.max(0, (isServer ? HacknetServerMaxLevel : HacknetNodeMaxLevel) - node.level);
|
||||
return purchaseLevelUpgrade(node, diff);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeLevel(sanitizedLevels, Player.hacknet_node_money_mult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function purchaseRamUpgrade(node, levels=1) {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateRamUpgradeCost(sanitizedLevels, Player.hacknet_node_ram_cost_mult);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isServer = (node instanceof HacknetServer);
|
||||
|
||||
// Fail if we're already at max
|
||||
if (node.ram >= (isServer ? HacknetServerMaxRam : HacknetNodeMaxRam)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the number of specified upgrades would exceed the max RAM, calculate the
|
||||
// max possible number of upgrades and use that
|
||||
if (isServer) {
|
||||
if (node.maxRam * Math.pow(2, sanitizedLevels) > HacknetServerMaxRam) {
|
||||
const diff = Math.max(0, Math.log2(Math.round(HacknetServerMaxRam / node.maxRam)));
|
||||
return purchaseRamUpgrade(node, diff);
|
||||
}
|
||||
} else {
|
||||
if (node.ram * Math.pow(2, sanitizedLevels) > HacknetNodeMaxRam) {
|
||||
const diff = Math.max(0, Math.log2(Math.round(HacknetNodeMaxRam / node.ram)));
|
||||
return purchaseRamUpgrade(node, diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeRam(sanitizedLevels, Player.hacknet_node_money_mult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function purchaseCoreUpgrade(node, levels=1) {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, Player.hacknet_node_core_cost_mult);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isServer = (node instanceof HacknetServer);
|
||||
|
||||
// Fail if we're already at max
|
||||
if (node.cores >= (isServer ? HacknetServerMaxCores : HacknetNodeMaxCores)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the specified number of upgrades would exceed the max Cores, calculate
|
||||
// the max possible number of upgrades and use that
|
||||
if (node.cores + sanitizedLevels > (isServer ? HacknetServerMaxCores : HacknetNodeMaxCores)) {
|
||||
const diff = Math.max(0, (isServer ? HacknetServerMaxCores : HacknetNodeMaxCores) - node.cores);
|
||||
return purchaseCoreUpgrade(node, diff);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeCore(sanitizedLevels, Player.hacknet_node_money_mult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function purchaseCacheUpgrade(node, levels=1) {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateCacheUpgradeCost(sanitizedLevels);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
console.warn(`purchaseCacheUpgrade() called for a non-HacknetNode`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fail if we're already at max
|
||||
if (node.cache + sanitizedLevels > HacknetServerMaxCache) {
|
||||
const diff = Math.max(0, HacknetServerMaxCache - node.cache);
|
||||
return purchaseCacheUpgrade(node, diff);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeCache(sanitizedLevels);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create/Refresh Hacknet Nodes UI
|
||||
export function renderHacknetNodesUI() {
|
||||
if (!routing.isOn(Page.HacknetNodes)) { return; }
|
||||
|
||||
@@ -294,7 +441,10 @@ function processAllHacknetServerEarnings(numCycles) {
|
||||
|
||||
let hashes = 0;
|
||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
||||
const hserver = AllServers[Player.hacknetNodes[i]]; // hacknetNodes array only contains the IP addresses
|
||||
// hacknetNodes array only contains the IP addresses of the servers.
|
||||
// Also, update the hash rate before processing
|
||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
||||
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
||||
hashes += hserver.process(numCycles);
|
||||
}
|
||||
|
||||
@@ -303,6 +453,37 @@ function processAllHacknetServerEarnings(numCycles) {
|
||||
return hashes;
|
||||
}
|
||||
|
||||
export function updateHashManagerCapacity() {
|
||||
if (!(Player.hashManager instanceof HashManager)) {
|
||||
console.error(`Player does not have a HashManager`);
|
||||
return;
|
||||
}
|
||||
|
||||
const nodes = Player.hacknetNodes;
|
||||
if (nodes.length === 0) {
|
||||
Player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
if (typeof nodes[i] !== "string") {
|
||||
Player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const h = AllServers[nodes[i]];
|
||||
if (!(h instanceof HacknetServer)) {
|
||||
Player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
}
|
||||
|
||||
total += h.hashCapacity;
|
||||
}
|
||||
|
||||
Player.hashManager.updateCapacity(total);
|
||||
}
|
||||
|
||||
export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
if (!(Player.hashManager instanceof HashManager)) {
|
||||
console.error(`Player does not have a HashManager`);
|
||||
@@ -317,6 +498,7 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
switch (upgName) {
|
||||
case "Sell for Money": {
|
||||
Player.gainMoney(upg.value);
|
||||
Player.recordMoneySource(upg.value, "hacknetnode");
|
||||
break;
|
||||
}
|
||||
case "Sell for Corporation Funds": {
|
||||
|
||||
@@ -9,7 +9,6 @@ import { IHacknetNode } from "./IHacknetNode";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { Generic_fromJSON,
|
||||
@@ -62,12 +61,14 @@ export class HacknetNode implements IHacknetNode {
|
||||
// Total money earned by this Node
|
||||
totalMoneyGenerated: number = 0;
|
||||
|
||||
constructor(name: string="") {
|
||||
constructor(name: string="", prodMult: number=1) {
|
||||
this.name = name;
|
||||
|
||||
this.updateMoneyGainRate(prodMult);
|
||||
}
|
||||
|
||||
// Get the cost to upgrade this Node's number of cores
|
||||
calculateCoreUpgradeCost(levels: number=1, p: IPlayer): number {
|
||||
calculateCoreUpgradeCost(levels: number=1, costMult: number): number {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
@@ -86,13 +87,13 @@ export class HacknetNode implements IHacknetNode {
|
||||
++currentCores;
|
||||
}
|
||||
|
||||
totalCost *= p.hacknet_node_core_cost_mult;
|
||||
totalCost *= costMult;
|
||||
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
// Get the cost to upgrade this Node's level
|
||||
calculateLevelUpgradeCost(levels: number=1, p: IPlayer): number {
|
||||
calculateLevelUpgradeCost(levels: number=1, costMult: number): number {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
@@ -110,11 +111,11 @@ export class HacknetNode implements IHacknetNode {
|
||||
++currLevel;
|
||||
}
|
||||
|
||||
return BaseCostForHacknetNode / 2 * totalMultiplier * p.hacknet_node_level_cost_mult;
|
||||
return BaseCostForHacknetNode / 2 * totalMultiplier * costMult;
|
||||
}
|
||||
|
||||
// Get the cost to upgrade this Node's RAM
|
||||
calculateRamUpgradeCost(levels: number=1, p: IPlayer): number {
|
||||
calculateRamUpgradeCost(levels: number=1, costMult: number): number {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
@@ -138,7 +139,7 @@ export class HacknetNode implements IHacknetNode {
|
||||
++numUpgrades;
|
||||
}
|
||||
|
||||
totalCost *= p.hacknet_node_ram_cost_mult;
|
||||
totalCost *= costMult;
|
||||
|
||||
return totalCost;
|
||||
}
|
||||
@@ -161,112 +162,37 @@ export class HacknetNode implements IHacknetNode {
|
||||
|
||||
// Upgrade this Node's number of cores, if possible
|
||||
// Returns a boolean indicating whether new cores were successfully bought
|
||||
purchaseCoreUpgrade(levels: number=1, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateCoreUpgradeCost(sanitizedLevels, p);
|
||||
if (isNaN(cost) || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fail if we're already at max
|
||||
if (this.cores >= HacknetNodeMaxCores) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the specified number of upgrades would exceed the max Cores, calculate
|
||||
// the max possible number of upgrades and use that
|
||||
if (this.cores + sanitizedLevels > HacknetNodeMaxCores) {
|
||||
const diff = Math.max(0, HacknetNodeMaxCores - this.cores);
|
||||
return this.purchaseCoreUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
this.cores = Math.round(this.cores + sanitizedLevels); // Just in case of floating point imprecision
|
||||
this.updateMoneyGainRate(p);
|
||||
|
||||
return true;
|
||||
upgradeCore(levels: number=1, prodMult: number): void {
|
||||
this.cores = Math.min(HacknetNodeMaxCores, Math.round(this.cores + levels));
|
||||
this.updateMoneyGainRate(prodMult);
|
||||
}
|
||||
|
||||
// Upgrade this Node's level, if possible
|
||||
// Returns a boolean indicating whether the level was successfully updated
|
||||
purchaseLevelUpgrade(levels: number=1, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateLevelUpgradeCost(sanitizedLevels, p);
|
||||
if (isNaN(cost) || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're at max level, return false
|
||||
if (this.level >= HacknetNodeMaxLevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the number of specified upgrades would exceed the max level, calculate
|
||||
// the maximum number of upgrades and use that
|
||||
if (this.level + sanitizedLevels > HacknetNodeMaxLevel) {
|
||||
var diff = Math.max(0, HacknetNodeMaxLevel - this.level);
|
||||
return this.purchaseLevelUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
this.level = Math.round(this.level + sanitizedLevels); // Just in case of floating point imprecision
|
||||
this.updateMoneyGainRate(p);
|
||||
|
||||
return true;
|
||||
upgradeLevel(levels: number=1, prodMult: number): void {
|
||||
this.level = Math.min(HacknetNodeMaxLevel, Math.round(this.level + levels));
|
||||
this.updateMoneyGainRate(prodMult);
|
||||
}
|
||||
|
||||
// Upgrade this Node's RAM, if possible
|
||||
// Returns a boolean indicating whether the RAM was successfully upgraded
|
||||
purchaseRamUpgrade(levels: number=1, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateRamUpgradeCost(sanitizedLevels, p);
|
||||
if (isNaN(cost) || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fail if we're already at max
|
||||
if (this.ram >= HacknetNodeMaxRam) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the number of specified upgrades would exceed the max RAM, calculate the
|
||||
// max possible number of upgrades and use that
|
||||
if (this.ram * Math.pow(2, sanitizedLevels) > HacknetNodeMaxRam) {
|
||||
var diff = Math.max(0, Math.log2(Math.round(HacknetNodeMaxRam / this.ram)));
|
||||
return this.purchaseRamUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
for (let i = 0; i < sanitizedLevels; ++i) {
|
||||
upgradeRam(levels: number=1, prodMult: number): void {
|
||||
for (let i = 0; i < levels; ++i) {
|
||||
this.ram *= 2; // Ram is always doubled
|
||||
}
|
||||
this.ram = Math.round(this.ram); // Handle any floating point precision issues
|
||||
this.updateMoneyGainRate(p);
|
||||
|
||||
return true;
|
||||
this.updateMoneyGainRate(prodMult);
|
||||
}
|
||||
|
||||
// Re-calculate this Node's production and update the moneyGainRatePerSecond prop
|
||||
updateMoneyGainRate(p: IPlayer): void {
|
||||
updateMoneyGainRate(prodMult: number): void {
|
||||
//How much extra $/s is gained per level
|
||||
var gainPerLevel = HacknetNodeMoneyGainPerLevel;
|
||||
|
||||
this.moneyGainRatePerSecond = (this.level * gainPerLevel) *
|
||||
Math.pow(1.035, this.ram - 1) *
|
||||
((this.cores + 5) / 6) *
|
||||
p.hacknet_node_money_mult *
|
||||
prodMult *
|
||||
BitNodeMultipliers.HacknetNodeMoney;
|
||||
if (isNaN(this.moneyGainRatePerSecond)) {
|
||||
this.moneyGainRatePerSecond = 0;
|
||||
|
||||
@@ -6,15 +6,16 @@ import { CONSTANTS } from "../Constants";
|
||||
import { IHacknetNode } from "./IHacknetNode";
|
||||
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
import { RunningScript } from "../Script/RunningScript";
|
||||
|
||||
import { createRandomIp } from "../../utils/IPAddress";
|
||||
|
||||
import { Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver } from "../../utils/JSONReviver";
|
||||
import {
|
||||
Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver
|
||||
} from "../../utils/JSONReviver";
|
||||
|
||||
// Constants for Hacknet Server stats/production
|
||||
export const HacknetServerHashesPerLevel: number = 0.001;
|
||||
@@ -31,7 +32,7 @@ export const HacknetServerUpgradeRamMult: number = 1.4; // Multiplier for co
|
||||
export const HacknetServerUpgradeCoreMult: number = 1.55; // Multiplier for cost when buying another core
|
||||
export const HacknetServerUpgradeCacheMult: number = 1.85; // Multiplier for cost when upgrading cache
|
||||
|
||||
export const MaxNumberHacknetServers: number = 25; // Max number of Hacknet Servers you can own
|
||||
export const MaxNumberHacknetServers: number = 20; // Max number of Hacknet Servers you can own
|
||||
|
||||
// Constants for max upgrade levels for Hacknet Server
|
||||
export const HacknetServerMaxLevel: number = 300;
|
||||
@@ -46,7 +47,6 @@ interface IConstructorParams {
|
||||
isConnectedTo?: boolean;
|
||||
maxRam?: number;
|
||||
organizationName?: string;
|
||||
player?: IPlayer;
|
||||
}
|
||||
|
||||
export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
@@ -81,10 +81,6 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
|
||||
this.maxRam = 1;
|
||||
this.updateHashCapacity();
|
||||
|
||||
if (params.player) {
|
||||
this.updateHashRate(params.player);
|
||||
}
|
||||
}
|
||||
|
||||
calculateCacheUpgradeCost(levels: number): number {
|
||||
@@ -109,7 +105,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
calculateCoreUpgradeCost(levels: number, p: IPlayer): number {
|
||||
calculateCoreUpgradeCost(levels: number, costMult: number): number {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
@@ -127,12 +123,12 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
++currentCores;
|
||||
}
|
||||
totalCost *= BaseCostForHacknetServerCore;
|
||||
totalCost *= p.hacknet_node_core_cost_mult;
|
||||
totalCost *= costMult;
|
||||
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
calculateLevelUpgradeCost(levels: number, p: IPlayer): number {
|
||||
calculateLevelUpgradeCost(levels: number, costMult: number): number {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
@@ -150,10 +146,10 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
++currLevel;
|
||||
}
|
||||
|
||||
return 10 * BaseCostForHacknetServer * totalMultiplier * p.hacknet_node_level_cost_mult;
|
||||
return 10 * BaseCostForHacknetServer * totalMultiplier * costMult;
|
||||
}
|
||||
|
||||
calculateRamUpgradeCost(levels: number, p: IPlayer): number {
|
||||
calculateRamUpgradeCost(levels: number, costMult: number): number {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
|
||||
return 0;
|
||||
@@ -175,149 +171,48 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
currentRam *= 2;
|
||||
++numUpgrades;
|
||||
}
|
||||
totalCost *= p.hacknet_node_ram_cost_mult;
|
||||
totalCost *= costMult;
|
||||
|
||||
return totalCost;
|
||||
}
|
||||
|
||||
// Process this Hacknet Server in the game loop.
|
||||
// Returns the number of hashes generated
|
||||
// Process this Hacknet Server in the game loop. Returns the number of hashes generated
|
||||
process(numCycles: number=1): number {
|
||||
const seconds = numCycles * CONSTANTS.MilliPerCycle / 1000;
|
||||
|
||||
return this.hashRate * seconds;
|
||||
}
|
||||
|
||||
// Returns a boolean indicating whether the cache was successfully upgraded
|
||||
purchaseCacheUpgrade(levels: number, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateCacheUpgradeCost(levels);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.cache >= HacknetServerMaxCache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the specified number of upgrades would exceed the max, try to purchase
|
||||
// the maximum possible
|
||||
if (this.cache + levels > HacknetServerMaxCache) {
|
||||
const diff = Math.max(0, HacknetServerMaxCache - this.cache);
|
||||
return this.purchaseCacheUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
this.cache = Math.round(this.cache + sanitizedLevels);
|
||||
upgradeCache(levels: number): void {
|
||||
this.cache = Math.min(HacknetServerMaxCache, Math.round(this.cache + levels));
|
||||
this.updateHashCapacity();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns a boolean indicating whether the number of cores was successfully upgraded
|
||||
purchaseCoreUpgrade(levels: number, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateCoreUpgradeCost(sanitizedLevels, p);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.cores >= HacknetServerMaxCores) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the specified number of upgrades would exceed the max, try to purchase
|
||||
// the maximum possible
|
||||
if (this.cores + sanitizedLevels > HacknetServerMaxCores) {
|
||||
const diff = Math.max(0, HacknetServerMaxCores - this.cores);
|
||||
return this.purchaseCoreUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
this.cores = Math.round(this.cores + sanitizedLevels);
|
||||
this.updateHashRate(p);
|
||||
|
||||
return true;
|
||||
upgradeCore(levels: number, prodMult: number): void {
|
||||
this.cores = Math.min(HacknetServerMaxCores, Math.round(this.cores + levels));
|
||||
this.updateHashRate(prodMult);
|
||||
}
|
||||
|
||||
// Returns a boolean indicating whether the level was successfully upgraded
|
||||
purchaseLevelUpgrade(levels: number, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateLevelUpgradeCost(sanitizedLevels, p);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.level >= HacknetServerMaxLevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the specified number of upgrades would exceed the max, try to purchase the
|
||||
// maximum possible
|
||||
if (this.level + sanitizedLevels > HacknetServerMaxLevel) {
|
||||
const diff = Math.max(0, HacknetServerMaxLevel - this.level);
|
||||
return this.purchaseLevelUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
this.level = Math.round(this.level + sanitizedLevels);
|
||||
this.updateHashRate(p);
|
||||
|
||||
return true;
|
||||
upgradeLevel(levels: number, prodMult: number): void {
|
||||
this.level = Math.min(HacknetServerMaxLevel, Math.round(this.level + levels));
|
||||
this.updateHashRate(prodMult);
|
||||
}
|
||||
|
||||
// Returns a boolean indicating whether the RAM was successfully upgraded
|
||||
purchaseRamUpgrade(levels: number, p: IPlayer): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = this.calculateRamUpgradeCost(sanitizedLevels, p);
|
||||
if(isNaN(cost) || cost <= 0 || sanitizedLevels <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.maxRam >= HacknetServerMaxRam) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the specified number of upgrades would exceed the max, try to purchase
|
||||
// just the maximum possible
|
||||
if (this.maxRam * Math.pow(2, sanitizedLevels) > HacknetServerMaxRam) {
|
||||
const diff = Math.max(0, Math.log2(Math.round(HacknetServerMaxRam / this.maxRam)));
|
||||
return this.purchaseRamUpgrade(diff, p);
|
||||
}
|
||||
|
||||
if (!p.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
for (let i = 0; i < sanitizedLevels; ++i) {
|
||||
upgradeRam(levels: number, prodMult: number): boolean {
|
||||
for (let i = 0; i < levels; ++i) {
|
||||
this.maxRam *= 2;
|
||||
}
|
||||
this.maxRam = Math.round(this.maxRam);
|
||||
this.updateHashRate(p);
|
||||
this.maxRam = Math.min(HacknetServerMaxRam, Math.round(this.maxRam));
|
||||
this.updateHashRate(prodMult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever a script is run, we must update this server's hash rate
|
||||
*/
|
||||
runScript(script: RunningScript, p?: IPlayer): void {
|
||||
|
||||
// Whenever a script is run, we must update this server's hash rate
|
||||
runScript(script: RunningScript, prodMult?: number): void {
|
||||
super.runScript(script);
|
||||
if (p) {
|
||||
this.updateHashRate(p);
|
||||
if (prodMult != null && typeof prodMult === "number") {
|
||||
this.updateHashRate(prodMult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +220,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
this.hashCapacity = 32 * Math.pow(2, this.cache);
|
||||
}
|
||||
|
||||
updateHashRate(p: IPlayer): void {
|
||||
updateHashRate(prodMult: number): void {
|
||||
const baseGain = HacknetServerHashesPerLevel * this.level;
|
||||
const ramMultiplier = Math.pow(1.07, Math.log2(this.maxRam));
|
||||
const coreMultiplier = 1 + (this.cores - 1) / 5;
|
||||
@@ -333,7 +228,7 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
|
||||
|
||||
const hashRate = baseGain * ramMultiplier * coreMultiplier * ramRatio;
|
||||
|
||||
this.hashRate = hashRate * p.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney;
|
||||
this.hashRate = hashRate * prodMult * BitNodeMultipliers.HacknetNodeMoney;
|
||||
|
||||
if (isNaN(this.hashRate)) {
|
||||
this.hashRate = 0;
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
* his hashes, and contains method for grabbing the data/multipliers from
|
||||
* those upgrades
|
||||
*/
|
||||
import { HacknetServer } from "./HacknetServer";
|
||||
import { HashUpgrades } from "./HashUpgrades";
|
||||
|
||||
import { IMap } from "../types";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver } from "../../utils/JSONReviver";
|
||||
@@ -84,14 +81,14 @@ export class HashManager {
|
||||
return upg.getCost(currLevel);
|
||||
}
|
||||
|
||||
prestige(p: IPlayer): void {
|
||||
prestige(): void {
|
||||
for (const name in HashUpgrades) {
|
||||
this.upgrades[name] = 0;
|
||||
}
|
||||
this.hashes = 0;
|
||||
if (p != null) {
|
||||
this.updateCapacity(p);
|
||||
}
|
||||
|
||||
// When prestiging, player's hacknet nodes are always reset. So capacity = 0
|
||||
this.updateCapacity(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,14 +96,16 @@ export class HashManager {
|
||||
*/
|
||||
refundUpgrade(upgName: string): void {
|
||||
const upg = HashUpgrades[upgName];
|
||||
|
||||
// Reduce the level first, so we get the right cost
|
||||
--this.upgrades[upgName];
|
||||
|
||||
const currLevel = this.upgrades[upgName];
|
||||
if (upg == null || currLevel == null || currLevel === 0) {
|
||||
if (upg == null || currLevel == null || currLevel < 0) {
|
||||
console.error(`Invalid Upgrade Name given to HashManager.upgrade(): ${upgName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reduce the level first, so we get the right cost
|
||||
--this.upgrades[upgName];
|
||||
const cost = upg.getCost(currLevel);
|
||||
this.hashes += cost;
|
||||
}
|
||||
@@ -116,33 +115,11 @@ export class HashManager {
|
||||
this.hashes = Math.min(this.hashes, this.capacity);
|
||||
}
|
||||
|
||||
updateCapacity(p: IPlayer): void {
|
||||
if (p.hacknetNodes.length <= 0) {
|
||||
updateCapacity(newCap: number): void {
|
||||
if (newCap < 0) {
|
||||
this.capacity = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the Player's `hacknetNodes` property actually holds Hacknet Servers
|
||||
const ip: string = <string>p.hacknetNodes[0];
|
||||
if (typeof ip !== "string") {
|
||||
this.capacity = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const hserver = <HacknetServer>AllServers[ip];
|
||||
if (!(hserver instanceof HacknetServer)) {
|
||||
this.capacity = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let total: number = 0;
|
||||
for (let i = 0; i < p.hacknetNodes.length; ++i) {
|
||||
const h = <HacknetServer>AllServers[<string>p.hacknetNodes[i]];
|
||||
total += h.hashCapacity;
|
||||
}
|
||||
|
||||
this.capacity = total;
|
||||
this.capacity = Math.max(newCap, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
// Interface for a Hacknet Node. Implemented by both a basic Hacknet Node,
|
||||
// and the upgraded Hacknet Server in BitNode-9
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
|
||||
export interface IHacknetNode {
|
||||
cores: number;
|
||||
level: number;
|
||||
onlineTimeSeconds: number;
|
||||
|
||||
calculateCoreUpgradeCost: (levels: number, p: IPlayer) => number;
|
||||
calculateLevelUpgradeCost: (levels: number, p: IPlayer) => number;
|
||||
calculateRamUpgradeCost: (levels: number, p: IPlayer) => number;
|
||||
purchaseCoreUpgrade: (levels: number, p: IPlayer) => boolean;
|
||||
purchaseLevelUpgrade: (levels: number, p: IPlayer) => boolean;
|
||||
purchaseRamUpgrade: (levels: number, p: IPlayer) => boolean;
|
||||
calculateCoreUpgradeCost: (levels: number, costMult: number) => number;
|
||||
calculateLevelUpgradeCost: (levels: number, costMult: number) => number;
|
||||
calculateRamUpgradeCost: (levels: number, costMult: number) => number;
|
||||
upgradeCore: (levels: number, prodMult: number) => void;
|
||||
upgradeLevel: (levels: number, prodMult: number) => void;
|
||||
upgradeRam: (levels: number, prodMult: number) => void;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,17 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
|
||||
{
|
||||
costPerLevel: 50,
|
||||
desc: "Use hashes to decrease the minimum security of a single server by 2%. " +
|
||||
"Note that a server's minimum security cannot go below 1.",
|
||||
"Note that a server's minimum security cannot go below 1. This effect persists " +
|
||||
"until you install Augmentations (since servers are reset at that time).",
|
||||
hasTargetServer: true,
|
||||
name: "Reduce Minimum Security",
|
||||
value: 0.98,
|
||||
},
|
||||
{
|
||||
costPerLevel: 50,
|
||||
desc: "Use hashes to increase the maximum amount of money on a single server by 2%",
|
||||
desc: "Use hashes to increase the maximum amount of money on a single server by 2%. " +
|
||||
"This effect persists until you install Augmentations (since servers " +
|
||||
"are reset at that time).",
|
||||
hasTargetServer: true,
|
||||
name: "Increase Maximum Money",
|
||||
value: 1.02,
|
||||
|
||||
@@ -15,7 +15,7 @@ export class GeneralInfo extends React.Component {
|
||||
`you hashes. Hashes can be spent on a variety of different upgrades.`;
|
||||
} else {
|
||||
return `Here, you can purchase a Hacknet Node, a specialized machine that can connect ` +
|
||||
`and contribute its resources to the Hacknet networ. This allows you to take ` +
|
||||
`and contribute its resources to the Hacknet network. This allows you to take ` +
|
||||
`a small percentage of profits from hacks performed on the network. Essentially, ` +
|
||||
`you are renting out your Node's computing power.`;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { HacknetNodeMaxLevel,
|
||||
HacknetNodeMaxRam,
|
||||
HacknetNodeMaxCores } from "../HacknetNode";
|
||||
import { getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades } from "../HacknetHelpers";
|
||||
import {
|
||||
HacknetNodeMaxLevel,
|
||||
HacknetNodeMaxRam,
|
||||
HacknetNodeMaxCores
|
||||
} from "../HacknetNode";
|
||||
import {
|
||||
getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
|
||||
@@ -35,7 +42,7 @@ export class HacknetNode extends React.Component {
|
||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
||||
}
|
||||
|
||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player);
|
||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.hacknet_node_level_cost_mult);
|
||||
upgradeLevelText = `Upgrade x${multiplier} - ${numeralWrapper.formatMoney(upgradeLevelCost)}`;
|
||||
if (Player.money.lt(upgradeLevelCost)) {
|
||||
upgradeLevelClass = "std-button-disabled";
|
||||
@@ -48,7 +55,7 @@ export class HacknetNode extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetNodeMaxLevel);
|
||||
}
|
||||
node.purchaseLevelUpgrade(numUpgrades, Player);
|
||||
purchaseLevelUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
return false;
|
||||
}
|
||||
@@ -66,7 +73,7 @@ export class HacknetNode extends React.Component {
|
||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
||||
}
|
||||
|
||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player);
|
||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.hacknet_node_ram_cost_mult);
|
||||
upgradeRamText = `Upgrade x${multiplier} - ${numeralWrapper.formatMoney(upgradeRamCost)}`;
|
||||
if (Player.money.lt(upgradeRamCost)) {
|
||||
upgradeRamClass = "std-button-disabled";
|
||||
@@ -79,7 +86,7 @@ export class HacknetNode extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberRamUpgrades(node, HacknetNodeMaxRam);
|
||||
}
|
||||
node.purchaseRamUpgrade(numUpgrades, Player);
|
||||
purchaseRamUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
return false;
|
||||
}
|
||||
@@ -97,7 +104,7 @@ export class HacknetNode extends React.Component {
|
||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
||||
}
|
||||
|
||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player);
|
||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.hacknet_node_core_cost_mult);
|
||||
upgradeCoresText = `Upgrade x${multiplier} - ${numeralWrapper.formatMoney(upgradeCoreCost)}`;
|
||||
if (Player.money.lt(upgradeCoreCost)) {
|
||||
upgradeCoresClass = "std-button-disabled";
|
||||
@@ -110,7 +117,7 @@ export class HacknetNode extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetNodeMaxCores);
|
||||
}
|
||||
node.purchaseCoreUpgrade(numUpgrades, Player);
|
||||
purchaseCoreUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,23 @@
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { HacknetServerMaxLevel,
|
||||
HacknetServerMaxRam,
|
||||
HacknetServerMaxCores,
|
||||
HacknetServerMaxCache } from "../HacknetServer";
|
||||
import { getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
getMaxNumberCacheUpgrades } from "../HacknetHelpers";
|
||||
import {
|
||||
HacknetServerMaxLevel,
|
||||
HacknetServerMaxRam,
|
||||
HacknetServerMaxCores,
|
||||
HacknetServerMaxCache
|
||||
} from "../HacknetServer";
|
||||
import {
|
||||
getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
getMaxNumberCacheUpgrades,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
purchaseCacheUpgrade,
|
||||
updateHashManagerCapacity,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
|
||||
@@ -37,7 +46,7 @@ export class HacknetServer extends React.Component {
|
||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
||||
}
|
||||
|
||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player);
|
||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.hacknet_node_level_cost_mult);
|
||||
upgradeLevelText = `Upgrade x${multiplier} - ${numeralWrapper.formatMoney(upgradeLevelCost)}`;
|
||||
if (Player.money.lt(upgradeLevelCost)) {
|
||||
upgradeLevelClass = "std-button-disabled";
|
||||
@@ -50,7 +59,7 @@ export class HacknetServer extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetServerMaxLevel);
|
||||
}
|
||||
node.purchaseLevelUpgrade(numUpgrades, Player);
|
||||
purchaseLevelUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
return false;
|
||||
}
|
||||
@@ -69,7 +78,7 @@ export class HacknetServer extends React.Component {
|
||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
||||
}
|
||||
|
||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player);
|
||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.hacknet_node_ram_cost_mult);
|
||||
upgradeRamText = `Upgrade x${multiplier} - ${numeralWrapper.formatMoney(upgradeRamCost)}`;
|
||||
if (Player.money.lt(upgradeRamCost)) {
|
||||
upgradeRamClass = "std-button-disabled";
|
||||
@@ -82,7 +91,7 @@ export class HacknetServer extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberRamUpgrades(node, HacknetServerMaxRam);
|
||||
}
|
||||
node.purchaseRamUpgrade(numUpgrades, Player);
|
||||
purchaseRamUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
return false;
|
||||
}
|
||||
@@ -101,7 +110,7 @@ export class HacknetServer extends React.Component {
|
||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
||||
}
|
||||
|
||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player);
|
||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.hacknet_node_core_cost_mult);
|
||||
upgradeCoresText = `Upgrade x${multiplier} - ${numeralWrapper.formatMoney(upgradeCoreCost)}`;
|
||||
if (Player.money.lt(upgradeCoreCost)) {
|
||||
upgradeCoresClass = "std-button-disabled";
|
||||
@@ -114,7 +123,7 @@ export class HacknetServer extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetServerMaxCores);
|
||||
}
|
||||
node.purchaseCoreUpgrade(numUpgrades, Player);
|
||||
purchaseCoreUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
return false;
|
||||
}
|
||||
@@ -146,9 +155,9 @@ export class HacknetServer extends React.Component {
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberCacheUpgrades(node, HacknetServerMaxCache);
|
||||
}
|
||||
node.purchaseCacheUpgrade(numUpgrades, Player);
|
||||
purchaseCacheUpgrade(node, numUpgrades);
|
||||
recalculate();
|
||||
Player.hashManager.updateCapacity(Player);
|
||||
updateHashManagerCapacity();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ export class HacknetRoot extends React.Component {
|
||||
}
|
||||
|
||||
this.createHashUpgradesPopup = this.createHashUpgradesPopup.bind(this);
|
||||
this.handlePurchaseButtonClick = this.handlePurchaseButtonClick.bind(this);
|
||||
this.recalculateTotalProduction = this.recalculateTotalProduction.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -50,6 +52,12 @@ export class HacknetRoot extends React.Component {
|
||||
createPopup(id, HashUpgradePopup, { popupId: id, rerender: this.createHashUpgradesPopup });
|
||||
}
|
||||
|
||||
handlePurchaseButtonClick() {
|
||||
if (purchaseHacknet() >= 0) {
|
||||
this.recalculateTotalProduction();
|
||||
}
|
||||
}
|
||||
|
||||
recalculateTotalProduction() {
|
||||
let total = 0;
|
||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
||||
@@ -85,13 +93,6 @@ export class HacknetRoot extends React.Component {
|
||||
purchaseCost = getCostOfNextHacknetNode();
|
||||
}
|
||||
|
||||
// onClick event handler for purchase button
|
||||
const purchaseOnClick = () => {
|
||||
if (purchaseHacknet() >= 0) {
|
||||
this.recalculateTotalProduction();
|
||||
}
|
||||
}
|
||||
|
||||
// onClick event handlers for purchase multiplier buttons
|
||||
const purchaseMultiplierOnClicks = [
|
||||
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x1),
|
||||
@@ -112,7 +113,7 @@ export class HacknetRoot extends React.Component {
|
||||
key={hserver.hostname}
|
||||
node={hserver}
|
||||
purchaseMultiplier={this.state.purchaseMultiplier}
|
||||
recalculate={this.recalculateTotalProduction.bind(this)}
|
||||
recalculate={this.recalculateTotalProduction}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
@@ -121,7 +122,7 @@ export class HacknetRoot extends React.Component {
|
||||
key={node.name}
|
||||
node={node}
|
||||
purchaseMultiplier={this.state.purchaseMultiplier}
|
||||
recalculate={this.recalculateTotalProduction.bind(this)}
|
||||
recalculate={this.recalculateTotalProduction}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -132,7 +133,7 @@ export class HacknetRoot extends React.Component {
|
||||
<h1>Hacknet Nodes</h1>
|
||||
<GeneralInfo />
|
||||
|
||||
<PurchaseButton cost={purchaseCost} multiplier={this.state.purchaseMultiplier} onClick={purchaseOnClick} />
|
||||
<PurchaseButton cost={purchaseCost} multiplier={this.state.purchaseMultiplier} onClick={this.handlePurchaseButtonClick} />
|
||||
|
||||
<br />
|
||||
<div id={"hacknet-nodes-money-multipliers-div"}>
|
||||
|
||||
@@ -129,7 +129,7 @@ function endInfiltration(inst, success) {
|
||||
clearEventListeners("infiltration-bribe");
|
||||
clearEventListeners("infiltration-escape");
|
||||
|
||||
Engine.loadLocationContent();
|
||||
Engine.loadLocationContent(false);
|
||||
}
|
||||
|
||||
function nextInfiltrationLevel(inst) {
|
||||
|
||||
@@ -321,7 +321,7 @@ function iTutorialEvaluateStep() {
|
||||
Engine.loadActiveScriptsContent();
|
||||
iTutorialSetText("This page displays stats/information about all of your scripts that are " +
|
||||
"running across every existing server. You can use this to gauge how well " +
|
||||
"your scripts are doing. Let's go back to the Terminal now using the 'Terminal'" +
|
||||
"your scripts are doing. Let's go back to the Terminal now using the 'Terminal' " +
|
||||
"link.");
|
||||
nextBtn.style.display = "none";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as acorn from "../utils/acorn";
|
||||
import * as acorn from "acorn";
|
||||
/**
|
||||
* @license
|
||||
* JavaScript Interpreter
|
||||
|
||||
@@ -2,46 +2,53 @@
|
||||
* Location and traveling-related helper functions.
|
||||
* Mostly used for UI
|
||||
*/
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
import { CityName } from "./data/CityNames";
|
||||
import { CityName } from "./data/CityNames";
|
||||
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { AllServers,
|
||||
AddToAllServers } from "../Server/AllServers";
|
||||
import { Server } from "../Server/Server";
|
||||
import { getPurchaseServerCost,
|
||||
purchaseRamForHomeComputer,
|
||||
purchaseServer } from "../Server/ServerPurchases";
|
||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import {
|
||||
AddToAllServers,
|
||||
createUniqueRandomIp,
|
||||
} from "../Server/AllServers";
|
||||
import { safetlyCreateUniqueServer } from "../Server/ServerHelpers";
|
||||
import {
|
||||
getPurchaseServerCost,
|
||||
purchaseRamForHomeComputer,
|
||||
purchaseServer
|
||||
} from "../Server/ServerPurchases";
|
||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { createRandomIp } from "../../utils/IPAddress";
|
||||
import { yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxClose,
|
||||
yesNoBoxCreate,
|
||||
yesNoTxtInpBoxGetYesButton,
|
||||
yesNoTxtInpBoxGetNoButton,
|
||||
yesNoTxtInpBoxClose,
|
||||
yesNoTxtInpBoxCreate } from "../../utils/YesNoBox";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import {
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoBoxClose,
|
||||
yesNoBoxCreate,
|
||||
yesNoTxtInpBoxGetYesButton,
|
||||
yesNoTxtInpBoxGetNoButton,
|
||||
yesNoTxtInpBoxClose,
|
||||
yesNoTxtInpBoxCreate
|
||||
} from "../../utils/YesNoBox";
|
||||
|
||||
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../../utils/uiHelpers/createPopup";
|
||||
import { createPopupCloseButton } from "../../utils/uiHelpers/createPopupCloseButton";
|
||||
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
|
||||
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../../utils/uiHelpers/createPopup";
|
||||
import { createPopupCloseButton } from "../../utils/uiHelpers/createPopupCloseButton";
|
||||
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
|
||||
|
||||
/**
|
||||
* Create a pop-up box that lets the player confirm traveling to a different city
|
||||
* If settings are configured to suppress this popup, just instantly travel
|
||||
* Create a pop-up box that lets the player confirm traveling to a different city.
|
||||
* If settings are configured to suppress this popup, just instantly travel.
|
||||
* The actual "Travel" implementation is implemented in the UI, and is passed in
|
||||
* as an argument
|
||||
* as an argument.
|
||||
* @param {CityName} destination - City that the player is traveling to
|
||||
* @param {Function} travelFn - Function that changes the player's state for traveling
|
||||
*/
|
||||
type TravelFunction = (to: CityName) => void;
|
||||
export function createTravelPopup(destination: CityName, travelFn: TravelFunction) {
|
||||
export function createTravelPopup(destination: CityName, travelFn: TravelFunction): void {
|
||||
const cost = CONSTANTS.TravelCost;
|
||||
|
||||
if (Settings.SuppressTravelConfirmation) {
|
||||
@@ -75,10 +82,10 @@ export function createTravelPopup(destination: CityName, travelFn: TravelFunctio
|
||||
|
||||
/**
|
||||
* Create a pop-up box that lets the player purchase a server.
|
||||
* @param ram - Amount of RAM (GB) on server
|
||||
* @param p - Player object
|
||||
* @param {number} ram - Amount of RAM (GB) on server
|
||||
* @param {IPlayer} p - Player object
|
||||
*/
|
||||
export function createPurchaseServerPopup(ram: number, p: IPlayer) {
|
||||
export function createPurchaseServerPopup(ram: number, p: IPlayer): void {
|
||||
const cost = getPurchaseServerCost(ram);
|
||||
if (cost === Infinity) {
|
||||
dialogBoxCreate("Something went wrong when trying to purchase this server. Please contact developer");
|
||||
@@ -106,6 +113,7 @@ export function createPurchaseServerPopup(ram: number, p: IPlayer) {
|
||||
|
||||
/**
|
||||
* Create a popup that lets the player start a Corporation
|
||||
* @param {IPlayer} p - Player object
|
||||
*/
|
||||
export function createStartCorporationPopup(p: IPlayer) {
|
||||
if (!p.canAccessCorporation() || p.hasCorporation()) { return; }
|
||||
@@ -167,8 +175,10 @@ export function createStartCorporationPopup(p: IPlayer) {
|
||||
if (worldHeader instanceof HTMLElement) {
|
||||
worldHeader.click(); worldHeader.click();
|
||||
}
|
||||
dialogBoxCreate("Congratulations! You just started your own corporation with government seed money. " +
|
||||
"You can visit and manage your company in the City");
|
||||
dialogBoxCreate(
|
||||
"Congratulations! You just started your own corporation with government seed money. " +
|
||||
"You can visit and manage your company in the City"
|
||||
);
|
||||
removeElementById(popupId);
|
||||
return false;
|
||||
}
|
||||
@@ -182,21 +192,23 @@ export function createStartCorporationPopup(p: IPlayer) {
|
||||
|
||||
/**
|
||||
* Create a popup that lets the player upgrade the cores on his/her home computer
|
||||
* @param p - Player object
|
||||
* @param {IPlayer} p - Player object
|
||||
*/
|
||||
export function createUpgradeHomeCoresPopup(p: IPlayer) {
|
||||
const currentCores = p.getHomeComputer().cpuCores;
|
||||
if (currentCores >= 8) { return; } // Max of 8 cores
|
||||
|
||||
//Cost of purchasing another cost is found by indexing this array with number of current cores
|
||||
const allCosts = [0,
|
||||
10e9, // 1->2 Cores - 10 bn
|
||||
250e9, // 2->3 Cores - 250 bn
|
||||
5e12, // 3->4 Cores - 5 trillion
|
||||
100e12, // 4->5 Cores - 100 trillion
|
||||
1e15, // 5->6 Cores - 1 quadrillion
|
||||
20e15, // 6->7 Cores - 20 quadrillion
|
||||
200e15]; // 7->8 Cores - 200 quadrillion
|
||||
// Cost of purchasing another cost is found by indexing this array with number of current cores
|
||||
const allCosts = [
|
||||
0,
|
||||
10e9,
|
||||
250e9,
|
||||
5e12,
|
||||
100e12,
|
||||
1e15,
|
||||
20e15,
|
||||
200e15
|
||||
];
|
||||
const cost: number = allCosts[currentCores];
|
||||
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
@@ -210,8 +222,10 @@ export function createUpgradeHomeCoresPopup(p: IPlayer) {
|
||||
} else {
|
||||
p.loseMoney(cost);
|
||||
p.getHomeComputer().cpuCores++;
|
||||
dialogBoxCreate("You purchased an additional CPU Core for your home computer! It now has " +
|
||||
p.getHomeComputer().cpuCores + " cores.");
|
||||
dialogBoxCreate(
|
||||
"You purchased an additional CPU Core for your home computer! It now has " +
|
||||
p.getHomeComputer().cpuCores + " cores."
|
||||
);
|
||||
}
|
||||
yesNoBoxClose();
|
||||
});
|
||||
@@ -221,15 +235,17 @@ export function createUpgradeHomeCoresPopup(p: IPlayer) {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
yesNoBoxCreate("Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " +
|
||||
"lets you start with an additional Core Node in Hacking Missions.<br><br>" +
|
||||
"Purchasing an additional core (for a total of " + (p.getHomeComputer().cpuCores + 1) + ") will " +
|
||||
"cost " + numeralWrapper.formatMoney(cost));
|
||||
yesNoBoxCreate(
|
||||
"Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " +
|
||||
"lets you start with an additional Core Node in Hacking Missions.<br><br>" +
|
||||
"Purchasing an additional core (for a total of " + (p.getHomeComputer().cpuCores + 1) + ") will " +
|
||||
"cost " + numeralWrapper.formatMoney(cost)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a popup that lets the player upgrade the RAM on his/her home computer
|
||||
* @param p - Player object
|
||||
* @param {IPlayer} p - Player object
|
||||
*/
|
||||
export function createUpgradeHomeRamPopup(p: IPlayer) {
|
||||
const cost: number = p.getUpgradeHomeRamCost();
|
||||
@@ -250,25 +266,31 @@ export function createUpgradeHomeRamPopup(p: IPlayer) {
|
||||
yesNoBoxClose();
|
||||
});
|
||||
|
||||
yesNoBoxCreate("Would you like to purchase additional RAM for your home computer? <br><br>" +
|
||||
"This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB. <br><br>" +
|
||||
"This will cost " + numeralWrapper.format(cost, '$0.000a'));
|
||||
yesNoBoxCreate(
|
||||
"Would you like to purchase additional RAM for your home computer? <br><br>" +
|
||||
"This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB. <br><br>" +
|
||||
"This will cost " + numeralWrapper.format(cost, '$0.000a')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to purchase a TOR router
|
||||
* @param p - Player object
|
||||
* @param {IPlayer} p - Player object
|
||||
*/
|
||||
export function purchaseTorRouter(p: IPlayer) {
|
||||
if (p.hasTorRouter()) {
|
||||
dialogBoxCreate(`You already have a TOR Router`);
|
||||
return;
|
||||
}
|
||||
if (!p.canAfford(CONSTANTS.TorRouterCost)) {
|
||||
dialogBoxCreate("You cannot afford to purchase the Tor router");
|
||||
return;
|
||||
}
|
||||
p.loseMoney(CONSTANTS.TorRouterCost);
|
||||
|
||||
const darkweb = new Server({
|
||||
ip: createRandomIp(), hostname:"darkweb", organizationName:"",
|
||||
const darkweb = safetlyCreateUniqueServer({
|
||||
ip: createUniqueRandomIp(), hostname:"darkweb", organizationName:"",
|
||||
isConnectedTo:false, adminRights:false, purchasedByPlayer:false, maxRam:1
|
||||
});
|
||||
AddToAllServers(darkweb);
|
||||
@@ -276,7 +298,9 @@ export function purchaseTorRouter(p: IPlayer) {
|
||||
|
||||
p.getHomeComputer().serversOnNetwork.push(darkweb.ip);
|
||||
darkweb.serversOnNetwork.push(p.getHomeComputer().ip);
|
||||
dialogBoxCreate("You have purchased a Tor router!<br>" +
|
||||
"You now have access to the dark web from your home computer<br>" +
|
||||
"Use the scan/scan-analyze commands to search for the dark web connection.");
|
||||
dialogBoxCreate(
|
||||
"You have purchased a Tor router!<br>" +
|
||||
"You now have access to the dark web from your home computer<br>" +
|
||||
"Use the scan/scan-analyze commands to search for the dark web connection."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ export class CompanyLocation extends React.Component<IProps, IState> {
|
||||
<StdButton
|
||||
onClick={this.startInfiltration}
|
||||
style={this.btnStyle}
|
||||
text={"Infiltration Company"}
|
||||
text={"Infiltrate Company"}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user