mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-03-08 03:24:48 +01:00
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ Netburner.txt
|
||||
/dist/*.map
|
||||
/tests/*.map
|
||||
/tests/*.bundle.*
|
||||
/tests/*.css
|
||||
|
61
css/_mixins.scss
Normal file
61
css/_mixins.scss
Normal file
@ -0,0 +1,61 @@
|
||||
@mixin animation($property) {
|
||||
-webkit-animation: $property;
|
||||
-moz-animation: $property;
|
||||
-ms-animation: $property;
|
||||
-o-animation: $property;
|
||||
animation: $property;
|
||||
}
|
||||
|
||||
@mixin borderRadius($property) {
|
||||
-webkit-border-radius: $property;
|
||||
-moz-border-radius: $property;
|
||||
border-radius: $property;
|
||||
}
|
||||
|
||||
@mixin boxShadow($value) {
|
||||
-webkit-box-shadow: $value;
|
||||
-moz-box-shadow: $value;
|
||||
box-shadow: $value;
|
||||
}
|
||||
|
||||
@mixin keyframes($animationName) {
|
||||
@-webkit-keyframes #{$animationName} {
|
||||
$browser: '-webkit-' !global;
|
||||
@content;
|
||||
}
|
||||
|
||||
@-moz-keyframes #{$animationName} {
|
||||
$browser: '-moz-' !global;
|
||||
@content;
|
||||
}
|
||||
|
||||
@-ms-keyframes #{$animationName} {
|
||||
$browser: '-ms-' !global;
|
||||
@content;
|
||||
}
|
||||
|
||||
@-o-keyframes #{$animationName} {
|
||||
$browser: '-o-' !global;
|
||||
@content;
|
||||
}
|
||||
|
||||
@keyframes #{$animationName} {
|
||||
$browser: '' !global;
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin transform($property) {
|
||||
-webkit-transform: $property;
|
||||
-moz-transform: $property;
|
||||
-ms-transform: $property;
|
||||
-o-transform: $property;
|
||||
transform: $property;
|
||||
}
|
||||
|
||||
@mixin userSelect($value) {
|
||||
-webkit-user-select: $value;
|
||||
-moz-user-select: $value;
|
||||
-ms-user-select: $value;
|
||||
user-select: $value;
|
||||
}
|
15
css/_reset.scss
Normal file
15
css/_reset.scss
Normal file
@ -0,0 +1,15 @@
|
||||
@import "theme";
|
||||
|
||||
* {
|
||||
font-size: $defaultFontSize;
|
||||
font-family: $fontFamily;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
}
|
2
css/_theme.scss
Normal file
2
css/_theme.scss
Normal file
@ -0,0 +1,2 @@
|
||||
$fontFamily: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman';
|
||||
$defaultFontSize: 16px;
|
@ -1,9 +1,13 @@
|
||||
#bladeburner-container p,
|
||||
#bladeburner-container pre,
|
||||
#bladeburner-container a,
|
||||
#bladeburner-container div,
|
||||
#bladeburner-container td {
|
||||
font-size: 13px;
|
||||
@import "theme";
|
||||
|
||||
#bladeburner-container {
|
||||
a,
|
||||
div,
|
||||
p,
|
||||
pre,
|
||||
td {
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
}
|
||||
}
|
||||
|
||||
.bladeburner-action {
|
||||
@ -11,10 +15,10 @@
|
||||
margin: 7px;
|
||||
padding: 7px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.bladeburner-action pre {
|
||||
white-space: pre-wrap;
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* Whatever action is currently active */
|
||||
@ -23,21 +27,25 @@
|
||||
}
|
||||
|
||||
/* Action & Skills panel navigation button */
|
||||
.bladeburner-nav-button {
|
||||
%bladburner-nav-button {
|
||||
border: 1px solid #fff;
|
||||
color: #fff;
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.bladeburner-nav-button:hover {
|
||||
background-color: #3d4044;
|
||||
.bladeburner-nav-button {
|
||||
@extend %bladburner-nav-button;
|
||||
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: #3d4044;
|
||||
}
|
||||
}
|
||||
|
||||
.bladeburner-nav-button-inactive {
|
||||
border: 1px solid #fff;
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
@extend %bladburner-nav-button;
|
||||
|
||||
text-decoration: none;
|
||||
background-color: #555;
|
||||
cursor: default;
|
||||
@ -76,7 +84,7 @@
|
||||
margin: 0 !important;
|
||||
border: 0;
|
||||
background-color: var(--my-background-color);
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
outline: none;
|
||||
color: var(--my-font-color);
|
||||
flex: 1 1 auto;
|
@ -1,7 +1,10 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
#cmpy-mgmt-container p,
|
||||
#cmpy-mgmt-container a,
|
||||
#cmpy-mgmt-container div {
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
}
|
||||
|
||||
/* Header tabs */
|
||||
@ -118,10 +121,14 @@
|
||||
margin: 2px;
|
||||
padding: 6px;
|
||||
border-radius: 25px;
|
||||
font-size: "12px";
|
||||
font-size: $defaultFontSize * 0.75;
|
||||
color: var(--my-font-color);
|
||||
}
|
||||
|
||||
.cmpy-mgmt-upgrade-div:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.cmpy-mgmt-advertising-info {
|
||||
font-size: $defaultFontSize * 0.75;
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
/* interactivetutorial.css */
|
||||
#interactive-tutorial-wrapper {
|
||||
position: relative;
|
||||
@ -15,10 +18,10 @@
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
background-color: #444; /* Fallback color */
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#interactive-tutorial-container > strong {
|
||||
background-color: #444;
|
||||
> strong {
|
||||
background-color: #444;
|
||||
}
|
||||
}
|
||||
|
||||
#interactive-tutorial-text {
|
||||
@ -31,16 +34,20 @@
|
||||
#interactive-tutorial-exit,
|
||||
#interactive-tutorial-next,
|
||||
#interactive-tutorial-back {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
|
||||
color: #aaa;
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
background-color: #000;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#interactive-tutorial-exit {
|
||||
@ -55,14 +62,3 @@
|
||||
#interactive-tutorial-next {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#interactive-tutorial-exit:hover,
|
||||
#interactive-tutorial-exit:focus,
|
||||
#interactive-tutorial-next:hover,
|
||||
#interactive-tutorial-next:focus,
|
||||
#interactive-tutorial-back:hover,
|
||||
#interactive-tutorial-back:focus {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
148
css/loader.css
148
css/loader.css
@ -1,148 +0,0 @@
|
||||
@-webkit-keyframes LOADERSPINNER {
|
||||
0% { -webkit-transform: translate(-50%, -50%) rotate(0deg); }
|
||||
100% { -webkit-transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
@-moz-keyframes LOADERSPINNER {
|
||||
0% { -moz-transform: translate(-50%, -50%) rotate(0deg); }
|
||||
100% { -moz-transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
@-ms-keyframes LOADERSPINNER {
|
||||
0% { -ms-transform: translate(-50%, -50%) rotate(0deg); }
|
||||
100% { -ms-transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
@-o-keyframes LOADERSPINNER {
|
||||
0% { -o-transform: translate(-50%, -50%) rotate(0deg); }
|
||||
100% { -o-transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
@keyframes LOADERSPINNER {
|
||||
0% { transform: translate(-50%, -50%) rotate(0deg); }
|
||||
100% { transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
|
||||
@-webkit-keyframes LOADERLABEL {
|
||||
0% { opacity: 1.0; -webkit-transform: translate(-50%, -50%) scale(1.0); }
|
||||
5% { opacity: 0.5; -webkit-transform: translate(-50%, -50%) scale(0.5); }
|
||||
95% { opacity: 0.5; -webkit-transform: translate(-50%, -50%) scale(0.5); }
|
||||
100% { opacity: 1.0; -webkit-transform: translate(-50%, -50%) scale(1.0); }
|
||||
}
|
||||
@-moz-keyframes LOADERLABEL {
|
||||
0% { opacity: 1.0; -moz-transform: translate(-50%, -50%) scale(1.0); }
|
||||
5% { opacity: 0.5; -moz-transform: translate(-50%, -50%) scale(0.5); }
|
||||
95% { opacity: 0.5; -moz-transform: translate(-50%, -50%) scale(0.5); }
|
||||
100% { opacity: 1.0; -moz-transform: translate(-50%, -50%) scale(1.0); }
|
||||
}
|
||||
@-ms-keyframes LOADERLABEL {
|
||||
0% { opacity: 1.0; -ms-transform: translate(-50%, -50%) scale(1.0); }
|
||||
5% { opacity: 0.5; -ms-transform: translate(-50%, -50%) scale(0.5); }
|
||||
95% { opacity: 0.5; -ms-transform: translate(-50%, -50%) scale(0.5); }
|
||||
100% { opacity: 1.0; -ms-transform: translate(-50%, -50%) scale(1.0); }
|
||||
}
|
||||
@-o-keyframes LOADERLABEL {
|
||||
0% { opacity: 1.0; -o-transform: translate(-50%, -50%) scale(1.0); }
|
||||
5% { opacity: 0.5; -o-transform: translate(-50%, -50%) scale(0.5); }
|
||||
95% { opacity: 0.5; -o-transform: translate(-50%, -50%) scale(0.5); }
|
||||
100% { opacity: 1.0; -o-transform: translate(-50%, -50%) scale(1.0); }
|
||||
}
|
||||
@keyframes LOADERLABEL {
|
||||
0% { opacity: 1.0; transform: translate(-50%, -50%) scale(1.0); }
|
||||
5% { opacity: 0.5; transform: translate(-50%, -50%) scale(0.5); }
|
||||
95% { opacity: 0.5; transform: translate(-50%, -50%) scale(0.5); }
|
||||
100% { opacity: 1.0; transform: translate(-50%, -50%) scale(1.0); }
|
||||
}
|
||||
|
||||
*, *:before, *:after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
}
|
||||
.loaderoverlay {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 1.0);
|
||||
}
|
||||
.loaderoverlay .loaderspinner,
|
||||
.loaderoverlay .loaderspinner:before,
|
||||
.loaderoverlay .loaderspinner:after {
|
||||
border: 20px solid rgba(0, 0, 0, 0);
|
||||
border-top: 20px solid #ccc;
|
||||
border-bottom: 20px solid #ccc;
|
||||
border-radius: 1000px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
.loaderoverlay .loaderspinner:before,
|
||||
.loaderoverlay .loaderspinner:after {
|
||||
content: "";
|
||||
}
|
||||
.loaderoverlay .loaderspinner {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
-webkit-animation: LOADERSPINNER 5s linear infinite;
|
||||
-moz-animation: LOADERSPINNER 5s linear infinite;
|
||||
-ms-animation: LOADERSPINNER 5s linear infinite;
|
||||
-o-animation: LOADERSPINNER 5s linear infinite;
|
||||
animation: LOADERSPINNER 5s linear infinite;
|
||||
}
|
||||
.loaderoverlay .loaderspinner:before {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
-webkit-animation: LOADERSPINNER 10s linear infinite;
|
||||
-moz-animation: LOADERSPINNER 10s linear infinite;
|
||||
-ms-animation: LOADERSPINNER 10s linear infinite;
|
||||
-o-animation: LOADERSPINNER 10s linear infinite;
|
||||
animation: LOADERSPINNER 10s linear infinite;
|
||||
}
|
||||
.loaderoverlay .loaderspinner:after {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
-webkit-animation: LOADERSPINNER 5s linear infinite;
|
||||
-moz-animation: LOADERSPINNER 5s linear infinite;
|
||||
-ms-animation: LOADERSPINNER 5s linear infinite;
|
||||
-o-animation: LOADERSPINNER 5s linear infinite;
|
||||
animation: LOADERSPINNER 5s linear infinite;
|
||||
}
|
||||
.loaderoverlay .loaderlabel {
|
||||
color: #6f3;
|
||||
text-transform: uppercase;
|
||||
font-family: sans-serif;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-animation: LOADERLABEL 5s linear infinite;
|
||||
-moz-animation: LOADERLABEL 5s linear infinite;
|
||||
-ms-animation: LOADERLABEL 5s linear infinite;
|
||||
-o-animation: LOADERLABEL 5s linear infinite;
|
||||
animation: LOADERLABEL 5s linear infinite;
|
||||
}
|
||||
button[type="button"] {
|
||||
padding: 0.5rem 1rem;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
-webkit-transform: translateX(-50%);
|
||||
-moz-transform: translateX(-50%);
|
||||
-ms-transform: translateX(-50%);
|
||||
-o-transform: translateX(-50%);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
/* Customize */
|
||||
.loaderoverlay {
|
||||
background: #000;
|
||||
}
|
||||
.loaderoverlay .loaderspinner,
|
||||
.loaderoverlay .loaderspinner:before,
|
||||
.loaderoverlay .loaderspinner:after {
|
||||
border-top-color: #6f3 !important;
|
||||
border-bottom-color: #6f3 !important;
|
||||
}
|
||||
.loaderoverlay .loaderlabel {
|
||||
color: #6f3;
|
||||
}
|
94
css/loader.scss
Normal file
94
css/loader.scss
Normal file
@ -0,0 +1,94 @@
|
||||
@import "mixins";
|
||||
@import "reset";
|
||||
@import "theme";
|
||||
|
||||
@include keyframes(LOADERSPINNER) {
|
||||
0% {
|
||||
#{$browser}transform: translate(-50%, -50%) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
#{$browser}transform: translate(-50%, -50%) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@include keyframes(LOADERLABEL) {
|
||||
0% {
|
||||
opacity: 1.0;
|
||||
#{$browser}transform: translate(-50%, -50%) scale(1.0);
|
||||
}
|
||||
5% {
|
||||
opacity: 0.5;
|
||||
#{$browser}transform: translate(-50%, -50%) scale(0.5);
|
||||
}
|
||||
95% {
|
||||
opacity: 0.5;
|
||||
#{$browser}transform: translate(-50%, -50%) scale(0.5);
|
||||
}
|
||||
100% {
|
||||
opacity: 1.0;
|
||||
#{$browser}transform: translate(-50%, -50%) scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.loaderoverlay {
|
||||
$spinnerBoxSize: 200px;
|
||||
$themeColor: #6f3;
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
color: $themeColor;
|
||||
|
||||
%spinnerBox {
|
||||
border: 20px solid rgba(0, 0, 0, 0);
|
||||
border-top-color: $themeColor;
|
||||
border-bottom-color: $themeColor;
|
||||
border-radius: 1000px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.loaderspinner:before,
|
||||
.loaderspinner:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.loaderspinner {
|
||||
@extend %spinnerBox;
|
||||
@include animation(LOADERSPINNER 5s linear infinite);
|
||||
|
||||
width: $spinnerBoxSize;
|
||||
height: $spinnerBoxSize;
|
||||
}
|
||||
|
||||
.loaderspinner:before {
|
||||
@extend %spinnerBox;
|
||||
@include animation(LOADERSPINNER 10s linear infinite);
|
||||
|
||||
width: $spinnerBoxSize * 0.8;
|
||||
height: $spinnerBoxSize * 0.8;
|
||||
}
|
||||
|
||||
.loaderspinner:after {
|
||||
@extend %spinnerBox;
|
||||
@include animation(LOADERSPINNER 5s linear infinite);
|
||||
|
||||
width: $spinnerBoxSize * 0.6;
|
||||
height: $spinnerBoxSize * 0.6;
|
||||
}
|
||||
|
||||
.loaderlabel {
|
||||
@include animation(LOADERLABEL 5s linear infinite);
|
||||
|
||||
text-transform: uppercase;
|
||||
font-family: sans-serif;
|
||||
font-size: $defaultFontSize * 1.375;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
||||
terminal which has its own page) */
|
||||
|
||||
@ -32,7 +35,7 @@
|
||||
|
||||
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-family: $fontFamily;
|
||||
}
|
||||
|
||||
.ace_line,
|
||||
@ -43,7 +46,7 @@
|
||||
}
|
||||
|
||||
.ace_text-input {
|
||||
font-size: 16px;
|
||||
font-size: $defaultFontSize;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@ -89,6 +92,9 @@
|
||||
}
|
||||
|
||||
#script-editor-filename {
|
||||
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
|
||||
@include boxShadow($boxShadowArgs);
|
||||
|
||||
background-color: #555;
|
||||
display: inline-block;
|
||||
float: center;
|
||||
@ -99,15 +105,6 @@
|
||||
padding: 2px;
|
||||
|
||||
border: 2px solid var(--my-highlight-color);
|
||||
-webkit-box-shadow:
|
||||
inset 0 0 8px rgba(0, 0, 0, 0.1),
|
||||
0 0 16px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow:
|
||||
inset 0 0 8px rgba(0, 0, 0, 0.1),
|
||||
0 0 16px rgba(0, 0, 0, 0.1);
|
||||
box-shadow:
|
||||
inset 0 0 8px rgba(0, 0, 0, 0.1),
|
||||
0 0 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#script-editor-status {
|
||||
@ -132,7 +129,7 @@
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 2px;
|
||||
font-size: 12px;
|
||||
font-size: $defaultFontSize * 0.75;
|
||||
}
|
||||
|
||||
/* Active scripts */
|
||||
@ -154,7 +151,7 @@
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
@ -176,7 +173,7 @@
|
||||
|
||||
.active-scripts-server-header:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
@ -184,7 +181,7 @@
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
@ -227,7 +224,7 @@
|
||||
|
||||
.active-scripts-script-header:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: var(--my-font-color);
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
@ -235,7 +232,7 @@
|
||||
|
||||
.active-scripts-script-header.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: var(--my-font-color);
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
@ -260,15 +257,12 @@
|
||||
}
|
||||
|
||||
.active-scripts-button {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
|
||||
color: #aaa;
|
||||
font-size: 16px;
|
||||
font-size: $defaultFontSize;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
background-color: #000;
|
||||
@ -323,19 +317,13 @@
|
||||
}
|
||||
|
||||
.hacknet-node {
|
||||
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
|
||||
@include boxShadow($boxShadowArgs);
|
||||
|
||||
margin: 6px;
|
||||
padding: 6px;
|
||||
width: 34vw;
|
||||
border: 2px solid var(--my-highlight-color);
|
||||
-webkit-box-shadow:
|
||||
inset 0 0 8px rgba(0, 0, 0, 0.1),
|
||||
0 0 16px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow:
|
||||
inset 0 0 8px rgba(0, 0, 0, 0.1),
|
||||
0 0 16px rgba(0, 0, 0, 0.1);
|
||||
box-shadow:
|
||||
inset 0 0 8px rgba(0, 0, 0, 0.1),
|
||||
0 0 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.hacknet-node-container {
|
||||
@ -355,7 +343,7 @@
|
||||
display: inline-block;
|
||||
margin: 0 4px; /* Don't want the vertical margin/padding, just left & right */
|
||||
padding: 0 4px;
|
||||
width: 48px; /* Four times font-size */
|
||||
width: $defaultFontSize * 4;
|
||||
}
|
||||
|
||||
.menu-page-text {
|
@ -1,3 +1,6 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
/* css for Missions */
|
||||
|
||||
/* Hacking missions */
|
||||
@ -15,10 +18,10 @@
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.hack-mission-grid::-webkit-scrollbar {
|
||||
display: none;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.hack-mission-node {
|
||||
@ -27,17 +30,15 @@
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.hack-mission-node p {
|
||||
margin-top: 8px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
p {
|
||||
@include userSelect(none);
|
||||
|
||||
margin-top: 8px;
|
||||
color: #fff;
|
||||
font-size: $defaultFontSize * 0.75;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.hack-mission-player-node {
|
||||
@ -56,11 +57,9 @@
|
||||
}
|
||||
|
||||
.hack-mission-cpu-node {
|
||||
@include borderRadius(50%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-moz-border-radius: 50%;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.hack-mission-firewall-node {
|
||||
@ -69,47 +68,37 @@
|
||||
}
|
||||
|
||||
.hack-mission-database-node {
|
||||
@include transform(skew(20deg));
|
||||
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
-webkit-transform: skew(20deg);
|
||||
-moz-transform: skew(20deg);
|
||||
-o-transform: skew(20deg);
|
||||
}
|
||||
|
||||
.hack-mission-database-node p {
|
||||
-webkit-transform: skew(-20deg);
|
||||
-moz-transform: skew(-20deg);
|
||||
-o-transform: skew(-20deg);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
p {
|
||||
@include transform(skew(-20deg));
|
||||
@include userSelect(none);
|
||||
|
||||
color: #fff;
|
||||
font-size: $defaultFontSize * 0.75;
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.hack-mission-transfer-node {
|
||||
@include transform(skew(-20deg));
|
||||
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
-webkit-transform: skew(-20deg);
|
||||
-moz-transform: skew(-20deg);
|
||||
-o-transform: skew(-20deg);
|
||||
}
|
||||
|
||||
.hack-mission-transfer-node p {
|
||||
-webkit-transform: skew(20deg);
|
||||
-moz-transform: skew(20deg);
|
||||
-o-transform: skew(20deg);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
p {
|
||||
@include transform(skew(20deg));
|
||||
@include userSelect(none);
|
||||
|
||||
color: #fff;
|
||||
font-size: $defaultFontSize * 0.75;
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.hack-mission-spam-node,
|
@ -1,3 +1,6 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
/* Pop-up boxes */
|
||||
.popup-box-container {
|
||||
display: none; /* Hidden by default */
|
||||
@ -24,7 +27,7 @@
|
||||
.popup-box-button-inactive {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
font-size: 16px;
|
||||
font-size: $defaultFontSize;
|
||||
font-weight: bold;
|
||||
padding: 2px;
|
||||
margin: 6px;
|
||||
@ -74,16 +77,13 @@
|
||||
}
|
||||
|
||||
.dialog-box-close-button {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
|
||||
float: right;
|
||||
color: #aaa;
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
}
|
||||
|
||||
#log-box-close {
|
||||
@ -155,18 +155,15 @@
|
||||
}
|
||||
|
||||
#game-options-close-button {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
|
||||
color: #aaa;
|
||||
float: right;
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px #fff;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
}
|
||||
|
||||
#game-options-close-button:hover,
|
@ -1,16 +1,14 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
@import "reset";
|
||||
|
||||
:root{
|
||||
--my-font-color: #6f3;
|
||||
--my-background-color: #000;
|
||||
--my-highlight-color: #fff;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
font-family: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman';
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--my-background-color);
|
||||
}
|
||||
@ -23,7 +21,7 @@ h2,
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
font-size: $defaultFontSize * 1.375;
|
||||
color: var(--my-font-color);
|
||||
}
|
||||
|
||||
@ -41,6 +39,16 @@ span {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
button[type="button"] {
|
||||
@include transform(translateX(-50%));
|
||||
|
||||
padding: 0.5rem 1rem;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
#entire-game-container {
|
||||
background-color: transparent;
|
||||
}
|
||||
@ -100,7 +108,7 @@ tr:focus {
|
||||
/* Plus and minus signs */
|
||||
.mainmenu-accordion-header:after {
|
||||
content: '\02795';
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
@ -127,7 +135,8 @@ tr:focus {
|
||||
}
|
||||
|
||||
/* Make html links ("a" elements) nice looking buttons with this class */
|
||||
a:link, a:visited {
|
||||
a:link,
|
||||
a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@ -150,9 +159,7 @@ a:link, a:visited {
|
||||
}
|
||||
|
||||
.a-link-button:active {
|
||||
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
|
||||
}
|
||||
|
||||
/* Make anchor tags ("a" elements) inactive (not clickable) */
|
||||
@ -212,7 +219,7 @@ a:link, a:visited {
|
||||
position: relative;
|
||||
}
|
||||
#create-program-notification {
|
||||
font-size: 10px;
|
||||
font-size: $defaultFontSize * 0.625;
|
||||
|
||||
position: absolute; /* Position the badge within the relatively positioned button */
|
||||
top: 0;
|
||||
@ -308,9 +315,7 @@ a:link, a:visited {
|
||||
}
|
||||
|
||||
.help-tip:active {
|
||||
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
|
||||
}
|
||||
|
||||
/* Flashing button (Red) */
|
||||
@ -408,7 +413,7 @@ a:link, a:visited {
|
||||
}
|
||||
|
||||
#status-text {
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
@ -446,15 +451,12 @@ a:link, a:visited {
|
||||
|
||||
#character-overview-save-button,
|
||||
#character-overview-options-button {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
|
||||
color: #aaa;
|
||||
font-size: 14px;
|
||||
font-size: $defaultFontSize * 0.875;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
height: 22px;
|
||||
background-color: #000;
|
||||
}
|
||||
@ -485,7 +487,7 @@ a:link, a:visited {
|
||||
/* Accordion menus (Header with collapsible panel) */
|
||||
.accordion-header {
|
||||
background-color: #444;
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
@ -507,7 +509,7 @@ a:link, a:visited {
|
||||
|
||||
.accordion-header:after {
|
||||
content: '\02795'; /* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
@ -515,7 +517,7 @@ a:link, a:visited {
|
||||
|
||||
.accordion-header.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: 13px;
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
@ -1,3 +1,5 @@
|
||||
@import "theme";
|
||||
|
||||
#terminal-container {
|
||||
position: fixed;
|
||||
margin-left: 10%;
|
||||
@ -12,7 +14,7 @@
|
||||
padding-left: 10px;
|
||||
height: auto;
|
||||
width: 70%;
|
||||
font-size: 16px;
|
||||
font-size: $defaultFontSize;
|
||||
overflow: auto;
|
||||
overflow-y: scroll;
|
||||
background-color: var(--my-background-color);
|
||||
@ -31,7 +33,7 @@
|
||||
margin: 0 !important;
|
||||
border: 0;
|
||||
background-color: var(--my-background-color);
|
||||
font-size: 16px;
|
||||
font-size: $defaultFontSize;
|
||||
outline: none;
|
||||
color: var(--my-font-color);
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
@import "mixins";
|
||||
@import "theme";
|
||||
|
||||
/* Both Work in progress and BitNode stuff */
|
||||
.generic-fullscreen-container {
|
||||
color: var(--my-font-color);
|
||||
@ -16,19 +19,16 @@
|
||||
}
|
||||
|
||||
#work-in-progress-cancel-button {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
|
||||
color: #aaa;
|
||||
float: left;
|
||||
font-size: 20px;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
font-weight: bold;
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
border-radius: 12px;
|
||||
border: 3px solid #fff;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
}
|
||||
|
||||
#work-in-progress-cancel-button:hover,
|
2
dist/engine.bundle.js
vendored
2
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
1857
dist/engine.css
vendored
Normal file
1857
dist/engine.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,33 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.40.0 - 7/28/2018
|
||||
-------------------
|
||||
* **WARNING: This update makes some significant changes to Netscript and therefore you may need to make some changes to your scripts. See** `this post <https://www.reddit.com/r/Bitburner/comments/9252j4/psa_netscript_10_changes_in_next_version_v0400/>`_ **this post for details**
|
||||
* Netscript 1.0 (NS1) now uses a fully-fledged ES5 JavaScript Interpreter. This means many new features are now available in NS1, and this also fixes several bugs.
|
||||
However this also means any ES6+ features are no longer supported in NS1
|
||||
* When a server is hacked with a very large number of threads and left with no money, the server's security level
|
||||
now only increases by however many threads were needed to drain the server. For example, if you hack a server with
|
||||
5000 threads but it only needed 2000 threads to deplete the server's money, then the server's security will only increase
|
||||
as if you had hacked it with 2000 threads (change by hydroflame)
|
||||
* Added getCurrentAction() to Bladeburner API
|
||||
* Added a variety of functions to Bladeburner API that deal with action levels (change by hydroflame)
|
||||
* Added getPurchasedServerLimit() and getPurchasedServerMaxRam() functions to Netscript (change by hydroflame & kopelli)
|
||||
* Added getOwnedSourceFiles() Singularity function (by hydroflame)
|
||||
* Completely re-designed the Hacknet Node API
|
||||
* getSkillLevel() in Bladeburner API now returns an error if no argument is passed in (as opposed to an object with all skill levels). This may break scripts
|
||||
* Minimum Netscript execution time reduced from 15ms to 10ms (configurable in Options)
|
||||
* Company reputation needed to get invited to Megacorporation factions decreased from 250k to 200k
|
||||
* HP is now reset (restored) when Augmenting
|
||||
* Source-File 6 now increases both the level and experience gain of all combat stats (it was only experience gain previously)
|
||||
* Reverted a previous change for Source-File 12. It's benefits are now multiplicative rather than additive
|
||||
* Starting Infiltration security level for almost every location decreased by ~10%
|
||||
* Changed 'fl1ght.exe' message when its listed conditions are fulfilled (by hydroflame)
|
||||
* The 'Save Game' button in the top-right overview panel now flashes red if autosave is disabled
|
||||
* Bug Fix: Infiltration buttons can no longer be clicked through NetscriptJS
|
||||
* Bug Fix: Bladeburner 'Overclock' skill can no longer be leveled above max level through the API (by hydroflame)
|
||||
* Bug Fix: Healthcare division in Bladeburner should no longer cause game to crash
|
||||
|
||||
v0.39.1 - 7/4/2018
|
||||
------------------
|
||||
|
||||
|
@ -14,10 +14,9 @@ to reach out to the developer!
|
||||
:maxdepth: 5
|
||||
:caption: Sections:
|
||||
|
||||
Learn to Program <netscriptlearntoprogram>
|
||||
Netscript 1.0 <netscript1>
|
||||
NetscriptJS (Netscript 2.0) <netscriptjs>
|
||||
Data Types and Variables <netscriptdatatypes>
|
||||
Operators <netscriptoperators>
|
||||
Loops and Conditionals <netscriptloopsandconditionals>
|
||||
Script Arguments <netscriptscriptarguments>
|
||||
Basic Functions <netscriptfunctions>
|
||||
Advanced Functions <netscriptadvancedfunctions>
|
||||
|
32
doc/source/netscript1.rst
Normal file
32
doc/source/netscript1.rst
Normal file
@ -0,0 +1,32 @@
|
||||
.. _netscript1:
|
||||
|
||||
Netscript 1.0
|
||||
=============
|
||||
Netscript 1.0 is implemented using modified version of Neil Fraser's
|
||||
`JS-Interpreter <https://github.com/NeilFraser/JS-Interpreter>`_.
|
||||
|
||||
This interpreter was created for ES5, which means that the code written
|
||||
for Netscript 1.0 must be compliant for that version. However, some additional
|
||||
ES6+ features are implemented through polyfills.
|
||||
|
||||
Netscript 1.0 scripts end with the ".script" extension.
|
||||
|
||||
Which ES6+ features are supported?
|
||||
----------------------------------
|
||||
|
||||
Netscript 1.0 is a ES5 interpreter, but the following features from versions ES6 and
|
||||
above are supported as well.
|
||||
|
||||
If there is an additional ES6+ feature you would like to see implemented with a polyfill,
|
||||
feel free to `open an issue <https://github.com/danielyxie/bitburner/issues>`_ (and provide
|
||||
the polyfill if possible).
|
||||
|
||||
* import - See :ref:`netscriptimporting`
|
||||
* `Array <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array>`_
|
||||
* `find() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find>`_
|
||||
* `findIndex() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex>`_
|
||||
* `includes() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes>`_
|
||||
* `String <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String>`_
|
||||
* `endsWith() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith>`_
|
||||
* `includes() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes>`_
|
||||
* `startsWith() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith>`_
|
@ -166,7 +166,9 @@ getActionMaxLevel
|
||||
:param string type: Type of action. See :ref:`bladeburner_action_types`
|
||||
:param string name: Name of action. Must be an exact match
|
||||
|
||||
Return the maximum level for this action.
|
||||
Returns the maximum level for this action.
|
||||
|
||||
Returns -1 if an invalid action is specified.
|
||||
|
||||
getActionCurrentLevel
|
||||
---------------------
|
||||
@ -176,7 +178,9 @@ getActionCurrentLevel
|
||||
:param string type: Type of action. See :ref:`bladeburner_action_types`
|
||||
:param string name: Name of action. Must be an exact match
|
||||
|
||||
Return the current level of this action.
|
||||
Returns the current level of this action.
|
||||
|
||||
Returns -1 if an invalid action is specified.
|
||||
|
||||
getActionAutolevel
|
||||
------------------
|
||||
@ -186,7 +190,9 @@ getActionAutolevel
|
||||
:param string type: Type of action. See :ref:`bladeburner_action_types`
|
||||
:param string name: Name of action. Must be an exact match
|
||||
|
||||
Return wether of not this action is currently autoleveling.
|
||||
Return a boolean indicating whether or not this action is currently set to autolevel.
|
||||
|
||||
Returns false if an invalid action is specified.
|
||||
|
||||
setActionAutolevel
|
||||
------------------
|
||||
@ -195,7 +201,9 @@ setActionAutolevel
|
||||
|
||||
:param string type: Type of action. See :ref:`bladeburner_action_types`
|
||||
:param string name: Name of action. Must be an exact match
|
||||
:param boolean autoLevel: wether or not to autolevel this action
|
||||
:param boolean autoLevel: Whether or not to autolevel this action
|
||||
|
||||
Enable/disable autoleveling for the specified action.
|
||||
|
||||
setActionLevel
|
||||
--------------
|
||||
@ -204,7 +212,9 @@ setActionLevel
|
||||
|
||||
:param string type: Type of action. See :ref:`bladeburner_action_types`
|
||||
:param string name: Name of action. Must be an exact match
|
||||
:param level int: the level to set this action to
|
||||
:param level int: Level to set this action to
|
||||
|
||||
Set the level for the specified action.
|
||||
|
||||
getRank
|
||||
-------
|
||||
|
@ -1,44 +0,0 @@
|
||||
Netscript Data Types and Variables
|
||||
==================================
|
||||
|
||||
|
||||
Data Types
|
||||
----------
|
||||
Netscript supports three primitive data types:
|
||||
|
||||
**Numbers** - Positive numerics, such as integers and floats. Examples: 6, 0, 10.5
|
||||
|
||||
**Strings** - A sequence of characters that represents text. The characters must be encapsulated by single or
|
||||
double quotes. Example: "This is a string" or equivalently 'This is a string'.
|
||||
*Strings are fully functional* `Javascript strings <https://www.w3schools.com/jsref/jsref_obj_string.asp>`_,
|
||||
*which means that all of the member functions of Javascript strings such as toLowerCase() and includes() are also available in Netscript!*
|
||||
|
||||
**Boolean** - true or false
|
||||
|
||||
**Array** - An array is a special container object that is capable of holding many different values. Arrays are simply Javascript
|
||||
arrays, and most Javascript array methods can be used in Netscript as well (join(), pop(), splice(), etc.). You can read more about
|
||||
`Javascript arrays here <https://www.w3schools.com/js/js_arrays.asp>`_
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variables can be thought of as named containers. Their purpose is to label and store data. The data stored in the
|
||||
variable can then be accessed and changed by referring to the variable's name. The name of a variable must start with
|
||||
either a letter or an underscore. The rest of the variable name can contain any alphanumeric (letters and numbers),
|
||||
as well as hyphens and underscores.
|
||||
|
||||
The Netscript language is untyped, meaning that any variable can hold any of the data types above. The value type of a variable
|
||||
can also change. For example, if a variable initially holds a number, it can later hold a string.
|
||||
|
||||
The following shows how you can declare and initialize variables::
|
||||
|
||||
i = 1;
|
||||
s = "This is a string";
|
||||
b = false;
|
||||
|
||||
After declaring a variable, the values in variables can be used simply by referencing the name. For example::
|
||||
|
||||
j = i + 5;
|
||||
s2 = s + " Adding more letters onto the string"
|
||||
|
||||
The first command above will store the value 6 in the variable j. The second command will store the string "This is a string Adding more letters onto the string" into the variable s2.
|
@ -670,6 +670,21 @@ purchaseHacknetNode
|
||||
end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford
|
||||
to purchase a new Hacknet Node then the function will return false.
|
||||
|
||||
getPurchasedServerCost
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. js:function:: getPurchasedServerCost(ram)
|
||||
|
||||
:param number ram: Amount of RAM of a potential purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20)
|
||||
|
||||
Returns the cost to purchase a server with the specified amount of *ram*.
|
||||
|
||||
Examples::
|
||||
|
||||
for (i = 1; i <= 20; i++) {
|
||||
tprint(i + " -- " + getPurchasedServerCost(Math.pow(2, i)));
|
||||
}
|
||||
|
||||
purchaseServer
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -8,7 +8,7 @@ still being able to access the Netscript functions.
|
||||
|
||||
NetscriptJS was developed primarily by `Github user jaguilar <https://github.com/jaguilar>`_
|
||||
|
||||
On top of having almost all of the features and capabilities of Javascript, NetscriptJS is also
|
||||
On top of having almost all of the features and capabilities of JavaScript, NetscriptJS is also
|
||||
significantly faster than Netscript 1.0.
|
||||
|
||||
This documentation will not go over any of the additional features of NetscriptJS, since
|
||||
|
70
doc/source/netscriptlearntoprogram.rst
Normal file
70
doc/source/netscriptlearntoprogram.rst
Normal file
@ -0,0 +1,70 @@
|
||||
.. _netscriptlearntoprogram:
|
||||
|
||||
Learn to Program in Netscript
|
||||
=============================
|
||||
Netscript is simply a subset of
|
||||
`JavaScript <https://developer.mozilla.org/en-US/docs/Web/JavaScript>`_,
|
||||
with some additional functions added in to allow interaction with the game.
|
||||
|
||||
For Beginner Programmers
|
||||
------------------------
|
||||
If you have little to no programming experience, that's okay! You don't need to be
|
||||
a great programmer in order to enjoy or play this game. In fact, this game could
|
||||
help you learn some basic programming concepts.
|
||||
|
||||
Here are some good tutorials for learning programming/JavaScript as a beginner:
|
||||
|
||||
* `Learn-JS <http://www.learn-js.org/en/Welcome>`_
|
||||
* `Speaking JavaScript <http://speakingjs.com/es5/index.html>`_
|
||||
This is a bit on the longer side. You can skip all of the historical
|
||||
background stuff. Recommended chapters: 1, 7-18
|
||||
|
||||
For Experienced Programmers
|
||||
---------------------------
|
||||
The following section lists several good tutorials/resources for those who have experience
|
||||
programming but who have not worked extensively with JavaScript before.
|
||||
|
||||
Before that, however, it's important to clarify some terminology about the different
|
||||
versions of JavaScript. These are summarized in this article:
|
||||
|
||||
`WTF is ES6, ES8, ES2017, ECMAScript... <https://codeburst.io/javascript-wtf-is-es6-es8-es-2017-ecmascript-dca859e4821c>`_
|
||||
|
||||
An important takeaway from this article is that ES6, also known as ES2015, introduced
|
||||
many major features that are commonly seen in modern JavaScript programming. However, this
|
||||
means that ES5 engines and interpreters will fail if they encounters these ES6 features. You'll see why this
|
||||
is important further down.
|
||||
|
||||
* `MDN Introduction to JS <https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript>`_
|
||||
* `Eloquent JavaScript (ES6+) <http://eloquentjavascript.net/>`_
|
||||
Recommended Chapters: Introduction, 1-6
|
||||
* `Modern Javascript Tutorial (ES6+) <https://javascript.info/>`_
|
||||
Recommended Chapters: 2, 4-6
|
||||
|
||||
Netscript 1.0 vs Netscript 2.0
|
||||
------------------------------
|
||||
There are two versions of Netscript:
|
||||
|
||||
* :doc:`netscript1`
|
||||
* :doc:`netscriptjs`
|
||||
|
||||
Visit the pages above to get more details about each version. If you are new
|
||||
to programming or unfamiliar with JavaScript, I would recommend starting out
|
||||
with :doc:`netscript1`. Experienced web developers can use :doc:`netscriptjs`
|
||||
to take advantage of faster speeds and additional features.
|
||||
|
||||
Here is a short summary of the differences between Netscript 1.0 and Netscript 2.0:
|
||||
|
||||
**Netscript 1.0**
|
||||
|
||||
* ES5
|
||||
* Some ES6 features implemented with polyfills
|
||||
* Slow compared to NetscriptJS (interpreter runs at the "Netscript Exec Time" speed configured in options)
|
||||
* Compatible with all browsers
|
||||
|
||||
**Netscript JS (Netscript 2.0)**
|
||||
|
||||
* Supports (almost) all features of modern JavaScript
|
||||
* Extremely fast - code is executed as an Async Function
|
||||
* Currently only works with Google Chrome browser
|
||||
* Each script becomes a module and therefore all instances of that script can easily
|
||||
share data between each other (essentially global/static variables)
|
@ -1,39 +0,0 @@
|
||||
Netscript Loops and Conditionals
|
||||
================================
|
||||
|
||||
|
||||
Netscript loops and conditionals are the same as Javascript. However, the one caveat is that when declaring variables such as the
|
||||
iterator for traversing a loop, you should not use the 'var' or 'let' keyword. For reference, you can see the Javascript
|
||||
documentation for loops/conditionals here:
|
||||
|
||||
`While loops <https://www.w3schools.com/js/js_loop_while.asp>`_
|
||||
|
||||
`For loops <https://www.w3schools.com/js/js_loop_for.asp>`_
|
||||
|
||||
`Conditionals (If/Else statements) <https://www.w3schools.com/js/js_if_else.asp>`_
|
||||
|
||||
Here are some simple code examples that show the use of loops and conditionals in Netscript.
|
||||
|
||||
The following is a while loop that runs the hack() Netscript function ten times::
|
||||
|
||||
i = 0;
|
||||
while (i < 10) {
|
||||
hack('foodnstuff');
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
The following is a for loop that runs the hack() Netscript function ten times::
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
hack("foodnstuff");
|
||||
}
|
||||
|
||||
The following is a conditional that uses the getServerMoneyAvailable() Netscript function to check how much money
|
||||
exists on the 'foodnstuff' server. If there is more than $200,000 on the server, then the server will be hacked.
|
||||
Otherwise, the money available on the server will be grown using the grow() Netscript function::
|
||||
|
||||
if (getServerMoneyAvailable('foodnstuff') > 200000) {
|
||||
hack("foodnstuff");
|
||||
} else {
|
||||
grow("foodnstuff");
|
||||
}
|
@ -142,6 +142,8 @@ Comments are not evaluated as code, and can be used to document and/or explain c
|
||||
* comment */
|
||||
print("This code will actually get executed");
|
||||
|
||||
.. _netscriptimporting:
|
||||
|
||||
Importing Functions
|
||||
-------------------
|
||||
|
||||
@ -201,7 +203,7 @@ to specify a namespace for the import::
|
||||
//...
|
||||
}
|
||||
|
||||
Note that exporting functions is not required.
|
||||
Note that exporting functions is not required.
|
||||
|
||||
|
||||
Javascript Math Module
|
||||
|
@ -1,53 +0,0 @@
|
||||
Netscript Operators
|
||||
===================
|
||||
|
||||
Operators
|
||||
---------
|
||||
|
||||
Binary Operators
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Binary operators require two operands and produce a result based on their values. In general, binary
|
||||
operators do not change the value of the operands.
|
||||
|
||||
=========== =========================== ==============================================================
|
||||
Operator Name Example/Comments
|
||||
=========== =========================== ==============================================================
|
||||
= Assignment i = 5 would assign the value 5 to the variable i
|
||||
\+ Addition 5 + 12 would return 17
|
||||
\- Subtraction 20 - 8 would return 12
|
||||
\* Multiplication 4 * 5 would return 20
|
||||
\/ Division 50 / 10 would return 5
|
||||
% Modulo 50 % 9 would return 5
|
||||
&& Logical AND true && false would return false
|
||||
|| Logical OR true || false would return true
|
||||
< Less than 4 < 5 would return true
|
||||
> Greater than 4 > 5 would return false
|
||||
<= Less than or equal to 5 <= 5 would return true
|
||||
>= Greater than or equal to 5 >= 4 would return true
|
||||
== Equality 1 == 1 would return true
|
||||
!= Inequality 4 != 5 would return true
|
||||
=== Strict equality 1 === "1" would return false
|
||||
!== Strict inequality 1 !== "1" would return true
|
||||
=========== =========================== ==============================================================
|
||||
|
||||
Unary Operators
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Unary operators require only a single operand and produce a result based on their values. Some unary operators will
|
||||
change the value of their operands. For example::
|
||||
|
||||
i = 0;
|
||||
++i;
|
||||
|
||||
Running the pre-increment unary operator (++) in the code above changes the value of the variable i.
|
||||
|
||||
|
||||
=============== =========================== ==============================================================================================
|
||||
Operator Name Example/comments
|
||||
=============== =========================== ==============================================================================================
|
||||
! Logical NOT operator !true would return false, and !false would return true. Does not change operand's value
|
||||
\- Negation Negates a number. Only works for numerics. Does not change operand's value
|
||||
++ Pre-increment ++i or i++. WARNING: This only pre-increments, even if you put i++. Changes operand's value
|
||||
-- Pre-decrement --i or i--. WARNING: This only pre-decrements, even if you put i--. Changes operand's value
|
||||
=============== =========================== ==============================================================================================
|
@ -481,6 +481,17 @@ getOwnedAugmentations
|
||||
|
||||
This function returns an array containing the names (as strings) of all Augmentations you have.
|
||||
|
||||
getOwnedSourceFiles
|
||||
-------------------
|
||||
|
||||
.. js:function:: getOwnedSourceFiles()
|
||||
|
||||
If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.
|
||||
|
||||
Returns an array of source files
|
||||
[{n: 1, lvl: 3}, {n: 4, lvl: 3}]
|
||||
|
||||
|
||||
getAugmentationsFromFaction
|
||||
---------------------------
|
||||
|
||||
|
13
index.html
13
index.html
@ -14,16 +14,7 @@
|
||||
<meta name="msapplication-TileColor" content="#000000">
|
||||
<meta name="msapplication-config" content="dist/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<link rel="stylesheet" type="text/css" href="css/styles.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/terminal.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/menupages.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/workinprogress.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/popupboxes.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/interactivetutorial.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/loader.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/missions.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/companymanagement.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/bladeburner.css" />
|
||||
<link rel="stylesheet" type="text/css" href="dist/engine.css" />
|
||||
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
@ -814,7 +805,7 @@
|
||||
<span class="tooltiptext">
|
||||
The minimum number of milliseconds it takes to execute an operation in Netscript.
|
||||
Setting this too low can result in poor performance if you have many scripts running.
|
||||
The default value is 50ms.
|
||||
The default value is 25ms.
|
||||
</span>
|
||||
</label>
|
||||
|
||||
|
@ -72,6 +72,7 @@ let NetscriptFunctions =
|
||||
"serverExists|fileExists|isRunning|" +
|
||||
"deleteServer|getPurchasedServers|" +
|
||||
"getPurchasedServerLimit|getPurchasedServerMaxRam|" +
|
||||
"getPurchasedServerCost|" +
|
||||
"purchaseServer|round|write|read|peek|clear|rm|getPortHandle|" +
|
||||
"scriptRunning|scriptKill|getScriptName|getScriptRam|" +
|
||||
"getHackTime|getGrowTime|getWeakenTime|getScriptIncome|getScriptExpGain|" +
|
||||
@ -82,9 +83,9 @@ let NetscriptFunctions =
|
||||
"getCompanyFavor|stopAction|getFactionFavor|" +
|
||||
"checkFactionInvitations|joinFaction|workForFaction|getFactionRep|" +
|
||||
"createProgram|commitCrime|getCrimeChance|getOwnedAugmentations|" +
|
||||
"getAugmentationsFromFaction|" +
|
||||
"getOwnedSourceFiles|getAugmentationsFromFaction|" +
|
||||
"getAugmentationCost|purchaseAugmentation|" +
|
||||
"installAugmentations|" +
|
||||
"installAugmentations|" +
|
||||
"getStockPrice|getStockPosition|buyStock|sellStock|shortStock|sellShort|" +
|
||||
"placeOrder|cancelOrder|" +
|
||||
//Hacknet Node API
|
||||
@ -96,6 +97,8 @@ let NetscriptFunctions =
|
||||
"bladeburner|getContractNames|getOperationNames|getBlackOpNames|" +
|
||||
"getGeneralActionNames|getSkillNames|startAction|stopBladeburnerAction|" +
|
||||
"getActionTime|getActionEstimatedSuccessChance|getActionCountRemaining|" +
|
||||
"getActionMaxLevel|getActionCurrentLevel|getActionAutolevel|" +
|
||||
"setActionAutolevel|setActionLevel|" +
|
||||
"getRank|getSkillPoints|getSkillLevel|upgradeSkill|getTeamSize|" +
|
||||
"setTeamSize|getCityEstimatedPopulation|getCityEstimatedCommunities|" +
|
||||
"getCityChaos|switchCity|getStamina|joinBladeburnerFaction";
|
||||
|
1918
package-lock.json
generated
1918
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -52,11 +52,14 @@
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^4.1.0",
|
||||
"lodash": "^4.17.10",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mocha": "^3.2.0",
|
||||
"mocha-lcov-reporter": "^1.0.0",
|
||||
"node-sass": "^4.9.2",
|
||||
"nsp": "^3.2.1",
|
||||
"raw-loader": "~0.5.0",
|
||||
"sass-loader": "^7.0.3",
|
||||
"script-loader": "~0.7.0",
|
||||
"should": "^11.1.1",
|
||||
"simple-git": "^1.96.0",
|
||||
|
@ -739,7 +739,8 @@ function initAugmentations() {
|
||||
"This augmentation: <br>" +
|
||||
"Increases the player's hacking speed by 2%<br>" +
|
||||
"Increases the player's chance of successfully performing a hack by 5%<br>" +
|
||||
"Increases the player's hacking skill by 7%"
|
||||
"Increases the player's hacking skill by 7%",
|
||||
prereqs:[AugmentationNames.CranialSignalProcessorsG1]
|
||||
});
|
||||
CranialSignalProcessorsG2.addToFactions(["NiteSec"]);
|
||||
if (augmentationExists(AugmentationNames.CranialSignalProcessorsG2)) {
|
||||
@ -756,7 +757,8 @@ function initAugmentations() {
|
||||
"This augmentation:<br>" +
|
||||
"Increases the player's hacking speed by 2%<br>" +
|
||||
"Increases the amount of money the player gains from hacking by 15%<br>" +
|
||||
"Increases the player's hacking skill by 9%"
|
||||
"Increases the player's hacking skill by 9%",
|
||||
prereqs:[AugmentationNames.CranialSignalProcessorsG2]
|
||||
});
|
||||
CranialSignalProcessorsG3.addToFactions(["NiteSec", "The Black Hand"]);
|
||||
if (augmentationExists(AugmentationNames.CranialSignalProcessorsG3)) {
|
||||
@ -773,7 +775,8 @@ function initAugmentations() {
|
||||
"This augmentation: <br>" +
|
||||
"Increases the player's hacking speed by 2%<br>" +
|
||||
"Increases the amount of money the player gains from hacking by 20%<br>" +
|
||||
"Increases the amount of money the player can inject into servers using grow() by 25%"
|
||||
"Increases the amount of money the player can inject into servers using grow() by 25%",
|
||||
prereqs:[AugmentationNames.CranialSignalProcessorsG3]
|
||||
});
|
||||
CranialSignalProcessorsG4.addToFactions(["The Black Hand"]);
|
||||
if (augmentationExists(AugmentationNames.CranialSignalProcessorsG4)) {
|
||||
@ -784,13 +787,14 @@ function initAugmentations() {
|
||||
var CranialSignalProcessorsG5 = new Augmentation({
|
||||
name:AugmentationNames.CranialSignalProcessorsG5, repCost:100e3, moneyCost:450e6,
|
||||
info:"The fifth generation of Cranial Signal Processors. Cranial Signal Processors " +
|
||||
"are a set of specialized microprocessors that are attached to " +
|
||||
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||
"so that the brain doesn't have to. <br><br>" +
|
||||
"This augmentation:<br>" +
|
||||
"Increases the player's hacking skill by 30%<br>" +
|
||||
"Increases the amount of money the player gains from hacking by 25%<br>" +
|
||||
"Increases the amount of money the player can inject into servers using grow() by 75%"
|
||||
"are a set of specialized microprocessors that are attached to " +
|
||||
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||
"so that the brain doesn't have to. <br><br>" +
|
||||
"This augmentation:<br>" +
|
||||
"Increases the player's hacking skill by 30%<br>" +
|
||||
"Increases the amount of money the player gains from hacking by 25%<br>" +
|
||||
"Increases the amount of money the player can inject into servers using grow() by 75%",
|
||||
prereqs:[AugmentationNames.CranialSignalProcessorsG4]
|
||||
});
|
||||
CranialSignalProcessorsG5.addToFactions(["BitRunners"]);
|
||||
if (augmentationExists(AugmentationNames.CranialSignalProcessorsG5)) {
|
||||
@ -884,7 +888,7 @@ function initAugmentations() {
|
||||
"This augmentation:<br>" +
|
||||
"Increases the amount of reputation the player gains when working for a company by 75%<br>" +
|
||||
"Increases the player's hacking skill by 10%",
|
||||
prereqs:[AugmentationNames.PCDNI],
|
||||
prereqs:[AugmentationNames.PCDNI]
|
||||
});
|
||||
PCDNIOptimizer.addToFactions(["Fulcrum Secret Technologies", "ECorp", "Blade Industries"]);
|
||||
if (augmentationExists(AugmentationNames.PCDNIOptimizer)) {
|
||||
@ -902,7 +906,7 @@ function initAugmentations() {
|
||||
"Increases the amount of reputation the player gains when working for a company by 100%<br>" +
|
||||
"Increases the player's hacking skill by 10%<br>" +
|
||||
"Increases the player's hacking speed by 5%",
|
||||
prereqs:[AugmentationNames.PCDNI],
|
||||
prereqs:[AugmentationNames.PCDNI]
|
||||
});
|
||||
PCDNINeuralNetwork.addToFactions(["Fulcrum Secret Technologies"]);
|
||||
if (augmentationExists(AugmentationNames.PCDNINeuralNetwork)) {
|
||||
@ -1112,7 +1116,8 @@ function initAugmentations() {
|
||||
"This augmentation: <br>" +
|
||||
"Increases the player's agility by 10% <br>" +
|
||||
"Increases the player's defense by 10% <br>" +
|
||||
"Increases the amount of money the player gains from crimes by 25%"
|
||||
"Increases the amount of money the player gains from crimes by 25%",
|
||||
prereqs:[AugmentationNames.LuminCloaking1]
|
||||
});
|
||||
LuminCloaking2.addToFactions(["Slum Snakes", "Tetrads"]);
|
||||
if (augmentationExists(AugmentationNames.LuminCloaking2)) {
|
||||
|
@ -357,8 +357,8 @@ function initBitNodeMultipliers() {
|
||||
sf12Lvl = Player.sourceFiles[i].lvl;
|
||||
}
|
||||
}
|
||||
var inc = Math.pow(1.01, sf12Lvl);
|
||||
var dec = Math.pow(0.99, sf12Lvl);
|
||||
var inc = Math.pow(1.02, sf12Lvl);
|
||||
var dec = 1/inc;
|
||||
BitNodeMultipliers.HackingLevelMultiplier = dec;
|
||||
|
||||
BitNodeMultipliers.ServerMaxMoney = dec;
|
||||
|
@ -358,7 +358,7 @@ function Skill(params={name:"foo", desc:"foo"}) {
|
||||
}
|
||||
|
||||
Skill.prototype.calculateCost = function(currentLevel) {
|
||||
return (this.baseCost + (currentLevel * this.costInc)) * BitNodeMultipliers.BladeburnerSkillCost;
|
||||
return Math.floor((this.baseCost + (currentLevel * this.costInc)) * BitNodeMultipliers.BladeburnerSkillCost);
|
||||
}
|
||||
var Skills = {};
|
||||
var SkillNames = {
|
||||
@ -1042,22 +1042,23 @@ Bladeburner.prototype.upgradeSkill = function(skill) {
|
||||
|
||||
Bladeburner.prototype.getActionObject = function(actionId) {
|
||||
//Given an ActionIdentifier object, returns the corresponding
|
||||
//Contract, Operation, or BlackOperation object
|
||||
//GeneralAction, Contract, Operation, or BlackOperation object
|
||||
switch (actionId.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
return this.contracts[actionId.name];
|
||||
break;
|
||||
case ActionTypes["Operation"]:
|
||||
return this.operations[actionId.name];
|
||||
break;
|
||||
case ActionTypes["BlackOp"]:
|
||||
case ActionTypes["BlackOperation"]:
|
||||
return BlackOperations[actionId.name];
|
||||
break;
|
||||
case ActionTypes["Training"]:
|
||||
return GeneralActions["Training"];
|
||||
case ActionTypes["Field Analysis"]:
|
||||
return GeneralActions["Field Analysis"];
|
||||
case ActionTypes["Recruitment"]:
|
||||
return GeneralActions["Recruitment"];
|
||||
default:
|
||||
return null;
|
||||
console.log("WARNING: Bladeburner.getActionObject() called with an unexpected " +
|
||||
"ActionIdentifier type: " + actionId.type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1093,6 +1094,7 @@ Bladeburner.prototype.startAction = function(actionId) {
|
||||
throw new Error ("Failed to get Operation Object for: " + actionId.name);
|
||||
}
|
||||
if (action.count < 1) {return this.resetAction();}
|
||||
if (actionId.name === "Raid" && this.getCurrentCity().commsEst === 0) {return this.resetAction();}
|
||||
this.actionTimeToComplete = action.getActionTime(this);
|
||||
} catch(e) {
|
||||
exceptionAlert(e);
|
||||
@ -1280,7 +1282,7 @@ Bladeburner.prototype.completeAction = function() {
|
||||
teamLossMax = Math.floor(teamCount);
|
||||
|
||||
if (this.logging.blackops) {
|
||||
this.log(action.name + " failed! Lost " + formatNumber(rankLoss, 1) + " rank and took" + formatNumber(damage, 0) + " damage");
|
||||
this.log(action.name + " failed! Lost " + formatNumber(rankLoss, 1) + " rank and took " + formatNumber(damage, 0) + " damage");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1662,6 +1664,7 @@ Bladeburner.prototype.initializeDomElementRefs = function() {
|
||||
overviewEstComms: null,
|
||||
overviewChaos: null,
|
||||
overviewSkillPoints: null,
|
||||
overviewBonusTime: null,
|
||||
overviewAugSuccessMult: null,
|
||||
overviewAugMaxStaminaMult: null,
|
||||
overviewAugStaminaGainMult: null,
|
||||
@ -1825,7 +1828,14 @@ Bladeburner.prototype.createOverviewContent = function() {
|
||||
"Having too high of a chaos level can make contracts and operations harder."
|
||||
});
|
||||
|
||||
DomElems.overviewBonusTime = createElement("p", {
|
||||
innerText: "Bonus time: ",
|
||||
display: "inline-block",
|
||||
tooltip: "You gain bonus time while offline or when you're not performing any action. " +
|
||||
"Bonus time makes the game progress faster."
|
||||
});
|
||||
DomElems.overviewSkillPoints = createElement("p", {display:"block"});
|
||||
|
||||
|
||||
DomElems.overviewAugSuccessMult = createElement("p", {display:"block"});
|
||||
DomElems.overviewAugMaxStaminaMult = createElement("p", {display:"block"});
|
||||
@ -1845,6 +1855,7 @@ Bladeburner.prototype.createOverviewContent = function() {
|
||||
appendLineBreaks(DomElems.overviewDiv, 1);
|
||||
DomElems.overviewDiv.appendChild(DomElems.overviewChaos);
|
||||
appendLineBreaks(DomElems.overviewDiv, 2);
|
||||
DomElems.overviewDiv.appendChild(DomElems.overviewBonusTime);
|
||||
DomElems.overviewDiv.appendChild(DomElems.overviewSkillPoints);
|
||||
appendLineBreaks(DomElems.overviewDiv, 1);
|
||||
DomElems.overviewDiv.appendChild(DomElems.overviewAugSuccessMult);
|
||||
@ -2015,7 +2026,7 @@ Bladeburner.prototype.createContractsContent = function() {
|
||||
}
|
||||
|
||||
DomElems.actionsAndSkillsDesc.innerHTML =
|
||||
"Complete contracts in order to increase your Bitburner rank and earn money. " +
|
||||
"Complete contracts in order to increase your Bladeburner rank and earn money. " +
|
||||
"Failing a contract will cause you to lose HP, which can lead to hospitalization.<br><br>" +
|
||||
"You can unlock higher-level contracts by successfully completing them. " +
|
||||
"Higher-level contracts are more difficult, but grant more rank, experience, and money.";
|
||||
@ -2205,6 +2216,7 @@ Bladeburner.prototype.updateOverviewContent = function() {
|
||||
DomElems.overviewEstComms.childNodes[0].nodeValue = "Est. Synthoid Communities: " + formatNumber(this.getCurrentCity().comms, 0);
|
||||
DomElems.overviewChaos.childNodes[0].nodeValue = "City Chaos: " + formatNumber(this.getCurrentCity().chaos);
|
||||
DomElems.overviewSkillPoints.innerText = "Skill Points: " + formatNumber(this.skillPoints, 0);
|
||||
DomElems.overviewBonusTime.childNodes[0].nodeValue = "Bonus time: " + this.storedCycles/CyclesPerSecond;
|
||||
DomElems.overviewAugSuccessMult.innerText = "Aug. Success Chance Mult: " + formatNumber(Player.bladeburner_success_chance_mult*100, 1) + "%";
|
||||
DomElems.overviewAugMaxStaminaMult.innerText = "Aug. Max Stamina Mult: " + formatNumber(Player.bladeburner_max_stamina_mult*100, 1) + "%";
|
||||
DomElems.overviewAugStaminaGainMult.innerText = "Aug. Stamina Gain Mult: " + formatNumber(Player.bladeburner_stamina_gain_mult*100, 1) + "%";
|
||||
@ -3222,6 +3234,7 @@ Bladeburner.prototype.getActionIdFromTypeAndName = function(type="", name="") {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "operation":
|
||||
case "operations":
|
||||
case "op":
|
||||
@ -3233,6 +3246,7 @@ Bladeburner.prototype.getActionIdFromTypeAndName = function(type="", name="") {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "blackoperation":
|
||||
case "black operation":
|
||||
case "black operations":
|
||||
@ -3247,6 +3261,7 @@ Bladeburner.prototype.getActionIdFromTypeAndName = function(type="", name="") {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case "general":
|
||||
case "general action":
|
||||
case "gen":
|
||||
@ -3314,7 +3329,7 @@ Bladeburner.prototype.getSkillNamesNetscriptFn = function() {
|
||||
}
|
||||
|
||||
Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.startAction() failed due to an invalid action specified. " +
|
||||
var errorLogText = "ERROR: bladeburner.startAction() failed due to an invalid action specified. " +
|
||||
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
|
||||
"name of the operation is case-sensitive.";
|
||||
var actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
@ -3326,19 +3341,19 @@ Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript
|
||||
try {
|
||||
this.startAction(actionId);
|
||||
if (workerScript.shouldLog("startAction")) {
|
||||
workerScript.scriptRef.log("Starting Bladeburner action with type " + type + " and name " + name);
|
||||
workerScript.scriptRef.log("Starting bladeburner action with type " + type + " and name " + name);
|
||||
}
|
||||
return true;
|
||||
} catch(e) {
|
||||
this.resetAction();
|
||||
workerScript.scriptRef.log("ERROR: Bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
|
||||
workerScript.scriptRef.log("ERROR: bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
|
||||
"Note that this name is case-sensitive and whitespace-sensitive");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.getActionTime() failed due to an invalid action specified. " +
|
||||
var errorLogText = "ERROR: bladeburner.getActionTime() failed due to an invalid action specified. " +
|
||||
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
|
||||
"name of the operation is case-sensitive.";
|
||||
var actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
@ -3372,7 +3387,7 @@ Bladeburner.prototype.getActionTimeNetscriptFn = function(type, name, workerScri
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getActionEstimatedSuccessChanceNetscriptFn = function(type, name, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.getActionEstimatedSuccessChance() failed due to an invalid action specified. " +
|
||||
var errorLogText = "ERROR: bladeburner.getActionEstimatedSuccessChance() failed due to an invalid action specified. " +
|
||||
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
|
||||
"name of the operation is case-sensitive.";
|
||||
var actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
@ -3406,7 +3421,7 @@ Bladeburner.prototype.getActionEstimatedSuccessChanceNetscriptFn = function(type
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.getActionCountRemaining() failed due to an invalid action specified. " +
|
||||
var errorLogText = "ERROR: bladeburner.getActionCountRemaining() failed due to an invalid action specified. " +
|
||||
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
|
||||
"name of the operation is case-sensitive.";
|
||||
var actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
@ -3438,7 +3453,7 @@ Bladeburner.prototype.getActionCountRemainingNetscriptFn = function(type, name,
|
||||
}
|
||||
|
||||
Bladeburner.prototype.getSkillLevelNetscriptFn = function(skillName, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.getSkillLevel() failed due to an invalid skill specified: " +
|
||||
var errorLogText = "ERROR: bladeburner.getSkillLevel() failed due to an invalid skill specified: " +
|
||||
skillName + ". Note that the name of the skill is case-sensitive";
|
||||
|
||||
if (skillName === "") {
|
||||
@ -3458,7 +3473,7 @@ Bladeburner.prototype.getSkillLevelNetscriptFn = function(skillName, workerScrip
|
||||
}
|
||||
|
||||
Bladeburner.prototype.upgradeSkillNetscriptFn = function(skillName, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.upgradeSkill() failed due to an invalid skill specified: " +
|
||||
var errorLogText = "ERROR: bladeburner.upgradeSkill() failed due to an invalid skill specified: " +
|
||||
skillName + ". Note that the name of the skill is case-sensitive";
|
||||
if (!Skills.hasOwnProperty(skillName)) {
|
||||
workerScript.log(errorLogText);
|
||||
@ -3472,9 +3487,16 @@ Bladeburner.prototype.upgradeSkillNetscriptFn = function(skillName, workerScript
|
||||
}
|
||||
var cost = skill.calculateCost(currentLevel);
|
||||
|
||||
if(skill.maxLvl && currentLevel >= skill.maxLvl) {
|
||||
if (workerScript.shouldLog("upgradeSkill")) {
|
||||
workerScript.log(`bladeburner.upgradeSkill() failed because ${skillName} is already maxed`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.skillPoints < cost) {
|
||||
if (workerScript.shouldLog("upgradeSkill")) {
|
||||
workerScript.log("Bladeburner.upgradeSkill() failed because you do not have enough " +
|
||||
workerScript.log("bladeburner.upgradeSkill() failed because you do not have enough " +
|
||||
"skill points to upgrade " + skillName + " (You have " +
|
||||
this.skillPoints + ", you need " + cost + ")");
|
||||
}
|
||||
@ -3497,7 +3519,7 @@ Bladeburner.prototype.getTeamSizeNetscriptFn = function(type, name, workerScript
|
||||
return this.teamSize;
|
||||
}
|
||||
|
||||
var errorLogText = "ERROR: Bladeburner.getTeamSize() failed due to an invalid action specified. " +
|
||||
var errorLogText = "ERROR: bladeburner.getTeamSize() failed due to an invalid action specified. " +
|
||||
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
|
||||
"name of the operation is case-sensitive.";
|
||||
|
||||
@ -3523,7 +3545,7 @@ Bladeburner.prototype.getTeamSizeNetscriptFn = function(type, name, workerScript
|
||||
}
|
||||
|
||||
Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, workerScript) {
|
||||
var errorLogText = "ERROR: Bladeburner.setTeamSize() failed due to an invalid action specified. " +
|
||||
var errorLogText = "ERROR: bladeburner.setTeamSize() failed due to an invalid action specified. " +
|
||||
"Type: " + type + ", Name: " + name + ". Note that for contracts and operations, the " +
|
||||
"name of the operation is case-sensitive.";
|
||||
var actionId = this.getActionIdFromTypeAndName(type, name);
|
||||
@ -3535,7 +3557,7 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
|
||||
if (actionId.type !== ActionTypes["Operation"] &&
|
||||
actionId.type !== ActionTypes["BlackOp"] &&
|
||||
actionId.type !== ActionTypes["BlackOperation"]) {
|
||||
workerScript.log("ERROR: Bladeburner.setTeamSize() failed. This function " +
|
||||
workerScript.log("ERROR: bladeburner.setTeamSize() failed. This function " +
|
||||
"only works for Operations and BlackOps");
|
||||
return -1;
|
||||
}
|
||||
@ -3548,7 +3570,7 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
|
||||
|
||||
var sanitizedSize = Math.round(size);
|
||||
if (isNaN(sanitizedSize)) {
|
||||
workerScript.log("ERROR: Bladeburner.setTeamSize() failed due to an invalid 'size' argument: " + size);
|
||||
workerScript.log("ERROR: bladeburner.setTeamSize() failed due to an invalid 'size' argument: " + size);
|
||||
return -1;
|
||||
}
|
||||
if (this.teamSize < sanitizedSize) {sanitizedSize = this.teamSize;}
|
||||
@ -3561,7 +3583,7 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
|
||||
|
||||
Bladeburner.prototype.getCityEstimatedPopulationNetscriptFn = function(cityName, workerScript) {
|
||||
if (!this.cities.hasOwnProperty(cityName)) {
|
||||
workerScript.log("ERROR: Bladeburner.getCityEstimatedPopulation() failed because the specified " +
|
||||
workerScript.log("ERROR: bladeburner.getCityEstimatedPopulation() failed because the specified " +
|
||||
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
|
||||
return -1;
|
||||
}
|
||||
@ -3570,7 +3592,7 @@ Bladeburner.prototype.getCityEstimatedPopulationNetscriptFn = function(cityName,
|
||||
|
||||
Bladeburner.prototype.getCityEstimatedCommunitiesNetscriptFn = function(cityName, workerScript) {
|
||||
if (!this.cities.hasOwnProperty(cityName)) {
|
||||
workerScript.log("ERROR: Bladeburner.getCityEstimatedCommunities() failed because the specified " +
|
||||
workerScript.log("ERROR: bladeburner.getCityEstimatedCommunities() failed because the specified " +
|
||||
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
|
||||
return -1;
|
||||
}
|
||||
@ -3579,7 +3601,7 @@ Bladeburner.prototype.getCityEstimatedCommunitiesNetscriptFn = function(cityName
|
||||
|
||||
Bladeburner.prototype.getCityChaosNetscriptFn = function(cityName, workerScript) {
|
||||
if (!this.cities.hasOwnProperty(cityName)) {
|
||||
workerScript.log("ERROR: Bladeburner.getCityChaos() failed because the specified " +
|
||||
workerScript.log("ERROR: bladeburner.getCityChaos() failed because the specified " +
|
||||
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
|
||||
return -1;
|
||||
}
|
||||
@ -3588,7 +3610,7 @@ Bladeburner.prototype.getCityChaosNetscriptFn = function(cityName, workerScript)
|
||||
|
||||
Bladeburner.prototype.switchCityNetscriptFn = function(cityName, workerScript) {
|
||||
if (!this.cities.hasOwnProperty(cityName)) {
|
||||
workerScript.log("ERROR: Bladeburner.switchCity() failed because the specified " +
|
||||
workerScript.log("ERROR: bladeburner.switchCity() failed because the specified " +
|
||||
"city was invalid: " + cityName + ". Note that this city argument is case-sensitive");
|
||||
return false;
|
||||
}
|
||||
@ -3636,7 +3658,7 @@ function initBladeburner() {
|
||||
Skills[SkillNames.BladesIntuition] = new Skill({
|
||||
name:SkillNames.BladesIntuition,
|
||||
desc:"Each level of this skill increases your success chance " +
|
||||
"for all contracts and operations by 3%",
|
||||
"for all Contracts, Operations, and BlackOps by 3%",
|
||||
baseCost:5, costInc:2,
|
||||
successChanceAll:3
|
||||
});
|
||||
@ -3650,7 +3672,7 @@ function initBladeburner() {
|
||||
Skills[SkillNames.Cloak] = new Skill({
|
||||
name:SkillNames.Cloak,
|
||||
desc:"Each level of this skill increases your " +
|
||||
"success chance in stealth-related contracts and operations by 5.5%",
|
||||
"success chance in stealth-related Contracts, Operations, and BlackOps by 5.5%",
|
||||
baseCost:3, costInc:1,
|
||||
successChanceStealth:5.5
|
||||
});
|
||||
@ -3661,7 +3683,7 @@ function initBladeburner() {
|
||||
Skills[SkillNames.Overclock] = new Skill({
|
||||
name:SkillNames.Overclock,
|
||||
desc:"Each level of this skill decreases the time it takes " +
|
||||
"to attempt a contract or operation by 1% (Max Level: 95)",
|
||||
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 95)",
|
||||
baseCost:5, costInc:1, maxLvl:95,
|
||||
actionTime:1
|
||||
});
|
||||
@ -3675,14 +3697,14 @@ function initBladeburner() {
|
||||
Skills[SkillNames.ShortCircuit] = new Skill({
|
||||
name:SkillNames.ShortCircuit,
|
||||
desc:"Each level of this skill increases your success chance " +
|
||||
"in contracts and operations that involve retirement by 5.5%",
|
||||
"in Contracts, Operations, and BlackOps that involve retirement by 5.5%",
|
||||
baseCost:3, costInc:2,
|
||||
successChanceKill:5.5
|
||||
});
|
||||
Skills[SkillNames.DigitalObserver] = new Skill({
|
||||
name:SkillNames.DigitalObserver,
|
||||
desc:"Each level of this skill increases your success chance in " +
|
||||
"all operations by 4%",
|
||||
"all Operations and BlackOps by 4%",
|
||||
baseCost:5, costInc:2,
|
||||
successChanceOperation:4
|
||||
});
|
||||
@ -3698,7 +3720,7 @@ function initBladeburner() {
|
||||
Skills[SkillNames.Tracer] = new Skill({
|
||||
name:SkillNames.Tracer,
|
||||
desc:"Each level of this skill increases your success chance in " +
|
||||
"all contracts by 4%",
|
||||
"all Contracts by 4%",
|
||||
baseCost:3, costInc:2,
|
||||
successChanceContract:4
|
||||
});
|
||||
|
@ -4736,7 +4736,7 @@ Corporation.prototype.updateDivisionContent = function(division) {
|
||||
var totalAdvertisingFac = advertisingFactors[0];
|
||||
advertisingInfo =
|
||||
"<p class='tooltip'>Advertising Multiplier: x" + formatNumber(totalAdvertisingFac, 3) +
|
||||
"<span class='tooltiptext' style='font-size:12px'>Total multiplier for this industry's sales due to its awareness and popularity<br>" +
|
||||
"<span class='tooltiptext cmpy-mgmt-advertising-info'>Total multiplier for this industry's sales due to its awareness and popularity<br>" +
|
||||
"Awareness Bonus: x" + formatNumber(Math.pow(awarenessFac, 0.85), 3) + "<br>" +
|
||||
"Popularity Bonus: x" + formatNumber(Math.pow(popularityFac, 0.85), 3) + "<br>" +
|
||||
"Ratio Multiplier: x" + formatNumber(Math.pow(ratioFac, 0.85), 3) + "</span></p><br>"
|
||||
|
@ -1,5 +1,5 @@
|
||||
let CONSTANTS = {
|
||||
Version: "0.39.1",
|
||||
Version: "0.40.0",
|
||||
|
||||
//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
|
||||
@ -7,7 +7,7 @@ let CONSTANTS = {
|
||||
MaxSkillLevel: 975,
|
||||
|
||||
//How much reputation is needed to join a megacorporation's faction
|
||||
CorpFactionRepRequirement: 250000,
|
||||
CorpFactionRepRequirement: 200e3,
|
||||
|
||||
/* Base costs */
|
||||
BaseCostFor1GBOfRamHome: 32000,
|
||||
@ -31,6 +31,7 @@ let CONSTANTS = {
|
||||
HacknetNodeMaxCores: 16,
|
||||
|
||||
/* Faction and Company favor */
|
||||
BaseFavorToDonate: 150,
|
||||
FactionReputationToFavorBase: 500,
|
||||
FactionReputationToFavorMult: 1.02,
|
||||
CompanyReputationToFavorBase: 500,
|
||||
@ -70,6 +71,7 @@ let CONSTANTS = {
|
||||
ScriptHNUpgCoreRamCost: 0.8,
|
||||
ScriptGetStockRamCost: 2.0,
|
||||
ScriptBuySellStockRamCost: 2.5,
|
||||
ScriptGetPurchaseServerRamCost: 0.25,
|
||||
ScriptPurchaseServerRamCost: 2.25,
|
||||
ScriptGetPurchasedServerLimit: 0.05,
|
||||
ScriptGetPurchasedServerMaxRam: 0.05,
|
||||
@ -78,6 +80,7 @@ let CONSTANTS = {
|
||||
ScriptArbScriptRamCost: 1.0, //Functions that apply to all scripts regardless of args
|
||||
ScriptGetScriptRamCost: 0.1,
|
||||
ScriptGetHackTimeRamCost: 0.05,
|
||||
ScriptGetFavorToDonate: 0.10,
|
||||
|
||||
ScriptSingularityFn1RamCost: 1,
|
||||
ScriptSingularityFn2RamCost: 2,
|
||||
@ -489,7 +492,10 @@ let CONSTANTS = {
|
||||
|
||||
LatestUpdate:
|
||||
"v0.40.0<br>" +
|
||||
"* Netscript 1.0 (NS1) now uses a fully-fledged ES5 Javascript Interpreter. This means many new features are now available in NS1, and this also fixes several bugs." +
|
||||
"* <b>WARNING: This update makes some significant changes to Netscript and therefore you may need to " +
|
||||
"make some changes to your scripts. See <a href='https://www.reddit.com/r/Bitburner/comments/9252j4/psa_netscript_10_changes_in_next_version_v0400/' target='_blank'> " +
|
||||
"this post for details</a></b><br>" +
|
||||
"* Netscript 1.0 (NS1) now uses a fully-fledged ES5 JavaScript Interpreter. This means many new features are now available in NS1, and this also fixes several bugs." +
|
||||
" However this also means any ES6+ features are no longer supported in NS1 <br>" +
|
||||
"* When a server is hacked with a very large number of threads and left with no money, the server's security level " +
|
||||
"now only increases by however many threads were needed to drain the server. For example, if you hack a server with " +
|
||||
@ -497,15 +503,22 @@ let CONSTANTS = {
|
||||
"as if you had hacked it with 2000 threads (change by hydroflame)<br>" +
|
||||
"* Added getCurrentAction() to Bladeburner API<br>" +
|
||||
"* Added a variety of functions to Bladeburner API that deal with action levels (change by hydroflame)<br>" +
|
||||
"* Added getPurchasedServerLimit() and getPurchasedServerMaxRam() functions to Netscript (change by hydroflame & kopelli)<br>" +
|
||||
"* Added getPurchasedServerLimit() and getPurchasedServerMaxRam() functions to Netscript (change by hydroflame & kopelli)<br>" +
|
||||
"* Added getOwnedSourceFiles() Singularity function (by hydroflame)<br>" +
|
||||
"* Completely re-designed the Hacknet Node API<br>" +
|
||||
"* getSkillLevel() in Bladeburner API now returns an error if no argument is passed in (as opposed to an object with all skill levels). This may break scripts<br>" +
|
||||
"* Minimum Netscript execution time reduced from 15ms to 10ms (configurable in Options)<br>" +
|
||||
"* Company reputation needed to get invited to Megacorporation factions decreased from 250k to 200k<br>" +
|
||||
"* HP is now reset (restored) when Augmenting<br>" +
|
||||
"* Source-File 6 now increases both the level and experience gain of all combat stats (it was only experience gain previously)<br>" +
|
||||
"* Reverted a previous change for Source-File 12. It's benefits are now multiplicative rather than additive<br>" +
|
||||
"* Starting Infiltration security level for almost every location decreased by ~10%<br>" +
|
||||
"* Bug Fix: Infiltration buttons can no longer be clicked through NetscriptJS<br>"
|
||||
"* Changed 'fl1ght.exe' message when its listed conditions are fulfilled (by hydroflame)<br>" +
|
||||
"* The 'Save Game' button in the top-right overview panel now flashes red if autosave is disabled<br>" +
|
||||
"* Bug Fix: Infiltration buttons can no longer be clicked through NetscriptJS<br>" +
|
||||
"* Bug Fix: Bladeburner 'Overclock' skill can no longer be leveled above max level through the API (by hydroflame)<br>" +
|
||||
"* Bug Fix: Healthcare division in Bladeburner should no longer cause game to crash"
|
||||
|
||||
}
|
||||
|
||||
export {CONSTANTS};
|
||||
|
@ -55,7 +55,7 @@ Faction.prototype.gainFavor = function() {
|
||||
this.rolloverRep = res[1];
|
||||
}
|
||||
|
||||
//Returns an array with [How much favor would be gained, how much favor would be left over]
|
||||
//Returns an array with [How much favor would be gained, how much rep would be left over]
|
||||
Faction.prototype.getFavorGain = function() {
|
||||
if (this.favor == null || this.favor == undefined) {this.favor = 0;}
|
||||
if (this.rolloverRep == null || this.rolloverRep == undefined) {this.rolloverRep = 0;}
|
||||
@ -432,7 +432,7 @@ function displayFactionContent(factionName) {
|
||||
throw new Error("Not a member of this faction, cannot display faction information");
|
||||
}
|
||||
|
||||
donateDiv.style.display = faction.favor >= (150 * BitNodeMultipliers.RepToDonateToFaction) ? "inline" : "none";
|
||||
donateDiv.style.display = faction.favor >= Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction) ? "inline" : "none";
|
||||
|
||||
hackMissionDiv.style.display = factionInfo.offerHackingMission ? "inline": "none";
|
||||
hackDiv.style.display = factionInfo.offerHackingWork ? "inline" : "none";
|
||||
@ -577,7 +577,6 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
|
||||
var aElem = createElement("a", {
|
||||
innerText:aug.name, display:"inline",
|
||||
clickListener:()=>{
|
||||
console.log('sup buy in fac: '+Settings.SuppressBuyAugmentationConfirmation);
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
purchaseAugmentationBoxCreate(aug, faction);
|
||||
} else {
|
||||
@ -670,7 +669,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
|
||||
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
|
||||
"purchase this one.";
|
||||
if (sing) {return txt;} else {dialogBoxCreate(txt);}
|
||||
} else if (Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
} else if (aug.baseCost !== 0 && Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
let txt = "You don't have enough money to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
@ -678,7 +677,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
|
||||
let txt = "You don't have enough faction reputation to purchase " + aug.name;
|
||||
if (sing) {return txt;}
|
||||
dialogBoxCreate(txt);
|
||||
} else if (Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
} else if (aug.baseCost === 0 || Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
|
||||
if (Player.firstAugPurchased === false) {
|
||||
Player.firstAugPurchased = true;
|
||||
document.getElementById("augmentations-tab").style.display = "list-item";
|
||||
|
@ -30,9 +30,12 @@ import * as acorn from "../utils/acorn";
|
||||
* @param {Function=} opt_initFunc Optional initialization function. Used to
|
||||
* define APIs. When called it is passed the interpreter object and the
|
||||
* global scope object.
|
||||
* @param {Number} Bitburner-specific number used for determining exception line numbers
|
||||
* @constructor
|
||||
*/
|
||||
var Interpreter = function(code, opt_initFunc) {
|
||||
var Interpreter = function(code, opt_initFunc, lineOffset=0) {
|
||||
this.sourceCode = code;
|
||||
this.sourceCodeLineOffset = lineOffset;
|
||||
if (typeof code === 'string') {
|
||||
code = acorn.parse(code, Interpreter.PARSE_OPTIONS);
|
||||
}
|
||||
@ -81,7 +84,8 @@ var Interpreter = function(code, opt_initFunc) {
|
||||
* @const {!Object} Configuration used for all Acorn parsing.
|
||||
*/
|
||||
Interpreter.PARSE_OPTIONS = {
|
||||
ecmaVersion: 5
|
||||
ecmaVersion: 5,
|
||||
locations: true
|
||||
};
|
||||
|
||||
/**
|
||||
@ -147,6 +151,37 @@ Interpreter.VALUE_IN_DESCRIPTOR = {};
|
||||
*/
|
||||
Interpreter.toStringCycles_ = [];
|
||||
|
||||
/**
|
||||
* Determine error/exception line number in Bitburner source code
|
||||
* @param {Object} AST Node that causes Error/Exception
|
||||
*/
|
||||
Interpreter.prototype.getErrorLineNumber = function(node) {
|
||||
var code = this.sourceCode;
|
||||
if (node == null || node.start == null) {return NaN;}
|
||||
try {
|
||||
code = code.substring(0, node.start);
|
||||
return (code.match(/\n/g) || []).length + 1 - this.sourceCodeLineOffset;
|
||||
} catch(e) {
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the appropriate line number error message for Bitburner
|
||||
* @param {Number} lineNumber
|
||||
*/
|
||||
Interpreter.prototype.getErrorLineNumberMessage = function(lineNumber) {
|
||||
if (isNaN(lineNumber)) {
|
||||
return " (Unknown line number)";
|
||||
} else if (lineNumber <= 0) {
|
||||
return " (Error occurred in an imported function)";
|
||||
} else {
|
||||
return " (Line Number " + lineNumber + ". This line number is probably incorrect " +
|
||||
"if your script is importing any functions. This is being worked on)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add more code to the interpreter.
|
||||
* @param {string|!Object} code Raw JavaScript text or AST.
|
||||
@ -910,6 +945,66 @@ Interpreter.prototype.initArray = function(scope) {
|
||||
"}",
|
||||
"});",
|
||||
|
||||
// Polyfill copied from:
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.find
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
|
||||
"if (!Array.prototype.find) {",
|
||||
"Object.defineProperty(Array.prototype, 'find', {",
|
||||
"value: function(predicate) {",
|
||||
"if (this == null) {",
|
||||
"throw new TypeError('\"this\" is null or not defined');",
|
||||
"}",
|
||||
"var o = Object(this);",
|
||||
"var len = o.length >>> 0;",
|
||||
"if (typeof predicate !== 'function') {",
|
||||
"throw new TypeError('predicate must be a function');",
|
||||
"}",
|
||||
"var thisArg = arguments[1];",
|
||||
"var k = 0;",
|
||||
"while (k < len) {",
|
||||
"var kValue = o[k];",
|
||||
"if (predicate.call(thisArg, kValue, k, o)) {",
|
||||
"return kValue;",
|
||||
"}",
|
||||
"k++;",
|
||||
"}",
|
||||
"return undefined;",
|
||||
"},",
|
||||
"configurable: true,",
|
||||
"writable: true",
|
||||
"});",
|
||||
"}",
|
||||
|
||||
// Poly fill copied from:
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
|
||||
"if (!Array.prototype.findIndex) {",
|
||||
"Object.defineProperty(Array.prototype, 'findIndex', {",
|
||||
"value: function(predicate) {",
|
||||
"if (this == null) {",
|
||||
"throw new TypeError('\"this\" is null or not defined');",
|
||||
"}",
|
||||
"var o = Object(this);",
|
||||
"var len = o.length >>> 0;",
|
||||
"if (typeof predicate !== 'function') {",
|
||||
"throw new TypeError('predicate must be a function');",
|
||||
"}",
|
||||
"var thisArg = arguments[1];",
|
||||
"var k = 0;",
|
||||
"while (k < len) {",
|
||||
"var kValue = o[k];",
|
||||
"if (predicate.call(thisArg, kValue, k, o)) {",
|
||||
"return k;",
|
||||
"}",
|
||||
"k++;",
|
||||
"}",
|
||||
"return -1;",
|
||||
"},",
|
||||
"configurable: true,",
|
||||
"writable: true",
|
||||
"});",
|
||||
"}",
|
||||
|
||||
// Polyfill copied from:
|
||||
// developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
|
||||
"Object.defineProperty(Array.prototype, 'forEach',",
|
||||
@ -928,6 +1023,48 @@ Interpreter.prototype.initArray = function(scope) {
|
||||
"}",
|
||||
"});",
|
||||
|
||||
// Polyfill copied from:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill
|
||||
"Object.defineProperty(Array.prototype, 'includes', {",
|
||||
"value: function(searchElement, fromIndex) {",
|
||||
"if (this == null) {",
|
||||
"throw new TypeError('\"this\" is null or not defined');",
|
||||
"}",
|
||||
"// 1. Let O be ? ToObject(this value).",
|
||||
"var o = Object(this);",
|
||||
"// 2. Let len be ? ToLength(? Get(O, \"length\")).",
|
||||
"var len = o.length >>> 0;",
|
||||
"// 3. If len is 0, return false.",
|
||||
"if (len === 0) {",
|
||||
"return false;",
|
||||
"}",
|
||||
"// 4. Let n be ? ToInteger(fromIndex).",
|
||||
"// (If fromIndex is undefined, this step produces the value 0.)",
|
||||
"var n = fromIndex | 0;",
|
||||
"// 5. If n ≥ 0, then",
|
||||
"// a. Let k be n.",
|
||||
"// 6. Else n < 0,",
|
||||
"// a. Let k be len + n.",
|
||||
"// b. If k < 0, let k be 0.",
|
||||
"var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);",
|
||||
"function sameValueZero(x, y) {",
|
||||
"return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));",
|
||||
"}",
|
||||
"// 7. Repeat, while k < len",
|
||||
"while (k < len) {",
|
||||
"// a. Let elementK be the result of ? Get(O, ! ToString(k)).",
|
||||
"// b. If SameValueZero(searchElement, elementK) is true, return true.",
|
||||
"if (sameValueZero(o[k], searchElement)) {",
|
||||
"return true;",
|
||||
"}",
|
||||
"// c. Increase k by 1. ",
|
||||
"k++;",
|
||||
"}",
|
||||
"// 8. Return false",
|
||||
"return false;",
|
||||
"}",
|
||||
"});",
|
||||
|
||||
// Polyfill copied from:
|
||||
// developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map
|
||||
"Object.defineProperty(Array.prototype, 'map',",
|
||||
@ -1012,48 +1149,6 @@ Interpreter.prototype.initArray = function(scope) {
|
||||
"}",
|
||||
"});",
|
||||
|
||||
// Polyfill copied from:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill
|
||||
"Object.defineProperty(Array.prototype, 'includes', {",
|
||||
"value: function(searchElement, fromIndex) {",
|
||||
"if (this == null) {",
|
||||
"throw new TypeError('\"this\" is null or not defined');",
|
||||
"}",
|
||||
"// 1. Let O be ? ToObject(this value).",
|
||||
"var o = Object(this);",
|
||||
"// 2. Let len be ? ToLength(? Get(O, \"length\")).",
|
||||
"var len = o.length >>> 0;",
|
||||
"// 3. If len is 0, return false.",
|
||||
"if (len === 0) {",
|
||||
"return false;",
|
||||
"}",
|
||||
"// 4. Let n be ? ToInteger(fromIndex).",
|
||||
"// (If fromIndex is undefined, this step produces the value 0.)",
|
||||
"var n = fromIndex | 0;",
|
||||
"// 5. If n ≥ 0, then",
|
||||
"// a. Let k be n.",
|
||||
"// 6. Else n < 0,",
|
||||
"// a. Let k be len + n.",
|
||||
"// b. If k < 0, let k be 0.",
|
||||
"var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);",
|
||||
"function sameValueZero(x, y) {",
|
||||
"return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));",
|
||||
"}",
|
||||
"// 7. Repeat, while k < len",
|
||||
"while (k < len) {",
|
||||
"// a. Let elementK be the result of ? Get(O, ! ToString(k)).",
|
||||
"// b. If SameValueZero(searchElement, elementK) is true, return true.",
|
||||
"if (sameValueZero(o[k], searchElement)) {",
|
||||
"return true;",
|
||||
"}",
|
||||
"// c. Increase k by 1. ",
|
||||
"k++;",
|
||||
"}",
|
||||
"// 8. Return false",
|
||||
"return false;",
|
||||
"}",
|
||||
"});",
|
||||
|
||||
"(function() {",
|
||||
"var sort_ = Array.prototype.sort;",
|
||||
"Array.prototype.sort = function(opt_comp) {",
|
||||
@ -1203,6 +1298,43 @@ Interpreter.prototype.initString = function(scope) {
|
||||
"return str;",
|
||||
"};",
|
||||
"})();",
|
||||
|
||||
// Polyfill copied from:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
|
||||
"if (!String.prototype.endsWith) {",
|
||||
"String.prototype.endsWith = function(search, this_len) {",
|
||||
"if (this_len === undefined || this_len > this.length) {",
|
||||
"this_len = this.length;",
|
||||
"}",
|
||||
"return this.substring(this_len - search.length, this_len) === search;",
|
||||
"};",
|
||||
"}",
|
||||
|
||||
//Polyfill copied from:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes
|
||||
"if (!String.prototype.includes) {",
|
||||
"String.prototype.includes = function(search, start) {",
|
||||
"'use strict';",
|
||||
"if (typeof start !== 'number') {",
|
||||
"start = 0;",
|
||||
"}",
|
||||
" ",
|
||||
"if (start + search.length > this.length) {",
|
||||
"return false;",
|
||||
"} else {",
|
||||
"return this.indexOf(search, start) !== -1;",
|
||||
"}",
|
||||
"};",
|
||||
"}",
|
||||
|
||||
// Polyfill copied from:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
||||
"if (!String.prototype.startsWith) {",
|
||||
"String.prototype.startsWith = function(search, pos) {",
|
||||
"return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;",
|
||||
"};",
|
||||
"}",
|
||||
|
||||
"");
|
||||
};
|
||||
|
||||
@ -1994,13 +2126,18 @@ Interpreter.prototype.getPrototype = function(value) {
|
||||
* Fetch a property value from a data object.
|
||||
* @param {Interpreter.Value} obj Data object.
|
||||
* @param {Interpreter.Value} name Name of property.
|
||||
* @param {Acorn AST Node} node Node that triggered this function. Used by Bitburner for getting error line numbers
|
||||
* @return {Interpreter.Value} Property value (may be undefined).
|
||||
*/
|
||||
Interpreter.prototype.getProperty = function(obj, name) {
|
||||
Interpreter.prototype.getProperty = function(obj, name, node) {
|
||||
name = String(name);
|
||||
if (obj === undefined || obj === null) {
|
||||
let lineNum;
|
||||
if (node != null && node.loc != null && node.loc.start != null) {
|
||||
lineNum = node.loc.start.line;
|
||||
}
|
||||
this.throwException(this.TYPE_ERROR,
|
||||
"Cannot read property '" + name + "' of " + obj);
|
||||
"Cannot read property '" + name + "' of " + obj, lineNum);
|
||||
}
|
||||
if (name === 'length') {
|
||||
// Special cases for magic length property.
|
||||
@ -2294,11 +2431,12 @@ Interpreter.prototype.createSpecialScope = function(parentScope, opt_scope) {
|
||||
/**
|
||||
* Retrieves a value from the scope chain.
|
||||
* @param {string} name Name of variable.
|
||||
* @param {Acorn AST Node} node Node that triggered this function. Used by Bitburner for getting error line number
|
||||
* @return {Interpreter.Value} Any value.
|
||||
* May be flagged as being a getter and thus needing immediate execution
|
||||
* (rather than being the value of the property).
|
||||
*/
|
||||
Interpreter.prototype.getValueFromScope = function(name) {
|
||||
Interpreter.prototype.getValueFromScope = function(name, node) {
|
||||
var scope = this.getScope();
|
||||
while (scope && scope !== this.global) {
|
||||
if (name in scope.properties) {
|
||||
@ -2317,7 +2455,12 @@ Interpreter.prototype.getValueFromScope = function(name) {
|
||||
prevNode['operator'] === 'typeof') {
|
||||
return undefined;
|
||||
}
|
||||
this.throwException(this.REFERENCE_ERROR, name + ' is not defined');
|
||||
|
||||
var lineNum;
|
||||
if (node != null && node.loc != null && node.loc.start != null) {
|
||||
lineNum = node.loc.start.line;
|
||||
}
|
||||
this.throwException(this.REFERENCE_ERROR, name + ' is not defined', lineNum);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2426,17 +2569,18 @@ Interpreter.prototype.calledWithNew = function() {
|
||||
/**
|
||||
* Gets a value from the scope chain or from an object property.
|
||||
* @param {!Array} ref Name of variable or object/propname tuple.
|
||||
* @param {Acorn AST Node} node Node that triggered this function. Used by Bitburner for getting error line number
|
||||
* @return {Interpreter.Value} Any value.
|
||||
* May be flagged as being a getter and thus needing immediate execution
|
||||
* (rather than being the value of the property).
|
||||
*/
|
||||
Interpreter.prototype.getValue = function(ref) {
|
||||
Interpreter.prototype.getValue = function(ref, node) {
|
||||
if (ref[0] === Interpreter.SCOPE_REFERENCE) {
|
||||
// A null/varname variable lookup.
|
||||
return this.getValueFromScope(ref[1]);
|
||||
return this.getValueFromScope(ref[1], node);
|
||||
} else {
|
||||
// An obj/prop components tuple (foo.bar).
|
||||
return this.getProperty(ref[0], ref[1]);
|
||||
return this.getProperty(ref[0], ref[1], node);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2478,7 +2622,7 @@ Interpreter.prototype.setValue = function(ref, value) {
|
||||
* provided) or the value to throw (if no message).
|
||||
* @param {string=} opt_message Message being thrown.
|
||||
*/
|
||||
Interpreter.prototype.throwException = function(errorClass, opt_message) {
|
||||
Interpreter.prototype.throwException = function(errorClass, opt_message, lineNumber) {
|
||||
if (opt_message === undefined) {
|
||||
var error = errorClass; // This is a value to throw, not an error class.
|
||||
} else {
|
||||
@ -2486,7 +2630,11 @@ Interpreter.prototype.throwException = function(errorClass, opt_message) {
|
||||
this.setProperty(error, 'message', opt_message,
|
||||
Interpreter.NONENUMERABLE_DESCRIPTOR);
|
||||
}
|
||||
this.unwind(Interpreter.Completion.THROW, error, undefined);
|
||||
var lineNumErrorMsg;
|
||||
if (lineNumber != null) {
|
||||
lineNumErrorMsg = this.getErrorLineNumberMessage(lineNumber);
|
||||
}
|
||||
this.unwind(Interpreter.Completion.THROW, error, undefined, lineNumErrorMsg);
|
||||
// Abort anything related to the current step.
|
||||
throw Interpreter.STEP_ERROR;
|
||||
};
|
||||
@ -2500,7 +2648,7 @@ Interpreter.prototype.throwException = function(errorClass, opt_message) {
|
||||
* @param {Interpreter.Value=} value Value computed, returned or thrown.
|
||||
* @param {string=} label Target label for break or return.
|
||||
*/
|
||||
Interpreter.prototype.unwind = function(type, value, label) {
|
||||
Interpreter.prototype.unwind = function(type, value, label, lineNumberMsg="") {
|
||||
if (type === Interpreter.Completion.NORMAL) {
|
||||
throw TypeError('Should not unwind for NORMAL completions');
|
||||
}
|
||||
@ -2548,9 +2696,9 @@ Interpreter.prototype.unwind = function(type, value, label) {
|
||||
var name = this.getProperty(value, 'name').toString();
|
||||
var message = this.getProperty(value, 'message').valueOf();
|
||||
var type = errorTable[name] || Error;
|
||||
realError = type(message);
|
||||
realError = type(message + lineNumberMsg);
|
||||
} else {
|
||||
realError = String(value);
|
||||
realError = String(value) + lineNumberMsg;
|
||||
}
|
||||
throw realError;
|
||||
};
|
||||
@ -2656,7 +2804,7 @@ Interpreter.prototype['stepAssignmentExpression'] =
|
||||
state.leftValue_ = state.value;
|
||||
}
|
||||
if (!state.doneGetter_ && node['operator'] !== '=') {
|
||||
var leftValue = this.getValue(state.leftReference_);
|
||||
var leftValue = this.getValue(state.leftReference_, node);
|
||||
state.leftValue_ = leftValue;
|
||||
if (leftValue && typeof leftValue === 'object' && leftValue.isGetter) {
|
||||
// Clear the getter flag and call the getter function.
|
||||
@ -2742,15 +2890,17 @@ Interpreter.prototype['stepBinaryExpression'] = function(stack, state, node) {
|
||||
case '>>>': value = leftValue >>> rightValue; break;
|
||||
case 'in':
|
||||
if (!rightValue || !rightValue.isObject) {
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.TYPE_ERROR,
|
||||
"'in' expects an object, not '" + rightValue + "'");
|
||||
"'in' expects an object, not '" + rightValue + "'", lineNum);
|
||||
}
|
||||
value = this.hasProperty(rightValue, leftValue);
|
||||
break;
|
||||
case 'instanceof':
|
||||
if (!this.isa(rightValue, this.FUNCTION)) {
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.TYPE_ERROR,
|
||||
'Right-hand side of instanceof is not an object');
|
||||
'Right-hand side of instanceof is not an object', lineNum);
|
||||
}
|
||||
value = leftValue.isObject ? this.isa(leftValue, rightValue) : false;
|
||||
break;
|
||||
@ -2788,7 +2938,7 @@ Interpreter.prototype['stepCallExpression'] = function(stack, state, node) {
|
||||
state.doneCallee_ = 2;
|
||||
var func = state.value;
|
||||
if (Array.isArray(func)) {
|
||||
state.func_ = this.getValue(func);
|
||||
state.func_ = this.getValue(func, node);
|
||||
if (func[0] === Interpreter.SCOPE_REFERENCE) {
|
||||
// (Globally or locally) named function. Is it named 'eval'?
|
||||
state.directEval_ = (func[1] === 'eval');
|
||||
@ -2823,7 +2973,8 @@ Interpreter.prototype['stepCallExpression'] = function(stack, state, node) {
|
||||
if (node['type'] === 'NewExpression') {
|
||||
if (func.illegalConstructor) {
|
||||
// Illegal: new escape();
|
||||
this.throwException(this.TYPE_ERROR, func + ' is not a constructor');
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.TYPE_ERROR, func + ' is not a constructor', lineNum);
|
||||
}
|
||||
// Constructor, 'this' is new object.
|
||||
var proto = func.properties['prototype'];
|
||||
@ -2842,7 +2993,8 @@ Interpreter.prototype['stepCallExpression'] = function(stack, state, node) {
|
||||
if (!state.doneExec_) {
|
||||
state.doneExec_ = true;
|
||||
if (!func || !func.isObject) {
|
||||
this.throwException(this.TYPE_ERROR, func + ' is not a function');
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.TYPE_ERROR, func + ' is not a function', lineNum);
|
||||
}
|
||||
var funcNode = func.node;
|
||||
if (funcNode) {
|
||||
@ -2880,7 +3032,8 @@ Interpreter.prototype['stepCallExpression'] = function(stack, state, node) {
|
||||
var ast = acorn.parse(code.toString(), Interpreter.PARSE_OPTIONS);
|
||||
} catch (e) {
|
||||
// Acorn threw a SyntaxError. Rethrow as a trappable error.
|
||||
this.throwException(this.SYNTAX_ERROR, 'Invalid code: ' + e.message);
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.SYNTAX_ERROR, 'Invalid code: ' + e.message, lineNum);
|
||||
}
|
||||
var evalNode = new this.nodeConstructor();
|
||||
evalNode['type'] = 'EvalProgram_';
|
||||
@ -2917,7 +3070,8 @@ Interpreter.prototype['stepCallExpression'] = function(stack, state, node) {
|
||||
var f = new F();
|
||||
f();
|
||||
*/
|
||||
this.throwException(this.TYPE_ERROR, func.class + ' is not a function');
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.TYPE_ERROR, func.class + ' is not a function', lineNum);
|
||||
}
|
||||
} else {
|
||||
// Execution complete. Put the return value on the stack.
|
||||
@ -3032,8 +3186,9 @@ Interpreter.prototype['stepForInStatement'] = function(stack, state, node) {
|
||||
if (node['left']['declarations'] &&
|
||||
node['left']['declarations'][0]['init']) {
|
||||
if (state.scope.strict) {
|
||||
let lineNum = this.getErrorLineNumber(node);
|
||||
this.throwException(this.SYNTAX_ERROR,
|
||||
'for-in loop variable declaration may not have an initializer.');
|
||||
'for-in loop variable declaration may not have an initializer.', lineNum);
|
||||
}
|
||||
// Variable initialization: for (var x = 4 in y)
|
||||
return new Interpreter.State(node['left'], state.scope);
|
||||
@ -3193,7 +3348,7 @@ Interpreter.prototype['stepIdentifier'] = function(stack, state, node) {
|
||||
stack[stack.length - 1].value = [Interpreter.SCOPE_REFERENCE, node['name']];
|
||||
return;
|
||||
}
|
||||
var value = this.getValueFromScope(node['name']);
|
||||
var value = this.getValueFromScope(node['name'], node);
|
||||
// An identifier could be a getter if it's a property on the global object.
|
||||
if (value && typeof value === 'object' && value.isGetter) {
|
||||
// Clear the getter flag and call the getter function.
|
||||
@ -3428,7 +3583,7 @@ Interpreter.prototype['stepSwitchStatement'] = function(stack, state, node) {
|
||||
|
||||
Interpreter.prototype['stepThisExpression'] = function(stack, state, node) {
|
||||
stack.pop();
|
||||
stack[stack.length - 1].value = this.getValueFromScope('this');
|
||||
stack[stack.length - 1].value = this.getValueFromScope('this', node);
|
||||
};
|
||||
|
||||
Interpreter.prototype['stepThrowStatement'] = function(stack, state, node) {
|
||||
@ -3529,7 +3684,7 @@ Interpreter.prototype['stepUpdateExpression'] = function(stack, state, node) {
|
||||
state.leftValue_ = state.value;
|
||||
}
|
||||
if (!state.doneGetter_) {
|
||||
var leftValue = this.getValue(state.leftSide_);
|
||||
var leftValue = this.getValue(state.leftSide_, node);
|
||||
state.leftValue_ = leftValue;
|
||||
if (leftValue && typeof leftValue === 'object' && leftValue.isGetter) {
|
||||
// Clear the getter flag and call the getter function.
|
||||
|
@ -178,7 +178,25 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
}
|
||||
return Player.hacknetNodes[i];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} ram The amount of server RAM to calculate cost of.
|
||||
* @exception {Error} If the value passed in is not numeric, out of range, or too large of a value.
|
||||
* @returns {number} The cost of
|
||||
*/
|
||||
const getPurchaseServerRamCostGuard = (ram) => {
|
||||
const guardedRam = Math.round(ram);
|
||||
if (isNaN(guardedRam) || !powerOfTwo(guardedRam)) {
|
||||
throw Error("failed due to invalid ram argument. Must be numeric and a power of 2");
|
||||
}
|
||||
|
||||
if (guardedRam > CONSTANTS.PurchasedServerMaxRam) {
|
||||
throw Error("failed because specified RAM was too high. Maximum RAM on a purchased server is " + CONSTANTS.PurchasedServerMaxRam + "GB");
|
||||
}
|
||||
|
||||
return guardedRam * CONSTANTS.BaseCostFor1GBOfRamServer;
|
||||
};
|
||||
|
||||
return {
|
||||
hacknet : {
|
||||
@ -298,7 +316,13 @@ function NetscriptFunctions(workerScript) {
|
||||
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
||||
if (rand < hackChance) { //Success!
|
||||
const percentHacked = scriptCalculatePercentMoneyHacked(server);
|
||||
const maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax))
|
||||
let maxThreadNeeded = Math.ceil(1/percentHacked*(server.moneyAvailable/server.moneyMax));
|
||||
if (isNaN(maxThreadNeeded)) {
|
||||
//Server has a 'max money' of 0 (probably).
|
||||
//We'll set this to an arbitrarily large value
|
||||
maxThreadNeeded = 1e6;
|
||||
}
|
||||
|
||||
let moneyGained = Math.floor(server.moneyAvailable * percentHacked) * threads;
|
||||
|
||||
//Over-the-top safety checks
|
||||
@ -1591,6 +1615,22 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
return CONSTANTS.PurchasedServerMaxRam;
|
||||
},
|
||||
getPurchasedServerCost: function(ram) {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getPurchasedServerCost", CONSTANTS.ScriptGetPurchaseServerRamCost);
|
||||
}
|
||||
updateDynamicRam("getPurchasedServerCost", CONSTANTS.ScriptGetPurchaseServerRamCost);
|
||||
|
||||
let cost = 0;
|
||||
try {
|
||||
cost = getPurchaseServerRamCostGuard(ram);
|
||||
} catch (e) {
|
||||
workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' " + e.message);
|
||||
return "";
|
||||
}
|
||||
|
||||
return cost;
|
||||
},
|
||||
purchaseServer : function(hostname, ram) {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("purchaseServer", CONSTANTS.ScriptPurchaseServerRamCost);
|
||||
@ -1609,18 +1649,14 @@ function NetscriptFunctions(workerScript) {
|
||||
return "";
|
||||
}
|
||||
|
||||
ram = Math.round(ram);
|
||||
if (isNaN(ram) || !isPowerOfTwo(ram)) {
|
||||
workerScript.scriptRef.log("ERROR: purchaseServer() failed due to invalid ram argument. Must be numeric and a power of 2");
|
||||
let cost = 0;
|
||||
try {
|
||||
cost = getPurchaseServerRamCostGuard(ram);
|
||||
} catch (e) {
|
||||
workerScript.scriptRef.log("ERROR: 'purchaseServer()' " + e.message);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (ram > CONSTANTS.PurchasedServerMaxRam) {
|
||||
workerScript.scriptRef.log("ERROR: purchasedServer() failed because specified RAM was too high. Maximum RAM on a purchased server is " + CONSTANTS.PurchasedServerMaxRam + "GB");
|
||||
return "";
|
||||
}
|
||||
|
||||
var cost = ram * CONSTANTS.BaseCostFor1GBOfRamServer;
|
||||
if (Player.money.lt(cost)) {
|
||||
workerScript.scriptRef.log("ERROR: Not enough money to purchase server. Need $" + formatNumber(cost, 2));
|
||||
return "";
|
||||
@ -2106,6 +2142,13 @@ function NetscriptFunctions(workerScript) {
|
||||
yesNoBoxCreate(txt);
|
||||
});
|
||||
},
|
||||
getFavorToDonate: function() {
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getFavorToDonate", CONSTANTS.ScriptGetFavorToDonate);
|
||||
}
|
||||
updateDynamicRam("getFavorToDonate", CONSTANTS.ScriptGetFavorToDonate);
|
||||
return Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
},
|
||||
|
||||
/* Singularity Functions */
|
||||
universityCourse : function(universityName, className) {
|
||||
@ -2741,6 +2784,27 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
return company.favor;
|
||||
},
|
||||
getCompanyFavorGain : function(companyName) {
|
||||
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost / 4;
|
||||
if (Player.bitNodeN !== 4) {ramCost *= 8;}
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getCompanyFavorGain", ramCost);
|
||||
}
|
||||
updateDynamicRam("getCompanyFavorGain", ramCost);
|
||||
if (Player.bitNodeN != 4) {
|
||||
if (!(hasSingularitySF && singularitySFLvl >= 2)) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Cannot run getCompanyFavorGain(). It is a Singularity Function and requires SourceFile-4 (level 2) to run.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
var company = Companies[companyName];
|
||||
if (company == null || !(company instanceof Company)) {
|
||||
workerScript.scriptRef.log("ERROR: Invalid companyName passed into getCompanyFavorGain(): " + companyName);
|
||||
return -1;
|
||||
}
|
||||
return company.getFavorGain()[0];
|
||||
},
|
||||
checkFactionInvitations : function() {
|
||||
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
|
||||
if (Player.bitNodeN !== 4) {ramCost *= 8;}
|
||||
@ -2938,6 +3002,27 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
return Factions[name].favor;
|
||||
},
|
||||
getFactionFavorGain: function(name){
|
||||
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
|
||||
if (Player.bitNodeN !== 4) {ramCost *= 8;}
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getFactionFavorGain", ramCost);
|
||||
}
|
||||
updateDynamicRam("getFactionFavorGain", ramCost);
|
||||
if (Player.bitNodeN != 4) {
|
||||
if (!(hasSingularitySF && singularitySFLvl >= 2)) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Cannot run getFactionFavorGain(). It is a Singularity Function and requires SourceFile-4 (level 2) to run.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!factionExists(name)) {
|
||||
workerScript.scriptRef.log("ERROR: Faction specified in getFactionFavorGain() does not exist.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Factions[name].getFavorGain()[0];
|
||||
},
|
||||
createProgram : function(name) {
|
||||
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
|
||||
if (Player.bitNodeN !== 4) {ramCost *= 8;}
|
||||
@ -3042,7 +3127,7 @@ function NetscriptFunctions(workerScript) {
|
||||
|
||||
const crime = findCrime(crimeRoughName.toLowerCase());
|
||||
if(crime == null) { // couldn't find crime
|
||||
throw makeRuntimeRejectMsg(workerScript, "Invalid crime passed into commitCrime(): " + crime);
|
||||
throw makeRuntimeRejectMsg(workerScript, "Invalid crime passed into commitCrime(): " + crimeRoughName);
|
||||
}
|
||||
if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.commitCrime == null) {
|
||||
workerScript.scriptRef.log("Attempting to commit crime: "+crime.name+"...");
|
||||
@ -3094,6 +3179,25 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getOwnedSourceFiles : function() {
|
||||
let ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
|
||||
if (Player.bitNodeN !== 4) {ramCost *= 8;}
|
||||
if (workerScript.checkingRam) {
|
||||
return updateStaticRam("getOwnedSourceFiles", ramCost);
|
||||
}
|
||||
updateDynamicRam("getOwnedSourceFiles", ramCost);
|
||||
if (Player.bitNodeN != 4) {
|
||||
if (!(hasSingularitySF && singularitySFLvl >= 3)) {
|
||||
throw makeRuntimeRejectMsg(workerScript, "Cannot run getOwnedSourceFiles(). It is a Singularity Function and requires SourceFile-4 (level 3) to run.");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
let res = [];
|
||||
for (let i = 0; i < Player.sourceFiles.length; ++i) {
|
||||
res.push({n: Player.sourceFiles[i].n, lvl: Player.sourceFiles[i].lvl});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getAugmentationsFromFaction : function(facname) {
|
||||
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
|
||||
if (Player.bitNodeN !== 4) {ramCost *= 8;}
|
||||
|
@ -39,8 +39,7 @@ export async function executeJSScript(scripts = [], workerScript) {
|
||||
// TODO: putting await in a non-async function yields unhelpful
|
||||
// "SyntaxError: unexpected reserved word" with no line number information.
|
||||
if (!loadedModule.main) {
|
||||
throw makeRuntimeRejectMsg(script.filename +
|
||||
" did not have a main function, cannot run it.");
|
||||
throw makeRuntimeRejectMsg(workerScript, `${script.filename} cannot be run because it does not have a main function.`);
|
||||
}
|
||||
return loadedModule.main(ns);
|
||||
} finally {
|
||||
|
@ -166,9 +166,11 @@ function startNetscript1Script(workerScript) {
|
||||
workerScript.running = true;
|
||||
|
||||
//Process imports
|
||||
var ast;
|
||||
var codeWithImports, codeLineOffset;
|
||||
try {
|
||||
ast = processNetscript1Imports(code, workerScript);
|
||||
let importProcessingRes = processNetscript1Imports(code, workerScript);
|
||||
codeWithImports = importProcessingRes.code;
|
||||
codeLineOffset = importProcessingRes.lineOffset;
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Error processing Imports in " + workerScript.name + ":<br>" + e);
|
||||
workerScript.env.stopFlag = true;
|
||||
@ -197,6 +199,23 @@ function startNetscript1Script(workerScript) {
|
||||
});
|
||||
}
|
||||
int.setProperty(scope, name, int.createAsyncFunction(tempWrapper));
|
||||
} else if (name === "sprintf" || name === "vsprintf" || name === "scp") {
|
||||
let tempWrapper = function() {
|
||||
let fnArgs = [];
|
||||
|
||||
//All of the Object/array elements are in JSInterpreter format, so
|
||||
//we have to convert them back to native format to pass them to these fns
|
||||
for (let i = 0; i < arguments.length; ++i) {
|
||||
if (typeof arguments[i] === 'object' || arguments[i].constructor === Array) {
|
||||
fnArgs.push(int.pseudoToNative(arguments[i]));
|
||||
} else {
|
||||
fnArgs.push(arguments[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return entry.apply(null, fnArgs);
|
||||
}
|
||||
int.setProperty(scope, name, int.createNativeFunction(tempWrapper));
|
||||
} else {
|
||||
let tempWrapper = function() {
|
||||
let res = entry.apply(null, arguments);
|
||||
@ -205,7 +224,6 @@ function startNetscript1Script(workerScript) {
|
||||
return res;
|
||||
} else if (res.constructor === Array || (res === Object(res))) {
|
||||
//Objects and Arrays must be converted to the interpreter's format
|
||||
console.log("Function returning object detected: " + name);
|
||||
return int.nativeToPseudo(res);
|
||||
} else {
|
||||
return res;
|
||||
@ -225,7 +243,7 @@ function startNetscript1Script(workerScript) {
|
||||
|
||||
var interpreter;
|
||||
try {
|
||||
interpreter = new Interpreter(ast, interpreterInitialization);
|
||||
interpreter = new Interpreter(codeWithImports, interpreterInitialization, codeLineOffset);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Syntax ERROR in " + workerScript.name + ":<br>" + e);
|
||||
workerScript.env.stopFlag = true;
|
||||
@ -273,7 +291,11 @@ function startNetscript1Script(workerScript) {
|
||||
we'll implement it ourselves by parsing the Nodes in the AST out.
|
||||
|
||||
@param code - The script's code
|
||||
@returns - ES5-compliant AST with properly imported functions
|
||||
@returns {Object} {
|
||||
code: Newly-generated code with imported functions
|
||||
lineOffset: Net number of lines of code added/removed due to imported functions
|
||||
Should typically be positive
|
||||
}
|
||||
*/
|
||||
function processNetscript1Imports(code, workerScript) {
|
||||
//allowReserved prevents 'import' from throwing error in ES5
|
||||
@ -294,10 +316,12 @@ function processNetscript1Imports(code, workerScript) {
|
||||
}
|
||||
|
||||
var generatedCode = ""; //Generated Javascript Code
|
||||
var hasImports = false;
|
||||
|
||||
//Walk over the tree and process ImportDeclaration nodes
|
||||
walk.simple(ast, {
|
||||
ImportDeclaration: (node) => {
|
||||
hasImports = true;
|
||||
let scriptName = node.source.value;
|
||||
let script = getScript(scriptName);
|
||||
if (script == null) {
|
||||
@ -336,7 +360,7 @@ function processNetscript1Imports(code, workerScript) {
|
||||
|
||||
//Finish
|
||||
generatedCode += (
|
||||
"})(" + namespace + " || " + "(" + namespace + " = {}));"
|
||||
"})(" + namespace + " || " + "(" + namespace + " = {}));\n"
|
||||
)
|
||||
} else {
|
||||
//import {...} from script
|
||||
@ -366,22 +390,34 @@ function processNetscript1Imports(code, workerScript) {
|
||||
}
|
||||
});
|
||||
|
||||
//If there are no imports, just return the original code
|
||||
if (!hasImports) {return {code:code, lineOffset:0};}
|
||||
|
||||
//Remove ImportDeclarations from AST. These ImportDeclarations must be in top-level
|
||||
var linesRemoved = 0;
|
||||
if (ast.type !== "Program" || ast.body == null) {
|
||||
throw new Error("Code could not be properly parsed");
|
||||
}
|
||||
for (let i = ast.body.length-1; i >= 0; --i) {
|
||||
if (ast.body[i].type === "ImportDeclaration") {
|
||||
ast.body.splice(i, 1);
|
||||
++linesRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
//Calculated line offset
|
||||
var lineOffset = (generatedCode.match(/\n/g) || []).length - linesRemoved;
|
||||
|
||||
//Convert the AST back into code
|
||||
code = generate(ast);
|
||||
|
||||
//Add the imported code and re-generate in ES5 (JS Interpreter for NS1 only supports ES5);
|
||||
code = generatedCode + code;
|
||||
return parse(code, {ecmaVersion:5});
|
||||
var res = {
|
||||
code: code,
|
||||
lineOffset: lineOffset
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//Loop through workerScripts and run every script that is not currently running
|
||||
|
@ -435,7 +435,7 @@ PlayerObject.prototype.calculateSkill = function(exp, mult=1) {
|
||||
}
|
||||
|
||||
PlayerObject.prototype.updateSkillLevels = function() {
|
||||
this.hacking_skill = Math.max(1, Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult) * BitNodeMultipliers.HackingLevelMultiplier));
|
||||
this.hacking_skill = Math.max(1, Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
|
||||
this.strength = this.calculateSkill(this.strength_exp, this.strength_mult);
|
||||
this.defense = this.calculateSkill(this.defense_exp, this.defense_mult);
|
||||
this.dexterity = this.calculateSkill(this.dexterity_exp, this.dexterity_mult);
|
||||
|
@ -24,12 +24,12 @@ import {iTutorialSteps, iTutorialNextStep,
|
||||
iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial";
|
||||
import {evaluateImport} from "./NetscriptEvaluator";
|
||||
import {NetscriptFunctions} from "./NetscriptFunctions";
|
||||
import {addWorkerScript, killWorkerScript,
|
||||
import {addWorkerScript,
|
||||
WorkerScript} from "./NetscriptWorker";
|
||||
import {Player} from "./Player";
|
||||
import {AllServers, processSingleServerGrowth} from "./Server";
|
||||
import {Settings} from "./Settings";
|
||||
import {post, Terminal} from "./Terminal";
|
||||
import {post} from "./Terminal";
|
||||
import {TextFile} from "./TextFile";
|
||||
|
||||
import {parse, Node} from "../utils/acorn";
|
||||
@ -39,6 +39,7 @@ import {Reviver, Generic_toJSON,
|
||||
import {compareArrays} from "../utils/helpers/compareArrays";
|
||||
import {createElement} from "../utils/uiHelpers/createElement";
|
||||
import {formatNumber} from "../utils/StringHelperFunctions";
|
||||
import {getTimestamp} from "../utils/helpers/getTimestamp";
|
||||
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
||||
|
||||
var keybindings = {
|
||||
@ -962,7 +963,7 @@ RunningScript.prototype.log = function(txt) {
|
||||
}
|
||||
let logEntry = txt;
|
||||
if (FconfSettings.ENABLE_TIMESTAMPS) {
|
||||
logEntry = "[" + Terminal.getTimestamp() + "] " + logEntry;
|
||||
logEntry = "[" + getTimestamp() + "] " + logEntry;
|
||||
}
|
||||
this.logs.push(logEntry);
|
||||
this.logUpd = true;
|
||||
|
266
src/Terminal.js
266
src/Terminal.js
@ -38,6 +38,7 @@ import {containsAllStrings, longestCommonStart,
|
||||
import {addOffset} from "../utils/helpers/addOffset";
|
||||
import {isString} from "../utils/helpers/isString";
|
||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||
import {getTimestamp} from "../utils/helpers/getTimestamp";
|
||||
import {logBoxCreate} from "../utils/LogBox";
|
||||
import {yesNoBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
@ -115,7 +116,7 @@ $(document).keydown(function(event) {
|
||||
if (command.length > 0) {
|
||||
post(
|
||||
"[" +
|
||||
(FconfSettings.ENABLE_TIMESTAMPS ? Terminal.getTimestamp() + " " : "") +
|
||||
(FconfSettings.ENABLE_TIMESTAMPS ? getTimestamp() + " " : "") +
|
||||
Player.getCurrentServer().hostname +
|
||||
" ~]> " + command
|
||||
);
|
||||
@ -646,11 +647,6 @@ let Terminal = {
|
||||
}
|
||||
},
|
||||
|
||||
getTimestamp: function() {
|
||||
let d = new Date();
|
||||
return (d.getMonth() + "/" + d.getDay() + " " + d.getHours() + ":" + d.getMinutes());
|
||||
},
|
||||
|
||||
finishAction: function(cancelled = false) {
|
||||
if (Terminal.hackFlag) {
|
||||
Terminal.finishHack(cancelled);
|
||||
@ -1831,97 +1827,124 @@ let Terminal = {
|
||||
if (splitArgs.length > 1) {
|
||||
programName = splitArgs[0];
|
||||
}
|
||||
switch (programName) {
|
||||
case Programs.NukeProgram.name:
|
||||
if (s.hasAdminRights) {
|
||||
post("You already have root access to this computer. There is no reason to run NUKE.exe");
|
||||
} else {
|
||||
if (s.openPortCount >= Player.getCurrentServer().numOpenPortsRequired) {
|
||||
s.hasAdminRights = true;
|
||||
post("NUKE successful! Gained root access to " + Player.getCurrentServer().hostname);
|
||||
//TODO Make this take time rather than be instant
|
||||
} else {
|
||||
post("NUKE unsuccessful. Not enough ports have been opened");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Programs.BruteSSHProgram.name:
|
||||
if (s.sshPortOpen) {
|
||||
post("SSH Port (22) is already open!");
|
||||
} else {
|
||||
s.sshPortOpen = true;
|
||||
post("Opened SSH Port(22)!")
|
||||
++s.openPortCount;
|
||||
}
|
||||
break;
|
||||
case Programs.FTPCrackProgram.name:
|
||||
if (s.ftpPortOpen) {
|
||||
post("FTP Port (21) is already open!");
|
||||
} else {
|
||||
s.ftpPortOpen = true;
|
||||
post("Opened FTP Port (21)!");
|
||||
++s.openPortCount;
|
||||
}
|
||||
break;
|
||||
case Programs.RelaySMTPProgram.name:
|
||||
if (s.smtpPortOpen) {
|
||||
post("SMTP Port (25) is already open!");
|
||||
} else {
|
||||
s.smtpPortOpen = true;
|
||||
post("Opened SMTP Port (25)!");
|
||||
++s.openPortCount;
|
||||
}
|
||||
break;
|
||||
case Programs.HTTPWormProgram.name:
|
||||
if (s.httpPortOpen) {
|
||||
post("HTTP Port (80) is already open!");
|
||||
} else {
|
||||
s.httpPortOpen = true;
|
||||
post("Opened HTTP Port (80)!");
|
||||
++s.openPortCount;
|
||||
}
|
||||
break;
|
||||
case Programs.SQLInjectProgram.name:
|
||||
if (s.sqlPortOpen) {
|
||||
post("SQL Port (1433) is already open!");
|
||||
} else {
|
||||
s.sqlPortOpen = true;
|
||||
post("Opened SQL Port (1433)!");
|
||||
++s.openPortCount;
|
||||
}
|
||||
break;
|
||||
case Programs.ServerProfiler.name:
|
||||
if (splitArgs.length != 2) {
|
||||
post("Must pass a server hostname or IP as an argument for ServerProfiler.exe");
|
||||
return;
|
||||
}
|
||||
var serv = getServer(splitArgs[1]);
|
||||
if (serv == null) {
|
||||
post("Invalid server IP/hostname");
|
||||
return;
|
||||
}
|
||||
post(serv.hostname + ":");
|
||||
post("Server base security level: " + serv.baseDifficulty);
|
||||
post("Server current security level: " + serv.hackDifficulty);
|
||||
post("Server growth rate: " + serv.serverGrowth);
|
||||
post("Netscript hack() execution time: " + formatNumber(scriptCalculateHackingTime(serv), 1) + "s");
|
||||
post("Netscript grow() execution time: " + formatNumber(scriptCalculateGrowTime(serv)/1000, 1) + "s");
|
||||
post("Netscript weaken() execution time: " + formatNumber(scriptCalculateWeakenTime(serv)/1000, 1) + "s");
|
||||
break;
|
||||
case Programs.AutoLink.name:
|
||||
post("This executable cannot be run.");
|
||||
post("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'.");
|
||||
post("When using scan-analyze, click on a server's hostname to connect to it.");
|
||||
break;
|
||||
case Programs.DeepscanV1.name:
|
||||
post("This executable cannot be run.");
|
||||
post("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5.");
|
||||
break;
|
||||
case Programs.DeepscanV2.name:
|
||||
post("This executable cannot be run.");
|
||||
post("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10.");
|
||||
break;
|
||||
case Programs.Flight.name:
|
||||
|
||||
// TODO: refactor this/these out of Terminal. This logic could reside closer to the Programs themselves.
|
||||
/**
|
||||
* @typedef {function (server=, args=)} ProgramHandler
|
||||
* @param {Server} server The current server the program is being executed against
|
||||
* @param {string[]} args The command line arguments passed in to the program
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* @type {Object.<string, ProgramHandler}
|
||||
*/
|
||||
const programHandlers = {};
|
||||
programHandlers[Programs.NukeProgram.name] = (server) => {
|
||||
if (server.hasAdminRights) {
|
||||
post("You already have root access to this computer. There is no reason to run NUKE.exe");
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.openPortCount >= Player.getCurrentServer().numOpenPortsRequired) {
|
||||
server.hasAdminRights = true;
|
||||
post("NUKE successful! Gained root access to " + Player.getCurrentServer().hostname);
|
||||
// TODO: Make this take time rather than be instant
|
||||
return;
|
||||
}
|
||||
|
||||
post("NUKE unsuccessful. Not enough ports have been opened");
|
||||
};
|
||||
programHandlers[Programs.BruteSSHProgram.name] = (server) => {
|
||||
if (server.sshPortOpen) {
|
||||
post("SSH Port (22) is already open!");
|
||||
return;
|
||||
}
|
||||
|
||||
server.sshPortOpen = true;
|
||||
post("Opened SSH Port(22)!")
|
||||
server.openPortCount++;
|
||||
};
|
||||
programHandlers[Programs.FTPCrackProgram.name] = (server) => {
|
||||
if (server.ftpPortOpen) {
|
||||
post("FTP Port (21) is already open!");
|
||||
return;
|
||||
}
|
||||
|
||||
server.ftpPortOpen = true;
|
||||
post("Opened FTP Port (21)!");
|
||||
server.openPortCount++;
|
||||
};
|
||||
programHandlers[Programs.RelaySMTPProgram.name] = (server) => {
|
||||
if (server.smtpPortOpen) {
|
||||
post("SMTP Port (25) is already open!");
|
||||
return;
|
||||
}
|
||||
|
||||
server.smtpPortOpen = true;
|
||||
post("Opened SMTP Port (25)!");
|
||||
server.openPortCount++;
|
||||
};
|
||||
programHandlers[Programs.HTTPWormProgram.name] = (server) => {
|
||||
if (serv.httpPortOpen) {
|
||||
post("HTTP Port (80) is already open!");
|
||||
return;
|
||||
}
|
||||
|
||||
server.httpPortOpen = true;
|
||||
post("Opened HTTP Port (80)!");
|
||||
server.openPortCount++;
|
||||
};
|
||||
programHandlers[Programs.SQLInjectProgram.name] = (server) => {
|
||||
if (server.sqlPortOpen) {
|
||||
post("SQL Port (1433) is already open!");
|
||||
return;
|
||||
}
|
||||
|
||||
server.sqlPortOpen = true;
|
||||
post("Opened SQL Port (1433)!");
|
||||
server.openPortCount++;
|
||||
};
|
||||
programHandlers[Programs.ServerProfiler.name] = (server, args) => {
|
||||
if (args.length !== 2) {
|
||||
post("Must pass a server hostname or IP as an argument for ServerProfiler.exe");
|
||||
return;
|
||||
}
|
||||
|
||||
const targetServer = getServer(args[1]);
|
||||
if (targetServer == null) {
|
||||
post("Invalid server IP/hostname");
|
||||
return;
|
||||
}
|
||||
post(targetServer.hostname + ":");
|
||||
post("Server base security level: " + targetServer.baseDifficulty);
|
||||
post("Server current security level: " + targetServer.hackDifficulty);
|
||||
post("Server growth rate: " + targetServer.serverGrowth);
|
||||
post("Netscript hack() execution time: " + formatNumber(scriptCalculateHackingTime(targetServer), 1) + "s");
|
||||
post("Netscript grow() execution time: " + formatNumber(scriptCalculateGrowTime(targetServer)/1000, 1) + "s");
|
||||
post("Netscript weaken() execution time: " + formatNumber(scriptCalculateWeakenTime(targetServer)/1000, 1) + "s");
|
||||
};
|
||||
programHandlers[Programs.AutoLink.name] = () => {
|
||||
post("This executable cannot be run.");
|
||||
post("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'.");
|
||||
post("When using scan-analyze, click on a server's hostname to connect to it.");
|
||||
};
|
||||
programHandlers[Programs.DeepscanV1.name] = () => {
|
||||
post("This executable cannot be run.");
|
||||
post("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5.");
|
||||
};
|
||||
programHandlers[Programs.DeepscanV2.name] = () => {
|
||||
post("This executable cannot be run.");
|
||||
post("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10.");
|
||||
};
|
||||
programHandlers[Programs.Flight.name] = () => {
|
||||
const fulfilled = Player.augmentations.length >= 30 &&
|
||||
Player.money.gt(1e11) &&
|
||||
((Player.hacking_skill >= 2500)||
|
||||
(Player.strength >= 1500 &&
|
||||
Player.defense >= 1500 &&
|
||||
Player.dexterity >= 1500 &&
|
||||
Player.agility >= 1500));
|
||||
if(!fulfilled) {
|
||||
post("Augmentations: " + Player.augmentations.length + " / 30");
|
||||
|
||||
post("Money: " + numeral(Player.money.toNumber()).format('($0.000a)') + " / " + numeral(1e11).format('($0.000a)'));
|
||||
@ -1933,28 +1956,35 @@ let Terminal = {
|
||||
post("Defense: " + Player.defense + " / 1500");
|
||||
post("Dexterity: " + Player.dexterity + " / 1500");
|
||||
post("Agility: " + Player.agility + " / 1500");
|
||||
break;
|
||||
case Programs.BitFlume.name:
|
||||
var yesBtn = yesNoBoxGetYesButton(),
|
||||
noBtn = yesNoBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Travel to BitNode Nexus";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
hackWorldDaemon(Player.bitNodeN, true);
|
||||
return yesNoBoxClose();
|
||||
});
|
||||
noBtn.addEventListener("click", function() {
|
||||
return yesNoBoxClose();
|
||||
});
|
||||
yesNoBoxCreate("WARNING: USING THIS PROGRAM WILL CAUSE YOU TO LOSE ALL OF YOUR PROGRESS ON THE CURRENT BITNODE.<br><br>" +
|
||||
"Do you want to travel to the BitNode Nexus? This allows you to reset the current BitNode " +
|
||||
"and select a new one.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
post("Invalid executable. Cannot be run");
|
||||
return;
|
||||
}
|
||||
post("We will contact you.");
|
||||
post("-- Daedalus --");
|
||||
};
|
||||
programHandlers[Programs.BitFlume.name] = () => {
|
||||
const yesBtn = yesNoBoxGetYesButton();
|
||||
const noBtn = yesNoBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Travel to BitNode Nexus";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", function() {
|
||||
hackWorldDaemon(Player.bitNodeN, true);
|
||||
return yesNoBoxClose();
|
||||
});
|
||||
noBtn.addEventListener("click", function() {
|
||||
return yesNoBoxClose();
|
||||
});
|
||||
yesNoBoxCreate("WARNING: USING THIS PROGRAM WILL CAUSE YOU TO LOSE ALL OF YOUR PROGRESS ON THE CURRENT BITNODE.<br><br>" +
|
||||
"Do you want to travel to the BitNode Nexus? This allows you to reset the current BitNode " +
|
||||
"and select a new one.");
|
||||
};
|
||||
|
||||
if (!programHandlers.hasOwnProperty(programName)){
|
||||
post("Invalid executable. Cannot be run");
|
||||
return;
|
||||
}
|
||||
|
||||
programHandlers[programName](s, splitArgs);
|
||||
},
|
||||
|
||||
runScript: function(scriptName) {
|
||||
|
@ -65,6 +65,19 @@ import {StockMarket, StockSymbols,
|
||||
displayStockMarketContent} from "./StockMarket";
|
||||
import {Terminal, postNetburnerText, post, KEY} from "./Terminal";
|
||||
|
||||
// These should really be imported with the module that is presenting that UI, but because they very much depend on the
|
||||
// cascade order, we'll pull them all in here.
|
||||
import "../css/styles.scss";
|
||||
import "../css/terminal.scss";
|
||||
import "../css/menupages.scss";
|
||||
import "../css/workinprogress.scss";
|
||||
import "../css/popupboxes.scss";
|
||||
import "../css/interactivetutorial.scss";
|
||||
import "../css/loader.scss";
|
||||
import "../css/missions.scss";
|
||||
import "../css/companymanagement.scss";
|
||||
import "../css/bladeburner.scss";
|
||||
|
||||
/* Shortcuts to navigate through the game
|
||||
* Alt-t - Terminal
|
||||
* Alt-c - Character
|
||||
@ -570,6 +583,16 @@ let Engine = {
|
||||
overviewText += "<br>Int: " + (Player.intelligence).toLocaleString();
|
||||
}
|
||||
document.getElementById("character-overview-text").innerHTML = overviewText.replace( / /g, " ");
|
||||
|
||||
|
||||
|
||||
const save = document.getElementById("character-overview-save-button");
|
||||
const flashClass = "flashing-button";
|
||||
if(!Settings.AutosaveInterval) {
|
||||
save.classList.add(flashClass);
|
||||
} else {
|
||||
save.classList.remove(flashClass);
|
||||
}
|
||||
},
|
||||
|
||||
/* Display character info */
|
||||
@ -1646,12 +1669,12 @@ let Engine = {
|
||||
Engine.Clickables.devMenuProgramsDropdown = document.getElementById("dev-menu-add-program-dropdown");
|
||||
const programsDD = Engine.Clickables.devMenuProgramsDropdown;
|
||||
for(const i in Programs) {
|
||||
programsDD.options[programsDD.options.length] = new Option(Programs[i], Programs[i]);
|
||||
programsDD.options[programsDD.options.length] = new Option(Programs[i].name, Programs[i].name);
|
||||
}
|
||||
|
||||
Engine.Clickables.devMenuAddProgram = document.getElementById("dev-add-program");
|
||||
Engine.Clickables.devMenuAddProgram.addEventListener("click", function() {
|
||||
const program = programsDD.options[programsDD.selectedIndex].value;;
|
||||
const program = programsDD.options[programsDD.selectedIndex].value;
|
||||
if(!Player.hasProgram(program)) {
|
||||
Player.getHomeComputer().programs.push(program);
|
||||
}
|
||||
|
@ -130,13 +130,17 @@ module.exports = {
|
||||
"no-missing-end-of-source-newline": true,
|
||||
"no-unknown-animations": true,
|
||||
"number-leading-zero": "always",
|
||||
"number-max-precision": [3, { ignoreUnits: [ "%" ] }],
|
||||
"number-max-precision": [4, { ignoreUnits: [ "%" ] }],
|
||||
// "number-no-trailing-zeros": true,
|
||||
"order/order": [
|
||||
[
|
||||
"dollar-variables",
|
||||
"at-variables",
|
||||
"custom-properties",
|
||||
{
|
||||
type: "at-rule",
|
||||
name: "extend"
|
||||
},
|
||||
{
|
||||
type: "at-rule",
|
||||
name: "include"
|
||||
|
9
utils/helpers/getTimestamp.ts
Normal file
9
utils/helpers/getTimestamp.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export function getTimestamp() {
|
||||
const d: Date = new Date();
|
||||
// A negative slice value takes from the end of the string rather than the beginning.
|
||||
const stringWidth: number = -2;
|
||||
const formattedHours: string = `0${d.getHours()}`.slice(stringWidth);
|
||||
const formattedMinutes: string = `0${d.getMinutes()}`.slice(stringWidth);
|
||||
|
||||
return `${d.getMonth() + 1}/${d.getDate()} ${formattedHours}:${formattedMinutes}`;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
var MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
|
||||
module.exports = (env, argv) => ({
|
||||
plugins: [
|
||||
@ -14,6 +15,10 @@ module.exports = (env, argv) => ({
|
||||
jquery: "jquery",
|
||||
jQuery: "jquery",
|
||||
$: "jquery"
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
chunkFilename: "[id].css"
|
||||
})
|
||||
],
|
||||
target: "web",
|
||||
@ -32,7 +37,15 @@ module.exports = (env, argv) => ({
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
"css-loader",
|
||||
"sass-loader"
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
|
Reference in New Issue
Block a user