mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-17 14:59:16 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52a80ad236 | ||
|
|
b2aafea656 | ||
|
|
135df8703c | ||
|
|
4743801e86 | ||
|
|
4e5ebcfe6f | ||
|
|
80b703639e | ||
|
|
0afdba8f38 |
257
.eslintrc.js
257
.eslintrc.js
@@ -2,91 +2,104 @@ module.exports = {
|
|||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"commonjs": true,
|
"commonjs": true,
|
||||||
"es6": false
|
"es6": false,
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 8,
|
"ecmaVersion": 8,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"experimentalObjectRestSpread": true
|
"experimentalObjectRestSpread": true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
"plugins": [
|
||||||
|
'@typescript-eslint',
|
||||||
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"accessor-pairs": [
|
"accessor-pairs": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"setWithoutGet": true,
|
"setWithoutGet": true,
|
||||||
"getWithoutSet": false
|
"getWithoutSet": false,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"array-bracket-newline": [
|
"array-bracket-newline": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"array-bracket-spacing": [
|
"array-bracket-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"array-callback-return": [
|
"array-callback-return": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"array-element-newline": [
|
"array-element-newline": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"arrow-body-style": [
|
"arrow-body-style": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"arrow-parens": [
|
"arrow-parens": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"arrow-spacing": [
|
"arrow-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"block-scoped-var": [
|
"block-scoped-var": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"block-spacing": [
|
"block-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"brace-style": [
|
"brace-style": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"callback-return": [
|
"callback-return": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"camelcase": [
|
"camelcase": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"capitalized-comments": [
|
"capitalized-comments": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"class-methods-use-this": [
|
"class-methods-use-this": [
|
||||||
"error"
|
"off",
|
||||||
],
|
],
|
||||||
"comma-dangle": [
|
"comma-dangle": [
|
||||||
"off"
|
"error", {
|
||||||
|
"arrays": "always-multiline",
|
||||||
|
"objects": "always-multiline",
|
||||||
|
"imports": "always-multiline",
|
||||||
|
"exports": "always-multiline",
|
||||||
|
"functions": "always-multiline",
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"comma-spacing": [
|
"comma-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"comma-style": [
|
"comma-style": [
|
||||||
"error",
|
"error",
|
||||||
"last"
|
"last",
|
||||||
],
|
],
|
||||||
"complexity": [
|
"complexity": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"computed-property-spacing": [
|
"computed-property-spacing": [
|
||||||
"off",
|
"off",
|
||||||
"never"
|
"never",
|
||||||
],
|
],
|
||||||
"consistent-return": [
|
"consistent-return": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"consistent-this": [
|
"consistent-this": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"constructor-super": [
|
"constructor-super": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"curly": [
|
"curly": [
|
||||||
"off"
|
"off"
|
||||||
@@ -99,203 +112,202 @@ module.exports = {
|
|||||||
"property"
|
"property"
|
||||||
],
|
],
|
||||||
"dot-notation": [
|
"dot-notation": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"eol-last": [
|
"eol-last": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"eqeqeq": [
|
"eqeqeq": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"for-direction": [
|
"for-direction": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"func-call-spacing": [
|
"func-call-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"func-name-matching": [
|
"func-name-matching": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"func-names": [
|
"func-names": [
|
||||||
"off",
|
"off",
|
||||||
"never"
|
"never",
|
||||||
],
|
],
|
||||||
"func-style": [
|
"func-style": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"function-paren-newline": [
|
"function-paren-newline": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"generator-star-spacing": [
|
"generator-star-spacing": [
|
||||||
"error",
|
"error",
|
||||||
"before"
|
"before",
|
||||||
],
|
],
|
||||||
"getter-return": [
|
"getter-return": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"allowImplicit": false
|
"allowImplicit": false,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"global-require": [
|
"global-require": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"guard-for-in": [
|
"guard-for-in": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"handle-callback-err": [
|
"handle-callback-err": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"id-blacklist": [
|
"id-blacklist": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"id-length": [
|
"id-length": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"id-match": [
|
"id-match": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"implicit-arrow-linebreak": [
|
"implicit-arrow-linebreak": [
|
||||||
"error",
|
"error",
|
||||||
"beside"
|
"beside",
|
||||||
],
|
],
|
||||||
"indent": [
|
"indent": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"indent-legacy": [
|
"indent-legacy": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"init-declarations": [
|
"init-declarations": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"jsx-quotes": [
|
"jsx-quotes": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"key-spacing": [
|
"key-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"keyword-spacing": [
|
"keyword-spacing": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"line-comment-position": [
|
"line-comment-position": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"linebreak-style": [
|
"linebreak-style": [
|
||||||
"error",
|
"off", // Line endings automatically converted to LF on git commit so probably shouldn't care about it here
|
||||||
"windows"
|
|
||||||
],
|
],
|
||||||
"lines-around-comment": [
|
"lines-around-comment": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"lines-around-directive": [
|
"lines-around-directive": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"lines-between-class-members": [
|
"lines-between-class-members": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"max-depth": [
|
"max-depth": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"max-len": [
|
"max-len": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"max-lines": [
|
"max-lines": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"max-nested-callbacks": [
|
"max-nested-callbacks": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"max-params": [
|
"max-params": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"max-statements": [
|
"max-statements": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"max-statements-per-line": [
|
"max-statements-per-line": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"multiline-comment-style": [
|
"multiline-comment-style": [
|
||||||
"off",
|
"off",
|
||||||
"starred-block"
|
"starred-block",
|
||||||
],
|
],
|
||||||
"multiline-ternary": [
|
"multiline-ternary": [
|
||||||
"off",
|
"off",
|
||||||
"never"
|
"never",
|
||||||
],
|
],
|
||||||
"new-cap": [
|
"new-cap": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"new-parens": [
|
"new-parens": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"newline-after-var": [
|
"newline-after-var": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"newline-before-return": [
|
"newline-before-return": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"newline-per-chained-call": [
|
"newline-per-chained-call": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"no-alert": [
|
"no-alert": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-array-constructor": [
|
"no-array-constructor": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-await-in-loop": [
|
"no-await-in-loop": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-bitwise": [
|
"no-bitwise": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"no-buffer-constructor": [
|
"no-buffer-constructor": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-caller": [
|
"no-caller": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-case-declarations": [
|
"no-case-declarations": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-catch-shadow": [
|
"no-catch-shadow": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-class-assign": [
|
"no-class-assign": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-compare-neg-zero": [
|
"no-compare-neg-zero": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-cond-assign": [
|
"no-cond-assign": [
|
||||||
"off",
|
"off",
|
||||||
"except-parens"
|
"except-parens",
|
||||||
],
|
],
|
||||||
"no-confusing-arrow": [
|
"no-confusing-arrow": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-console": [
|
"no-console": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"no-const-assign": [
|
"no-const-assign": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-constant-condition": [
|
"no-constant-condition": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
"checkLoops": false
|
"checkLoops": false,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"no-continue": [
|
"no-continue": [
|
||||||
"off"
|
"off",
|
||||||
],
|
],
|
||||||
"no-control-regex": [
|
"no-control-regex": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-debugger": [
|
"no-debugger": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-delete-var": [
|
"no-delete-var": [
|
||||||
"error"
|
"error",
|
||||||
],
|
],
|
||||||
"no-div-regex": [
|
"no-div-regex": [
|
||||||
"error"
|
"error"
|
||||||
@@ -346,11 +358,7 @@ module.exports = {
|
|||||||
"error"
|
"error"
|
||||||
],
|
],
|
||||||
"no-extra-parens": [
|
"no-extra-parens": [
|
||||||
"error",
|
"off"
|
||||||
"all",
|
|
||||||
{
|
|
||||||
"conditionalAssign": false
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"no-extra-semi": [
|
"no-extra-semi": [
|
||||||
"off"
|
"off"
|
||||||
@@ -367,9 +375,6 @@ module.exports = {
|
|||||||
"no-extra-label": [
|
"no-extra-label": [
|
||||||
"error"
|
"error"
|
||||||
],
|
],
|
||||||
"no-extra-parens": [
|
|
||||||
"off"
|
|
||||||
],
|
|
||||||
"no-fallthrough": [
|
"no-fallthrough": [
|
||||||
"off"
|
"off"
|
||||||
],
|
],
|
||||||
@@ -853,5 +858,53 @@ module.exports = {
|
|||||||
"error",
|
"error",
|
||||||
"never"
|
"never"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
// TypeScript configuration
|
||||||
|
"files": [ "**/*.ts", "**/*.tsx" ],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"plugins": [ "@typescript-eslint" ],
|
||||||
|
"extends": [
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"lines-between-class-members": "off",
|
||||||
|
"no-empty-pattern": "off",
|
||||||
|
"no-useless-constructor": [
|
||||||
|
"off", // Valid for typescript due to property ctor shorthand
|
||||||
|
],
|
||||||
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
"@typescript-eslint/ban-ts-ignore": "off",
|
||||||
|
"@typescript-eslint/camelcase": "off",
|
||||||
|
"@typescript-eslint/explicit-function-return-type": ["error", {
|
||||||
|
"allowExpressions": true,
|
||||||
|
}],
|
||||||
|
"@typescript-eslint/member-delimiter-style": ["error", {
|
||||||
|
"multiline": {
|
||||||
|
"delimiter": "semi",
|
||||||
|
"requireLast": true,
|
||||||
|
},
|
||||||
|
"singleline": {
|
||||||
|
"delimiter": "semi",
|
||||||
|
"requireLast": false,
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"@typescript-eslint/member-ordering": ["error", {
|
||||||
|
"default": [
|
||||||
|
"signature",
|
||||||
|
"static-field",
|
||||||
|
"instance-field",
|
||||||
|
"abstract-field",
|
||||||
|
"constructor",
|
||||||
|
"instance-method",
|
||||||
|
"abstract-method",
|
||||||
|
"static-method",
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/no-use-before-define": "off",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
@@ -7,4 +7,17 @@ Update the following
|
|||||||
- `doc/source/conf.py` `version` and `release`
|
- `doc/source/conf.py` `version` and `release`
|
||||||
- `doc/source/changelog.rst`
|
- `doc/source/changelog.rst`
|
||||||
- post to discord
|
- post to discord
|
||||||
- post to reddit.com/r/Bitburner
|
- post to reddit.com/r/Bitburner
|
||||||
|
|
||||||
|
Deploying `dev` to the Beta Branch
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Development Workflow Best Practices
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
- Work in a new branch forked from the `dev` branch to isolate your new code
|
||||||
|
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
|
||||||
|
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
|
||||||
|
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`
|
||||||
|
|||||||
24
css/casino.scss
Normal file
24
css/casino.scss
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.casino-card {
|
||||||
|
padding: 10px;
|
||||||
|
border: solid 1px #808080;
|
||||||
|
background-color: white;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 14pt;
|
||||||
|
text-align: center;
|
||||||
|
margin: 3px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.casino-card .value {
|
||||||
|
font-size:15pt;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.casino-card.red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.casino-card.black {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
5
css/milestones.scss
Normal file
5
css/milestones.scss
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#milestones-container {
|
||||||
|
position: fixed;
|
||||||
|
padding: 6px;
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
@@ -228,14 +228,15 @@ a:visited {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
display: inline-block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
-webkit-animation: status-text 3s 1;
|
-webkit-animation: status-text 3s 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#status-text-container {
|
#status-text-container {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#status-text {
|
#status-text {
|
||||||
|
|||||||
4
dist/engine.bundle.js
vendored
4
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/engineStyle.bundle.js
vendored
2
dist/engineStyle.bundle.js
vendored
@@ -1,2 +1,2 @@
|
|||||||
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([398,0]),o()}({341:function(n,t,o){},343:function(n,t,o){},345:function(n,t,o){},347:function(n,t,o){},349:function(n,t,o){},351:function(n,t,o){},353:function(n,t,o){},355:function(n,t,o){},357:function(n,t,o){},359:function(n,t,o){},361:function(n,t,o){},363:function(n,t,o){},365:function(n,t,o){},367:function(n,t,o){},369:function(n,t,o){},371:function(n,t,o){},373:function(n,t,o){},375:function(n,t,o){},377:function(n,t,o){},379:function(n,t,o){},381:function(n,t,o){},383:function(n,t,o){},385:function(n,t,o){},387:function(n,t,o){},389:function(n,t,o){},391:function(n,t,o){},393:function(n,t,o){},395:function(n,t,o){},398:function(n,t,o){"use strict";o.r(t);o(397),o(395),o(393),o(391),o(389),o(387),o(385),o(383),o(381),o(379),o(377),o(375),o(373),o(371),o(369),o(367),o(365),o(363),o(361),o(359),o(357),o(355),o(353),o(351),o(349),o(347),o(345),o(343),o(341)}});
|
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],p=0,s=[];p<f.length;p++)i=f[p],u[i]&&s.push(u[i][0]),u[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(a&&a(t);s.length;)s.shift()();return r.push.apply(r,l||[]),o()}function o(){for(var n,t=0;t<r.length;t++){for(var o=r[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==u[c]&&(e=!1)}e&&(r.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},u={1:0},r=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var a=c;r.push([842,0]),o()}({781:function(n,t,o){},783:function(n,t,o){},785:function(n,t,o){},787:function(n,t,o){},789:function(n,t,o){},791:function(n,t,o){},793:function(n,t,o){},795:function(n,t,o){},797:function(n,t,o){},799:function(n,t,o){},801:function(n,t,o){},803:function(n,t,o){},805:function(n,t,o){},807:function(n,t,o){},809:function(n,t,o){},811:function(n,t,o){},813:function(n,t,o){},815:function(n,t,o){},817:function(n,t,o){},819:function(n,t,o){},821:function(n,t,o){},823:function(n,t,o){},825:function(n,t,o){},827:function(n,t,o){},829:function(n,t,o){},831:function(n,t,o){},833:function(n,t,o){},835:function(n,t,o){},837:function(n,t,o){},839:function(n,t,o){},842:function(n,t,o){"use strict";o.r(t);o(841),o(839),o(837),o(835),o(833),o(831),o(829),o(827),o(825),o(823),o(821),o(819),o(817),o(815),o(813),o(811),o(809),o(807),o(805),o(803),o(801),o(799),o(797),o(795),o(793),o(791),o(789),o(787),o(785),o(783),o(781)}});
|
||||||
//# sourceMappingURL=engineStyle.bundle.js.map
|
//# sourceMappingURL=engineStyle.bundle.js.map
|
||||||
33
dist/engineStyle.css
vendored
33
dist/engineStyle.css
vendored
@@ -250,13 +250,14 @@ a:visited {
|
|||||||
opacity: 0; } }
|
opacity: 0; } }
|
||||||
|
|
||||||
.status-text {
|
.status-text {
|
||||||
display: inline-block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
-webkit-animation: status-text 3s 1; }
|
-webkit-animation: status-text 3s 1; }
|
||||||
|
|
||||||
#status-text-container {
|
#status-text-container {
|
||||||
background-color: transparent; }
|
background-color: transparent;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%; }
|
||||||
|
|
||||||
#status-text {
|
#status-text {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@@ -5006,5 +5007,31 @@ html {
|
|||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
margin-right: 0px; }
|
margin-right: 0px; }
|
||||||
|
|
||||||
|
.casino-card {
|
||||||
|
padding: 10px;
|
||||||
|
border: solid 1px #808080;
|
||||||
|
background-color: white;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 14pt;
|
||||||
|
text-align: center;
|
||||||
|
margin: 3px;
|
||||||
|
font-weight: bold; }
|
||||||
|
|
||||||
|
.casino-card .value {
|
||||||
|
font-size: 15pt;
|
||||||
|
font-family: sans-serif; }
|
||||||
|
|
||||||
|
.casino-card.red {
|
||||||
|
color: red; }
|
||||||
|
|
||||||
|
.casino-card.black {
|
||||||
|
color: black; }
|
||||||
|
|
||||||
|
#milestones-container {
|
||||||
|
position: fixed;
|
||||||
|
padding: 6px;
|
||||||
|
width: 60%; }
|
||||||
|
|
||||||
|
|
||||||
/*# sourceMappingURL=engineStyle.css.map*/
|
/*# sourceMappingURL=engineStyle.css.map*/
|
||||||
78
dist/vendor.bundle.js
vendored
78
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@@ -35,7 +35,7 @@ List of Factions and their Requirements
|
|||||||
| Early Game | Faction Name | Requirements | Joining this Faction prevents |
|
| Early Game | Faction Name | Requirements | Joining this Faction prevents |
|
||||||
| Factions | | | you from joining: |
|
| Factions | | | you from joining: |
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | CyberSec | * Hack CSEC Manually | |
|
| | CyberSec | * Install a backdoor on the CSEC server | |
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | Tian Di Hui | * $1m | |
|
| | Tian Di Hui | * $1m | |
|
||||||
| | | * Hacking Level 50 | |
|
| | | * Hacking Level 50 | |
|
||||||
@@ -74,13 +74,16 @@ List of Factions and their Requirements
|
|||||||
| | | | * New Tokyo |
|
| | | | * New Tokyo |
|
||||||
| | | | * Ishima |
|
| | | | * Ishima |
|
||||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||||
| Hacking | NiteSec | * Hack avmnite-02h manually | |
|
| Hacking | NiteSec | * Install a backdoor on the avmnite-02h | |
|
||||||
| Groups | | * Home Computer RAM of at least 32GB | |
|
| Groups | | server | |
|
||||||
|
| | | * Home Computer RAM of at least 32GB | |
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | The Black Hand | * Hack I.I.I.I manually | |
|
| | The Black Hand | * Install a backdoor on the I.I.I.I | |
|
||||||
|
| | | server | |
|
||||||
| | | * Home Computer RAM of at least 64GB | |
|
| | | * Home Computer RAM of at least 64GB | |
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | Bitrunners | * Hack run4theh111z manually | |
|
| | Bitrunners | * Install a backdoor on the run4theh111z| |
|
||||||
|
| | | server | |
|
||||||
| | | * Home Computer RAM of at least 128GB | |
|
| | | * Home Computer RAM of at least 128GB | |
|
||||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||||
| Megacorporations | ECorp | * Have 200k reputation with | |
|
| Megacorporations | ECorp | * Have 200k reputation with | |
|
||||||
@@ -112,7 +115,8 @@ List of Factions and their Requirements
|
|||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | Fulcrum Secret | * Have 250k reputation with | |
|
| | Fulcrum Secret | * Have 250k reputation with | |
|
||||||
| | Technologies | the Corporation | |
|
| | Technologies | the Corporation | |
|
||||||
| | | * Hack fulcrumassets manually | |
|
| | | * Install a backdoor on the | |
|
||||||
|
| | | fulcrumassets server | |
|
||||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||||
| Criminal | Slum Snakes | * All Combat Stats of 30 | |
|
| Criminal | Slum Snakes | * All Combat Stats of 30 | |
|
||||||
| Organizations | | * -9 Karma | |
|
| Organizations | | * -9 Karma | |
|
||||||
|
|||||||
@@ -148,6 +148,14 @@ has root access, what ports are opened/closed, and also hacking-related informat
|
|||||||
such as an estimated chance to successfully hack, an estimate of how much money is
|
such as an estimated chance to successfully hack, an estimate of how much money is
|
||||||
available on the server, etc.
|
available on the server, etc.
|
||||||
|
|
||||||
|
backdoor
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
Installs a backdoor on the current server. Root access is required to do this.
|
||||||
|
|
||||||
|
Servers will give different bonuses when you install a backdoor.
|
||||||
|
This can pass faction tests or give bonsues such as discounts from companies.
|
||||||
|
|
||||||
buy
|
buy
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,152 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
|
||||||
|
v0.51.6 - 2021-04-28 Backdoor! (Community)
|
||||||
|
-------
|
||||||
|
|
||||||
|
**Backdoor**
|
||||||
|
|
||||||
|
* a new terminal command, backdoor, has been added to help differentiate
|
||||||
|
between the terminal hack command and the netscript hack function. (@dewint)
|
||||||
|
|
||||||
|
**Milestones**
|
||||||
|
|
||||||
|
* A new tab under the Help menu has been added to guide players through the
|
||||||
|
game.
|
||||||
|
|
||||||
|
**Casino**
|
||||||
|
|
||||||
|
* Blackjack has been added (@BigD)
|
||||||
|
|
||||||
|
**Netscript**
|
||||||
|
|
||||||
|
* 'prompt' now converts input to JSON.
|
||||||
|
* 'getRunningScript' is a new netscript function that returns a bunch of
|
||||||
|
data related to a running script.
|
||||||
|
|
||||||
|
**Coding contracts**
|
||||||
|
|
||||||
|
* trivial puzzles should no longer appear.
|
||||||
|
|
||||||
|
**Infiltration**
|
||||||
|
|
||||||
|
* All numbers are formatted like the rest of the game.
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* Server security is capped at 100.
|
||||||
|
* Added option to quit a job.
|
||||||
|
* 'cd' no longer works on unexistent folders.
|
||||||
|
* cd with no arguments brings you back to top level folder (@Andreas)
|
||||||
|
* 'softReset' documentation udpated.
|
||||||
|
* Money tracker now accounts for going to the hospital manually.
|
||||||
|
* codemirror is now the default editor (for new save files)
|
||||||
|
* fix typo in dark web help text (@Rodeth)
|
||||||
|
* so many documentation and typos fixes (@Pimgd)
|
||||||
|
* A corruption visual effect has been added to location with servers that
|
||||||
|
have backdoor installed. (@dewint)
|
||||||
|
|
||||||
|
|
||||||
|
v0.51.5 - 2021-04-20 Flags! (hydroflame)
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
**Netscript**
|
||||||
|
|
||||||
|
* 'flags' is a new function that helps script handle flags.
|
||||||
|
This is subject to change if it doesn't meet the need of the players.
|
||||||
|
* 'ps' now returns the pid.
|
||||||
|
* 'tail' now works with pid as first argument.
|
||||||
|
* 'tail' hostname defaults to current server. (like the documentation says)
|
||||||
|
* 'isRunning' hostname defaults to current server.
|
||||||
|
* 'isRunning' now works with pid as first argument.
|
||||||
|
|
||||||
|
**Gang**
|
||||||
|
|
||||||
|
* Nerfed ascension mechanic once again :(
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* Souce-File typo fix
|
||||||
|
* Fix 'while you were away' screen.
|
||||||
|
* Bladeburner team size can no longer be set to negative amounts.
|
||||||
|
|
||||||
|
v0.51.4 - 2021-04-19 Manual hacking is fun (hydroflame)
|
||||||
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
**Manual hacking**
|
||||||
|
|
||||||
|
* These bonus require an install or a soft reset to take effect.
|
||||||
|
* Manual hacking gyms and university gives you a 10% discount.
|
||||||
|
* Manual hacking a corporation server decreases the penalty for leaving work
|
||||||
|
early.
|
||||||
|
|
||||||
|
**BladeBurner**
|
||||||
|
|
||||||
|
* nerfed int exp gained.
|
||||||
|
|
||||||
|
**Documentation**
|
||||||
|
|
||||||
|
* purchaseServer specifies what happens on failure.
|
||||||
|
* Fixed typo in recommended bitnode page.
|
||||||
|
* Removed misleading ram requirements for hacking factions.
|
||||||
|
|
||||||
|
**Netscript**
|
||||||
|
|
||||||
|
* growthAnalyze handles Infinity correctly.
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* Faction Augmentation will list how much reputation is required even after
|
||||||
|
that goal has been reached.
|
||||||
|
* Removed dollar sign in travel agency confirmation dialog box.
|
||||||
|
* Fixed typo in alpha-omega.lit
|
||||||
|
* the 'Game saved!' text no longer blocks the save game/options button.
|
||||||
|
* The text editor now remembers the location of your cursor and restores it.
|
||||||
|
* skills are recalculated instantly.
|
||||||
|
* Fix typo in Operation Zero description.
|
||||||
|
|
||||||
|
v0.51.3 - 2021-04-16 Y'all broke it on the first day (hydroflame)
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
**Passive faction reputation**
|
||||||
|
|
||||||
|
* Reworked, from 1 rep / 2 minute. Now is a complicated percentage of the
|
||||||
|
reputation you'd gain working for them. It's not op but it feels a bit
|
||||||
|
more useful.
|
||||||
|
|
||||||
|
**Netscript**
|
||||||
|
|
||||||
|
* print/tprint now take any number of arguments.
|
||||||
|
* print/tprint will now print object as json.
|
||||||
|
* print/tprint now handle passing in an undefined argument properly.
|
||||||
|
|
||||||
|
**Casino**
|
||||||
|
|
||||||
|
* Cannot bet negative money anymore.
|
||||||
|
* Roulette max bet is a bit higher.
|
||||||
|
* Coin Flip has a small cooldown.
|
||||||
|
* All buttons reject unstrusted mouse events.
|
||||||
|
|
||||||
|
**Documentation**
|
||||||
|
|
||||||
|
* Changed a message that said nsjs only works on Chrome.
|
||||||
|
|
||||||
|
**Bugfix**
|
||||||
|
|
||||||
|
* hacknet.maxNumNodes now works for both nodes and servers.
|
||||||
|
* Fixed a bug where the popup boxes would contain data from previous popup boxes.
|
||||||
|
* .js files will also have the 'export async function' boilerplate.
|
||||||
|
|
||||||
|
**Misc.**
|
||||||
|
|
||||||
|
* turned off web form autocomplete for the terminal text input.
|
||||||
|
* Fixed an issue on Windows+Firefox where pressing up on the terminal would
|
||||||
|
bring the cursor to the begining of the line. (Issue #836)
|
||||||
|
* Hacknet node names is easier to handle for screen readers.
|
||||||
|
* Money spent on classes is now tracked independently of work money.
|
||||||
|
* running coding contract from the terminal will display its name.
|
||||||
|
|
||||||
v0.51.2 - 2021-04-09 Vegas, Baby! (hydroflame)
|
v0.51.2 - 2021-04-09 Vegas, Baby! (hydroflame)
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
|||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.51'
|
version = '0.51'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.51.2'
|
release = '0.51.5'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|||||||
@@ -634,7 +634,7 @@ This tells me that I can reach :code:`CSEC` by going through :code:`iron-gym`::
|
|||||||
Make sure you notice the required hacking skill for the :code:`CSEC` server.
|
Make sure you notice the required hacking skill for the :code:`CSEC` server.
|
||||||
This is a random value between 51 and 60. Although you receive the message
|
This is a random value between 51 and 60. Although you receive the message
|
||||||
from CSEC once you hit 50 hacking, you cannot actually pass their test
|
from CSEC once you hit 50 hacking, you cannot actually pass their test
|
||||||
until your hacking is high enough to hack their server.
|
until your hacking is high enough to install a backdoor on their server.
|
||||||
|
|
||||||
After you are connected to the :code:`CSEC` server, you can hack it. Note that this
|
After you are connected to the :code:`CSEC` server, you can hack it. Note that this
|
||||||
server requires one open port in order to gain root access. We can open the SSH port
|
server requires one open port in order to gain root access. We can open the SSH port
|
||||||
@@ -642,10 +642,10 @@ using the :code:`BruteSSH.exe` program we created earlier. In |Terminal|::
|
|||||||
|
|
||||||
$ run BruteSSH.exe
|
$ run BruteSSH.exe
|
||||||
$ run NUKE.exe
|
$ run NUKE.exe
|
||||||
$ hack
|
$ backdoor
|
||||||
|
|
||||||
Keep hacking the server until you are successful. After you successfully hack it, you should
|
After you successfully install the backdoor, you should receive a faction
|
||||||
receive a faction invitation from |CyberSec| shortly afterwards. Accept it. If you accidentally
|
invitation from |CyberSec| shortly afterwards. Accept it. If you accidentally
|
||||||
reject the invitation, that's okay. Just go to the :code:`Factions` tab
|
reject the invitation, that's okay. Just go to the :code:`Factions` tab
|
||||||
(|Keyboard shortcut| Alt + f) and you should see an option that lets you
|
(|Keyboard shortcut| Alt + f) and you should see an option that lets you
|
||||||
accept the invitation.
|
accept the invitation.
|
||||||
|
|||||||
@@ -278,6 +278,7 @@ Description
|
|||||||
hashes, which can be spent on a variety of different upgrades.
|
hashes, which can be spent on a variety of different upgrades.
|
||||||
|
|
||||||
In this BitNode:
|
In this BitNode:
|
||||||
|
|
||||||
* Your stats are significantly decreased
|
* Your stats are significantly decreased
|
||||||
* You cannnot purchase additional servers
|
* You cannnot purchase additional servers
|
||||||
* Hacking is significantly less profitable
|
* Hacking is significantly less profitable
|
||||||
@@ -292,7 +293,7 @@ Source-File
|
|||||||
* Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode
|
* Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode
|
||||||
|
|
||||||
(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT
|
(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT
|
||||||
when installing Augmentation
|
when installing Augmentations.)
|
||||||
|
|
||||||
Difficulty
|
Difficulty
|
||||||
Hard
|
Hard
|
||||||
@@ -312,6 +313,7 @@ Description
|
|||||||
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
|
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously
|
||||||
|
|
||||||
In this BitNode:
|
In this BitNode:
|
||||||
|
|
||||||
* Your stats are significantly decreased
|
* Your stats are significantly decreased
|
||||||
* All methods of gaining money are half as profitable (except Stock Market)
|
* All methods of gaining money are half as profitable (except Stock Market)
|
||||||
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit
|
* Purchased servers are more expensive, have less max RAM, and a lower maximum limit
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ getServer() Netscript Function
|
|||||||
sshPortOpen
|
sshPortOpen
|
||||||
baseDifficulty
|
baseDifficulty
|
||||||
hackDifficulty
|
hackDifficulty
|
||||||
manuallyHacked
|
backdoorInstalled
|
||||||
minDifficulty
|
minDifficulty
|
||||||
moneyAvailable
|
moneyAvailable
|
||||||
moneyMax
|
moneyMax
|
||||||
|
|||||||
40
doc/source/netscript/basicfunctions/flags.rst
Normal file
40
doc/source/netscript/basicfunctions/flags.rst
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
flags() Netscript Function
|
||||||
|
============================
|
||||||
|
|
||||||
|
.. js:function:: flags(data)
|
||||||
|
|
||||||
|
:RAM cost: 0 GB
|
||||||
|
:param data array of pairs of strings: Flags definition.
|
||||||
|
:returns: Object containing all the flags that were parsed or default.
|
||||||
|
|
||||||
|
The flag definition is an array of pairs of values, the first value is the
|
||||||
|
name of the flag, the 2nd value is the default value for that flag.
|
||||||
|
|
||||||
|
The return object is a map containing flag names to the value. It also
|
||||||
|
contains the special field '_' which contains all arguments that were not flags.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
/* example.script
|
||||||
|
var data = flags([
|
||||||
|
['delay', 0], // a default number means this flag is a number
|
||||||
|
['server', 'foodnstuff'], // a default string means this flag is a string
|
||||||
|
['exclude', []], // a default array means this flag is a default array of string
|
||||||
|
['help', false], // a default boolean means this flag is a boolean
|
||||||
|
]);
|
||||||
|
tprint(data);
|
||||||
|
*/
|
||||||
|
[home ~/]> run example.script
|
||||||
|
{"_":[],"delay":0,"server":"foodnstuff"}
|
||||||
|
[home ~/]> run example.script --delay 3000
|
||||||
|
{"_":[],"server":"foodnstuff","delay":3000}
|
||||||
|
[home ~/]> run example.script --delay 3000 --server harakiri-sushi
|
||||||
|
{"_":[],"delay":3000,"server":"harakiri-sushi"}
|
||||||
|
[home ~/]> run example.script --delay 3000 --server harakiri-sushi hello world
|
||||||
|
{"_":["hello","world"],"delay":3000,"server":"harakiri-sushi"}
|
||||||
|
[home ~/]> run example.script --delay 3000 --server harakiri-sushi hello world --exclude a --exclude b
|
||||||
|
{"_":["hello","world"],"delay":3000,"server":"harakiri-sushi","exclude":["a","b"]}
|
||||||
|
[home ~/]> run example.script --help
|
||||||
|
{"_":[],"delay":0,"server":"foodnstuff","exclude":[],"help":true}
|
||||||
88
doc/source/netscript/basicfunctions/getRunningScript.rst
Normal file
88
doc/source/netscript/basicfunctions/getRunningScript.rst
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
getRunningScript() Netscript Function
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
.. js:function:: getRunningScript()
|
||||||
|
|
||||||
|
:RAM cost: 0.3 GB
|
||||||
|
:returns: Script object or null if not found
|
||||||
|
|
||||||
|
The object has the following properties:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
// Script arguments
|
||||||
|
args
|
||||||
|
|
||||||
|
// Script filename
|
||||||
|
filename
|
||||||
|
|
||||||
|
// This script's logs. An array of log entries
|
||||||
|
logs
|
||||||
|
|
||||||
|
// Flag indicating whether the logs have been updated since
|
||||||
|
// the last time the UI was updated
|
||||||
|
logUpd
|
||||||
|
|
||||||
|
// Total amount of hacking experience earned from this script when offline
|
||||||
|
offlineExpGained
|
||||||
|
|
||||||
|
// Total amount of money made by this script when offline
|
||||||
|
offlineMoneyMade
|
||||||
|
|
||||||
|
// Number of seconds that the script has been running offline
|
||||||
|
offlineRunningTime
|
||||||
|
|
||||||
|
// Total amount of hacking experience earned from this script when online
|
||||||
|
onlineExpGained
|
||||||
|
|
||||||
|
// Total amount of money made by this script when online
|
||||||
|
onlineMoneyMade
|
||||||
|
|
||||||
|
// Number of seconds that this script has been running online
|
||||||
|
onlineRunningTime
|
||||||
|
|
||||||
|
// Process ID.
|
||||||
|
pid
|
||||||
|
|
||||||
|
// How much RAM this script uses for ONE thread
|
||||||
|
ramUsage
|
||||||
|
|
||||||
|
// IP of the server on which this script is running
|
||||||
|
server
|
||||||
|
|
||||||
|
// Number of threads that this script is running with
|
||||||
|
threads
|
||||||
|
}
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
getRunningScript(); // get the current script.
|
||||||
|
|
||||||
|
.. js:function:: getRunningScript(pid)
|
||||||
|
|
||||||
|
:RAM cost: 0.3 GB
|
||||||
|
:param number pid: PID of the script
|
||||||
|
:returns: Script object or null if not found
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
getRunningScript(42); // get the script with pid 42.
|
||||||
|
|
||||||
|
.. js:function:: getRunningScript(fn, hostname[, args])
|
||||||
|
|
||||||
|
:RAM cost: 0.3 GB
|
||||||
|
:param number fn: filename of the target script
|
||||||
|
:param number hostname: hostname of the server running the script
|
||||||
|
:param number args: arguments to the script.
|
||||||
|
:returns: Script object or null if not found
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
getRunningScript("example.script", "home", "foodnstuff"); // get the script called "example.script" on "home" with argument "foodnstuff"
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
isRunning() Netscript Function
|
isRunning() Netscript Function
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
.. js:function:: isRunning(filename, hostname, [args...])
|
.. js:function:: isRunning(filename[, hostname=current hostname[, args...]])
|
||||||
|
|
||||||
:RAM cost: 0.1 GB
|
:RAM cost: 0.1 GB
|
||||||
:param string filename: Filename of script to check. case-sensitive.
|
:param string filename: Filename of script to check. case-sensitive.
|
||||||
:param string hostname: Hostname of target server.
|
:param string hostname: Hostname of target server. Defaults to current server
|
||||||
:param args...: Arguments to specify/identify which scripts to search for
|
:param args...: Arguments to specify/identify which scripts to search for
|
||||||
:returns: ``true`` if that script with those args is running on that server.
|
:returns: ``true`` if that script with those args is running on that server.
|
||||||
|
|
||||||
@@ -38,3 +38,17 @@ isRunning() Netscript Function
|
|||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
isRunning("foo.script", "joesguns", 1, 5, "test");
|
isRunning("foo.script", "joesguns", 1, 5, "test");
|
||||||
|
|
||||||
|
|
||||||
|
.. js:function:: isRunning(scriptPid)
|
||||||
|
|
||||||
|
:RAM cost: 0.1 GB
|
||||||
|
:param number scriptPid: PID of the script to check.
|
||||||
|
|
||||||
|
Same as the above version but with pid.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
isRunning(39);
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
print() Netscript Function
|
print() Netscript Function
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
.. js:function:: print(x)
|
.. js:function:: print(args...)
|
||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param x: Value to be printed.
|
:param args: Values to be printed.
|
||||||
|
|
||||||
Prints a value or a variable to the script's logs.
|
Prints any number of values to the script's logs.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
print("Hello world!"); // Prints "Hello world!" in the logs.
|
print("Hello world!"); // Prints "Hello world!" in the logs.
|
||||||
|
print({a:5}); // Prints '{"a":5}' in the logs.
|
||||||
@@ -7,7 +7,7 @@ purchaseServer() Netscript Function
|
|||||||
:param string hostname: Hostname of the purchased server.
|
:param string hostname: Hostname of the purchased server.
|
||||||
:param number ram: Amount of RAM of the purchased server. Must be a power of
|
:param number ram: Amount of RAM of the purchased server. Must be a power of
|
||||||
2. Maximum value of :doc:`getPurchasedServerMaxRam<getPurchasedServerMaxRam>`
|
2. Maximum value of :doc:`getPurchasedServerMaxRam<getPurchasedServerMaxRam>`
|
||||||
:returns: The hostname of the newly purchased server.
|
:returns: The hostname of the newly purchased server. Empty string on failure.
|
||||||
|
|
||||||
Purchased a server with the specified hostname and amount of RAM.
|
Purchased a server with the specified hostname and amount of RAM.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
tail() Netscript Function
|
tail() Netscript Function
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
.. js:function:: tail([fn[, hostname=current hostname[, [...args]]])
|
.. js:function:: tail([fn[, hostname=current hostname[, ...args]])
|
||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param string fn: Optional. Filename of script to get logs from.
|
:param string fn: Optional. Filename of script to get logs from.
|
||||||
@@ -29,3 +29,33 @@ tail() Netscript Function
|
|||||||
|
|
||||||
// Open logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"]
|
// Open logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"]
|
||||||
tail("foo.script", "foodnstuff", 1, "test");
|
tail("foo.script", "foodnstuff", 1, "test");
|
||||||
|
|
||||||
|
.. js:function:: tail(scriptPid)
|
||||||
|
|
||||||
|
:RAM cost: 0 GB
|
||||||
|
:param number scriptPid: PID of the script to tail.
|
||||||
|
|
||||||
|
Opens a script's logs by pid
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
// Open logs from process with id 42
|
||||||
|
tail(42);
|
||||||
|
|
||||||
|
// Open logs from process with id 42 on the foodnstuff server
|
||||||
|
tail(42, "foodnstuff");
|
||||||
|
|
||||||
|
.. js:function:: tail()
|
||||||
|
|
||||||
|
:RAM cost: 0 GB
|
||||||
|
|
||||||
|
Opens the current script logs.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
// Open the current script logs.
|
||||||
|
tail();
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
tprint() Netscript Function
|
tprint() Netscript Function
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
.. js:function:: tprint(x)
|
.. js:function:: tprint(args...)
|
||||||
|
|
||||||
:RAM cost: 0 GB
|
:RAM cost: 0 GB
|
||||||
:param x: Value to be printed
|
:param args: Values to be printed
|
||||||
|
|
||||||
Prints a value or a variable to the Terminal.
|
Prints any number of values to the Terminal.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
tprint("Hello world!"); // Prints "Hello world!" to the terminal.
|
tprint("Hello world!"); // Prints "Hello world!" to the terminal.
|
||||||
|
tprint({a:5}); // Prints '{"a":5}' to the terminal.
|
||||||
@@ -75,6 +75,7 @@ This includes information such as function signatures, what they do, and their r
|
|||||||
scriptKill() <basicfunctions/scriptKill>
|
scriptKill() <basicfunctions/scriptKill>
|
||||||
getScriptName() <basicfunctions/getScriptName>
|
getScriptName() <basicfunctions/getScriptName>
|
||||||
getScriptRam() <basicfunctions/getScriptRam>
|
getScriptRam() <basicfunctions/getScriptRam>
|
||||||
|
getRunningScript() <basicfunctions/getRunningScript>
|
||||||
getHackTime() <basicfunctions/getHackTime>
|
getHackTime() <basicfunctions/getHackTime>
|
||||||
getGrowTime() <basicfunctions/getGrowTime>
|
getGrowTime() <basicfunctions/getGrowTime>
|
||||||
getWeakenTime() <basicfunctions/getWeakenTime>
|
getWeakenTime() <basicfunctions/getWeakenTime>
|
||||||
@@ -88,3 +89,4 @@ This includes information such as function signatures, what they do, and their r
|
|||||||
prompt() <basicfunctions/prompt>
|
prompt() <basicfunctions/prompt>
|
||||||
wget() <basicfunctions/wget>
|
wget() <basicfunctions/wget>
|
||||||
getFavorToDonate() <basicfunctions/getFavorToDonate>
|
getFavorToDonate() <basicfunctions/getFavorToDonate>
|
||||||
|
flags() <basicfunctions/flags>
|
||||||
|
|||||||
@@ -65,6 +65,6 @@ Here is a short summary of the differences between Netscript 1.0 and Netscript 2
|
|||||||
|
|
||||||
* Supports (almost) all features of modern JavaScript
|
* Supports (almost) all features of modern JavaScript
|
||||||
* Extremely fast - code is executed as an Async Function
|
* Extremely fast - code is executed as an Async Function
|
||||||
* Currently only works with Google Chrome browser
|
* Works on most modern browsers.
|
||||||
* Each script becomes a module and therefore all instances of that script can easily
|
* Each script becomes a module and therefore all instances of that script can easily
|
||||||
share data between each other (essentially global/static variables)
|
share data between each other (essentially global/static variables)
|
||||||
|
|||||||
@@ -9,13 +9,12 @@ manualHack() Netscript Function
|
|||||||
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
|
If you are not in BitNode-4, then you must have Level 1 of Source-File 4 in order to use this function.
|
||||||
|
|
||||||
This function will perform a manual hack on the server you are currently connected to.
|
This function will perform a manual hack on the server you are currently connected to.
|
||||||
This is typically required to join factions.
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
connect("CSEC");
|
connect("foodnstuff");
|
||||||
manualHack();
|
manualHack();
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
softReset() Netscript Function
|
softReset() Netscript Function
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
.. js:function:: softReset()
|
.. js:function:: softReset([callbackScript])
|
||||||
|
|
||||||
:RAM cost: 5 GB
|
:RAM cost: 5 GB
|
||||||
|
:param string cbScript:
|
||||||
|
Optional callback script. This is a script that will automatically be
|
||||||
|
run after the soft reset. This script will be run with no arguments and
|
||||||
|
1 thread. It must be located on your home computer.
|
||||||
|
|
||||||
If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.
|
If you are not in BitNode-4, then you must have Level 3 of Source-File 4 in order to use this function.
|
||||||
|
|
||||||
|
|||||||
27
index.html
27
index.html
@@ -100,9 +100,12 @@
|
|||||||
<li id="help-menu-header-li">
|
<li id="help-menu-header-li">
|
||||||
<button id="help-menu-header" class="mainmenu-accordion-header"> Help </button>
|
<button id="help-menu-header" class="mainmenu-accordion-header"> Help </button>
|
||||||
</li>
|
</li>
|
||||||
<li id="tutorial-tab" class="mainmenu-accordion-panel">
|
<li id="milestones-tab" class="mainmenu-accordion-panel">
|
||||||
<button id="tutorial-menu-link"> Tutorial </button>
|
<button id="milestones-menu-link"> Milestones </button>
|
||||||
</li>
|
</li>
|
||||||
|
<li id="tutorial-tab" class="mainmenu-accordion-panel">
|
||||||
|
<button id="tutorial-menu-link"> Tutorial </button>
|
||||||
|
</li>
|
||||||
<li id="options-tab" class="mainmenu-accordion-panel">
|
<li id="options-tab" class="mainmenu-accordion-panel">
|
||||||
<button id="options-menu-link"> Options </button>
|
<button id="options-menu-link"> Options </button>
|
||||||
</li>
|
</li>
|
||||||
@@ -177,7 +180,7 @@
|
|||||||
<table id="terminal">
|
<table id="terminal">
|
||||||
<tr id="terminal-input">
|
<tr id="terminal-input">
|
||||||
<td id="terminal-input-td" tabindex="2">$
|
<td id="terminal-input-td" tabindex="2">$
|
||||||
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;"/>
|
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -226,6 +229,10 @@
|
|||||||
<!-- Augmentations -->
|
<!-- Augmentations -->
|
||||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||||
|
|
||||||
|
<!-- Milestones content -->
|
||||||
|
<div id="milestones-container" class="generic-menupage-container">
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Tutorial content -->
|
<!-- Tutorial content -->
|
||||||
<div id="tutorial-container" class="generic-menupage-container">
|
<div id="tutorial-container" class="generic-menupage-container">
|
||||||
<h1> Tutorial (AKA Links to Documentation) </h1>
|
<h1> Tutorial (AKA Links to Documentation) </h1>
|
||||||
@@ -381,7 +388,7 @@
|
|||||||
|
|
||||||
<!-- Status text -->
|
<!-- Status text -->
|
||||||
<div id="status-text-container">
|
<div id="status-text-container">
|
||||||
<p id="status-text"> </p>
|
<p id="status-text"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Game Options -->
|
<!-- Game Options -->
|
||||||
@@ -521,6 +528,16 @@
|
|||||||
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- Disable text effects such as corruption. -->
|
||||||
|
<fieldset>
|
||||||
|
<label for="settingsDisableTextEffects" class="tooltip">Disable Text Effects:
|
||||||
|
<span class="tooltiptexthigh">
|
||||||
|
If this is set, text effects will not be displayed. This can help if text is difficult to read in certain areas.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableTextEffects" id="settingsDisableTextEffects">
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<!-- Locale for displaying numbers -->
|
<!-- Locale for displaying numbers -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="settingsLocale" class="tooltip">Locale:
|
<label for="settingsLocale" class="tooltip">Locale:
|
||||||
|
|||||||
13764
package-lock.json
generated
13764
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -6,6 +6,7 @@
|
|||||||
"url": "https://github.com/danielyxie/bitburner/issues"
|
"url": "https://github.com/danielyxie/bitburner/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@material-ui/core": "^4.11.3",
|
||||||
"@types/numeral": "0.0.25",
|
"@types/numeral": "0.0.25",
|
||||||
"@types/react": "^16.8.6",
|
"@types/react": "^16.8.6",
|
||||||
"@types/react-dom": "^16.8.2",
|
"@types/react-dom": "^16.8.2",
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"acorn-walk": "^6.2.0",
|
"acorn-walk": "^6.2.0",
|
||||||
"ajv": "^5.1.5",
|
"ajv": "^5.1.5",
|
||||||
"ajv-keywords": "^2.0.0",
|
"ajv-keywords": "^2.0.0",
|
||||||
|
"arg": "^5.0.0",
|
||||||
"async": "^2.6.1",
|
"async": "^2.6.1",
|
||||||
"autosize": "^4.0.2",
|
"autosize": "^4.0.2",
|
||||||
"brace": "^0.11.1",
|
"brace": "^0.11.1",
|
||||||
@@ -46,7 +48,10 @@
|
|||||||
"@babel/core": "^7.3.4",
|
"@babel/core": "^7.3.4",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"@types/chai": "^4.1.7",
|
"@types/chai": "^4.1.7",
|
||||||
|
"@types/lodash": "^4.14.168",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||||
|
"@typescript-eslint/parser": "^4.22.0",
|
||||||
"babel-loader": "^8.0.5",
|
"babel-loader": "^8.0.5",
|
||||||
"beautify-lint": "^1.0.3",
|
"beautify-lint": "^1.0.3",
|
||||||
"benchmark": "^2.1.1",
|
"benchmark": "^2.1.1",
|
||||||
@@ -54,8 +59,8 @@
|
|||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^0.28.11",
|
||||||
"es6-promise-polyfill": "^1.1.1",
|
"es6-promise-polyfill": "^1.1.1",
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^7.24.0",
|
||||||
"eslint-plugin-node": "^6.0.1",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"i18n-webpack-plugin": "^1.0.0",
|
"i18n-webpack-plugin": "^1.0.0",
|
||||||
@@ -85,8 +90,7 @@
|
|||||||
"stylelint-declaration-use-variable": "^1.6.1",
|
"stylelint-declaration-use-variable": "^1.6.1",
|
||||||
"stylelint-order": "^0.8.1",
|
"stylelint-order": "^0.8.1",
|
||||||
"ts-loader": "^4.5.0",
|
"ts-loader": "^4.5.0",
|
||||||
"tslint": "^5.10.0",
|
"typescript": "^4.2.4",
|
||||||
"typescript": "^2.9.2",
|
|
||||||
"uglify-es": "^3.3.9",
|
"uglify-es": "^3.3.9",
|
||||||
"uglifyjs-webpack-plugin": "^1.3.0",
|
"uglifyjs-webpack-plugin": "^1.3.0",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.0.1",
|
||||||
@@ -112,14 +116,13 @@
|
|||||||
"build": "webpack --mode production",
|
"build": "webpack --mode production",
|
||||||
"build:dev": "webpack --mode development",
|
"build:dev": "webpack --mode development",
|
||||||
"build:test": "webpack --config webpack.config-test.js",
|
"build:test": "webpack --config webpack.config-test.js",
|
||||||
"lint": "npm run lint:typescript & npm run lint:javascript & npm run lint:style",
|
"lint": "npm run lint:jsts & npm run lint:style",
|
||||||
"lint:javascript": "eslint *.js ./src/**/*.js ./tests/**/*.js ./utils/**/*.js",
|
"lint:jsts": "eslint '*.{js,jsx,ts,tsx}' './src/**/*.{js,jsx,ts,tsx}' './test/**/*.{js,jsx,ts,tsx}' './utils/**/*.{js,jsx,ts,tsx}'",
|
||||||
"lint:style": "stylelint ./css/*",
|
"lint:style": "stylelint ./css/*",
|
||||||
"lint:typescript": "tslint --project . --exclude **/*.d.ts --format stylish src/**/*.ts utils/**/*.ts",
|
|
||||||
"preinstall": "node ./scripts/engines-check.js",
|
"preinstall": "node ./scripts/engines-check.js",
|
||||||
"test": "mochapack --webpack-config webpack.config-test.js -r jsdom-global/register ./test/index.js",
|
"test": "mochapack --webpack-config webpack.config-test.js -r jsdom-global/register ./test/index.js",
|
||||||
"watch": "webpack --watch --mode production",
|
"watch": "webpack --watch --mode production",
|
||||||
"watch:dev": "webpack --watch --mode development"
|
"watch:dev": "webpack --watch --mode development"
|
||||||
},
|
},
|
||||||
"version": "0.51.1"
|
"version": "0.51.5"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export function printAliases(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if successful, false otherwise
|
// Returns true if successful, false otherwise
|
||||||
export function parseAliasDeclaration(dec: string, global: boolean=false) {
|
export function parseAliasDeclaration(dec: string, global = false): boolean {
|
||||||
var re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
|
var re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
|
||||||
var matches = dec.match(re);
|
var matches = dec.match(re);
|
||||||
if (matches == null || matches.length != 3) {return false;}
|
if (matches == null || matches.length != 3) {return false;}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { clearObject } from "../../utils/helpers/clearObject";
|
|||||||
import { createElement } from "../../utils/uiHelpers/createElement";
|
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||||
import { isString } from "../../utils/helpers/isString";
|
import { isString } from "../../utils/helpers/isString";
|
||||||
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
|
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
|
import { Money } from "../ui/React/Money";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
@@ -177,7 +178,7 @@ function initAugmentations() {
|
|||||||
const CombatRib3 = new Augmentation({
|
const CombatRib3 = new Augmentation({
|
||||||
name:AugmentationNames.CombatRib3, repCost:14e3, moneyCost:24e6,
|
name:AugmentationNames.CombatRib3, repCost:14e3, moneyCost:24e6,
|
||||||
info:"This is an upgrade to the Combat Rib II augmentation, and is capable of releasing even more potent combat-enhancing " +
|
info:"This is an upgrade to the Combat Rib II augmentation, and is capable of releasing even more potent combat-enhancing " +
|
||||||
"drugs into the bloodstream<br><br>." +
|
"drugs into the bloodstream.<br><br>" +
|
||||||
"This augmentation increases the player's strength and defense by 18%.",
|
"This augmentation increases the player's strength and defense by 18%.",
|
||||||
prereqs:[AugmentationNames.CombatRib2],
|
prereqs:[AugmentationNames.CombatRib2],
|
||||||
strength_mult: 1.18,
|
strength_mult: 1.18,
|
||||||
@@ -880,9 +881,7 @@ function initAugmentations() {
|
|||||||
info:"The body is genetically re-engineered so that it produces the ADR-V1 pheromone, " +
|
info:"The body is genetically re-engineered so that it produces the ADR-V1 pheromone, " +
|
||||||
"an artificial pheromone discovered by scientists. The ADR-V1 pheromone, when excreted, " +
|
"an artificial pheromone discovered by scientists. The ADR-V1 pheromone, when excreted, " +
|
||||||
"triggers feelings of admiration and approval in other people.<br><br>" +
|
"triggers feelings of admiration and approval in other people.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the amount of reputation the player gains when working for a faction or company by 10%.",
|
||||||
"Increases the amount of reputation the player gains when working for a company by 10% <br>" +
|
|
||||||
"Increases the amount of reputation the player gains for a faction by 10%.",
|
|
||||||
company_rep_mult: 1.1,
|
company_rep_mult: 1.1,
|
||||||
faction_rep_mult: 1.1,
|
faction_rep_mult: 1.1,
|
||||||
});
|
});
|
||||||
@@ -897,8 +896,7 @@ function initAugmentations() {
|
|||||||
info:"The body is genetically re-engineered so that it produces the ADR-V2 pheromone, " +
|
info:"The body is genetically re-engineered so that it produces the ADR-V2 pheromone, " +
|
||||||
"which is similar to but more potent than ADR-V1. This pheromone, when excreted, " +
|
"which is similar to but more potent than ADR-V1. This pheromone, when excreted, " +
|
||||||
"triggers feelings of admiration, approval, and respect in others.<br><br>" +
|
"triggers feelings of admiration, approval, and respect in others.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the amount of reputation the player gains when working for a faction or company by 20%.",
|
||||||
"Increases the amount of reputation the player gains for a faction and company by 20%.",
|
|
||||||
company_rep_mult: 1.2,
|
company_rep_mult: 1.2,
|
||||||
faction_rep_mult: 1.2,
|
faction_rep_mult: 1.2,
|
||||||
});
|
});
|
||||||
@@ -915,8 +913,7 @@ function initAugmentations() {
|
|||||||
"criminal organizations and allows the user to project and control holographic " +
|
"criminal organizations and allows the user to project and control holographic " +
|
||||||
"simulacrums within a large radius. These simulacrums are commonly used for " +
|
"simulacrums within a large radius. These simulacrums are commonly used for " +
|
||||||
"espionage and surveillance work.<br><br>" +
|
"espionage and surveillance work.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the amount of reputation the player gains when working for a faction or company by 15%.",
|
||||||
"Increases the amount of reputation the player gains when working for a faction or company by 15%.",
|
|
||||||
company_rep_mult: 1.15,
|
company_rep_mult: 1.15,
|
||||||
faction_rep_mult: 1.15,
|
faction_rep_mult: 1.15,
|
||||||
});
|
});
|
||||||
@@ -1152,7 +1149,7 @@ function initAugmentations() {
|
|||||||
"cells, when powered, have a negative refractive index. As a result, they bend light " +
|
"cells, when powered, have a negative refractive index. As a result, they bend light " +
|
||||||
"around the skin, making the user much harder to see from the naked eye.<br><br>" +
|
"around the skin, making the user much harder to see from the naked eye.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation:<br>" +
|
||||||
"Increases the player's agility by 5% <br>" +
|
"Increases the player's agility by 5%.<br>" +
|
||||||
"Increases the amount of money the player gains from crimes by 10%.",
|
"Increases the amount of money the player gains from crimes by 10%.",
|
||||||
agility_mult: 1.05,
|
agility_mult: 1.05,
|
||||||
crime_money_mult: 1.1,
|
crime_money_mult: 1.1,
|
||||||
@@ -1170,8 +1167,8 @@ function initAugmentations() {
|
|||||||
"cells, when powered, are capable of not only bending light but also of bending heat, " +
|
"cells, when powered, are capable of not only bending light but also of bending heat, " +
|
||||||
"making the user more resilient as well as stealthy.<br><br>" +
|
"making the user more resilient as well as stealthy.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation:<br>" +
|
||||||
"Increases the player's agility by 10% <br>" +
|
"Increases the player's agility by 10%.<br>" +
|
||||||
"Increases the player's defense by 10% <br>" +
|
"Increases the player's defense by 10%.<br>" +
|
||||||
"Increases the amount of money the player gains from crimes by 25%.",
|
"Increases the amount of money the player gains from crimes by 25%.",
|
||||||
prereqs:[AugmentationNames.LuminCloaking1],
|
prereqs:[AugmentationNames.LuminCloaking1],
|
||||||
agility_mult: 1.1,
|
agility_mult: 1.1,
|
||||||
@@ -1372,7 +1369,7 @@ function initAugmentations() {
|
|||||||
name:AugmentationNames.Xanipher, repCost:350e3, moneyCost:850e6,
|
name:AugmentationNames.Xanipher, repCost:350e3, moneyCost:850e6,
|
||||||
info:"A concoction of advanced nanobots that is orally ingested into the " +
|
info:"A concoction of advanced nanobots that is orally ingested into the " +
|
||||||
"body. These nanobots induce physiological change and significantly " +
|
"body. These nanobots induce physiological change and significantly " +
|
||||||
"improve the body's functionining in all aspects.<br><br>" +
|
"improve the body's functioning in all aspects.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation:<br>" +
|
||||||
"Increases all of the player's stats by 20%.<br>" +
|
"Increases all of the player's stats by 20%.<br>" +
|
||||||
"Increases the player's experience gain rate for all stats by 15%.",
|
"Increases the player's experience gain rate for all stats by 15%.",
|
||||||
@@ -1395,6 +1392,23 @@ function initAugmentations() {
|
|||||||
}
|
}
|
||||||
AddToAugmentations(Xanipher);
|
AddToAugmentations(Xanipher);
|
||||||
|
|
||||||
|
const HydroflameLeftArm = new Augmentation({
|
||||||
|
name:AugmentationNames.HydroflameLeftArm, repCost:500e3, moneyCost:500e9,
|
||||||
|
info:"The left arm of a legendary BitRunner who ascended beyond this world. " +
|
||||||
|
"It projects a light blue energy shield that protects the exposed inner parts. " +
|
||||||
|
"Even though it contains no weapons, the advance tungsten titanium " +
|
||||||
|
"alloy increases the users strength to unbelievable levels.<br><br>" +
|
||||||
|
"This augmentation increases the player's strength by 300%.",
|
||||||
|
strength_mult: 3,
|
||||||
|
});
|
||||||
|
HydroflameLeftArm.addToFactions(["NWO"]);
|
||||||
|
if (augmentationExists(AugmentationNames.HydroflameLeftArm)) {
|
||||||
|
delete Augmentations[AugmentationNames.HydroflameLeftArm];
|
||||||
|
}
|
||||||
|
AddToAugmentations(HydroflameLeftArm);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ClarkeIncorporated
|
// ClarkeIncorporated
|
||||||
const nextSENS = new Augmentation({
|
const nextSENS = new Augmentation({
|
||||||
name:AugmentationNames.nextSENS, repCost:175e3, moneyCost:385e6,
|
name:AugmentationNames.nextSENS, repCost:175e3, moneyCost:385e6,
|
||||||
@@ -1537,12 +1551,12 @@ function initAugmentations() {
|
|||||||
// Sector12
|
// Sector12
|
||||||
const CashRoot = new Augmentation({
|
const CashRoot = new Augmentation({
|
||||||
name:AugmentationNames.CashRoot, repCost:5e3, moneyCost:25e6,
|
name:AugmentationNames.CashRoot, repCost:5e3, moneyCost:25e6,
|
||||||
info:"A collection of digital assets saved on a small chip. The chip is implanted " +
|
info:<>A collection of digital assets saved on a small chip. The chip is implanted
|
||||||
"into your wrist. A small jack in the chip allows you to connect it to a computer " +
|
into your wrist. A small jack in the chip allows you to connect it to a computer
|
||||||
"and upload the assets.<br><br>" +
|
and upload the assets.<br /><br />
|
||||||
"This augmentation:<br>" +
|
This augmentation:<br />
|
||||||
"Lets the player start with $1,000,000 after a reset.<br>" +
|
Lets the player start with {Money(1e6)} after a reset.<br />
|
||||||
"Lets the player start with the BruteSSH.exe program after a reset."
|
Lets the player start with the BruteSSH.exe program after a reset.</>
|
||||||
});
|
});
|
||||||
CashRoot.addToFactions(["Sector-12"]);
|
CashRoot.addToFactions(["Sector-12"]);
|
||||||
if (augmentationExists(AugmentationNames.CashRoot)) {
|
if (augmentationExists(AugmentationNames.CashRoot)) {
|
||||||
@@ -1557,8 +1571,7 @@ function initAugmentations() {
|
|||||||
"synthesizes glucose, amino acids, and vitamins and redistributes them " +
|
"synthesizes glucose, amino acids, and vitamins and redistributes them " +
|
||||||
"across the body. The device is powered by the body's naturally wasted " +
|
"across the body. The device is powered by the body's naturally wasted " +
|
||||||
"energy in the form of heat.<br><br>" +
|
"energy in the form of heat.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the player's experience gain rate for all combat stats by 20%.",
|
||||||
"Increases the player's experience gain rate for all combat stats by 20%.",
|
|
||||||
strength_exp_mult: 1.2,
|
strength_exp_mult: 1.2,
|
||||||
defense_exp_mult: 1.2,
|
defense_exp_mult: 1.2,
|
||||||
dexterity_exp_mult: 1.2,
|
dexterity_exp_mult: 1.2,
|
||||||
@@ -1768,8 +1781,7 @@ function initAugmentations() {
|
|||||||
"nature of the plasma disrupts the electrical systems of Augmentations. However, " +
|
"nature of the plasma disrupts the electrical systems of Augmentations. However, " +
|
||||||
"it can also be effective against non-augmented enemies due to its high temperature " +
|
"it can also be effective against non-augmented enemies due to its high temperature " +
|
||||||
"and concussive force.<br><br>" +
|
"and concussive force.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 6%.",
|
||||||
"Increases the player's success chance in Bladeburner contracts/operations by 6%.",
|
|
||||||
bladeburner_success_chance_mult: 1.06,
|
bladeburner_success_chance_mult: 1.06,
|
||||||
isSpecial: true,
|
isSpecial: true,
|
||||||
});
|
});
|
||||||
@@ -1782,8 +1794,7 @@ function initAugmentations() {
|
|||||||
"is more advanced and powerful than the original V1 model. This V2 model is " +
|
"is more advanced and powerful than the original V1 model. This V2 model is " +
|
||||||
"more power-efficiency, more accurate, and can fire plasma bolts at a much " +
|
"more power-efficiency, more accurate, and can fire plasma bolts at a much " +
|
||||||
"higher velocity than the V1 model.<br><br>" +
|
"higher velocity than the V1 model.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
|
||||||
prereqs:[AugmentationNames.HyperionV1],
|
prereqs:[AugmentationNames.HyperionV1],
|
||||||
bladeburner_success_chance_mult: 1.08,
|
bladeburner_success_chance_mult: 1.08,
|
||||||
isSpecial: true,
|
isSpecial: true,
|
||||||
@@ -1941,8 +1952,7 @@ function initAugmentations() {
|
|||||||
info:"Upgrades the BLADE-51b Tesla Armor with a concentrated deuterium-fluoride laser " +
|
info:"Upgrades the BLADE-51b Tesla Armor with a concentrated deuterium-fluoride laser " +
|
||||||
"weapon. It's precision an accuracy makes it useful for quickly neutralizing " +
|
"weapon. It's precision an accuracy makes it useful for quickly neutralizing " +
|
||||||
"threats while keeping casualties to a minimum.<br><br>" +
|
"threats while keeping casualties to a minimum.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
||||||
"Increases the player's success chance in Bladeburner contracts/operations by 8%.",
|
|
||||||
prereqs:[AugmentationNames.BladeArmor],
|
prereqs:[AugmentationNames.BladeArmor],
|
||||||
bladeburner_success_chance_mult: 1.08,
|
bladeburner_success_chance_mult: 1.08,
|
||||||
isSpecial: true,
|
isSpecial: true,
|
||||||
@@ -1956,8 +1966,7 @@ function initAugmentations() {
|
|||||||
"multiple-fiber system. The upgraded weapon uses multiple fiber laser " +
|
"multiple-fiber system. The upgraded weapon uses multiple fiber laser " +
|
||||||
"modules that combine together to form a single, more powerful beam of up to " +
|
"modules that combine together to form a single, more powerful beam of up to " +
|
||||||
"2000MW.<br><br>" +
|
"2000MW.<br><br>" +
|
||||||
"This augmentation:<br>" +
|
"This augmentation increases the player's success chance in Bladeburner contracts/operations by 10%.",
|
||||||
"Increases the player's success chance in Bladeburner contracts/operations by 10%.",
|
|
||||||
prereqs:[AugmentationNames.BladeArmorUnibeam],
|
prereqs:[AugmentationNames.BladeArmorUnibeam],
|
||||||
bladeburner_success_chance_mult: 1.1,
|
bladeburner_success_chance_mult: 1.1,
|
||||||
isSpecial: true,
|
isSpecial: true,
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export let AugmentationNames: IMap<string> = {
|
|||||||
BrachiBlades: "BrachiBlades",
|
BrachiBlades: "BrachiBlades",
|
||||||
BionicArms: "Bionic Arms",
|
BionicArms: "Bionic Arms",
|
||||||
SNA: "Social Negotiation Assistant (S.N.A)",
|
SNA: "Social Negotiation Assistant (S.N.A)",
|
||||||
|
HydroflameLeftArm: "Hydroflame Left Arm",
|
||||||
EsperEyewear: "EsperTech Bladeburner Eyewear",
|
EsperEyewear: "EsperTech Bladeburner Eyewear",
|
||||||
EMS4Recombination: "EMS-4 Recombination",
|
EMS4Recombination: "EMS-4 Recombination",
|
||||||
OrionShoulder: "ORION-MKIV Shoulder",
|
OrionShoulder: "ORION-MKIV Shoulder",
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ export function PlayerMultipliers(): React.ReactElement {
|
|||||||
let elems: any[] = [];
|
let elems: any[] = [];
|
||||||
if(r) {
|
if(r) {
|
||||||
elems = [
|
elems = [
|
||||||
<td key='2'> => </td>,
|
<td key="2"> {"=>"} </td>,
|
||||||
<td key='3'>{numeralWrapper.formatPercentage(r)}</td>
|
<td key="3">{numeralWrapper.formatPercentage(r)}</td>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return elems;
|
return elems;
|
||||||
@@ -36,8 +36,8 @@ export function PlayerMultipliers(): React.ReactElement {
|
|||||||
return <table>
|
return <table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{rows.map((r: any) => <tr key={r[0]}>
|
{rows.map((r: any) => <tr key={r[0]}>
|
||||||
<td key='0'><span>{r[0]} multiplier: </span></td>
|
<td key="0"><span>{r[0]} multiplier: </span></td>
|
||||||
<td key='1' style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
|
<td key="1" style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
|
||||||
{improvements(r[2])}
|
{improvements(r[2])}
|
||||||
</tr>)}
|
</tr>)}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
|
|||||||
"Level 3: 56%");
|
"Level 3: 56%");
|
||||||
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
|
||||||
"To iterate is human, to recurse divine.<br><br>" +
|
"To iterate is human, to recurse divine.<br><br>" +
|
||||||
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you Souce-File 12, or " +
|
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you Source-File 12, or " +
|
||||||
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
|
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
|
||||||
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
|
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
|
||||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||||
|
|||||||
@@ -1069,7 +1069,11 @@ Bladeburner.prototype.gainActionStats = function(action, success) {
|
|||||||
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
|
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
|
||||||
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
|
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
|
||||||
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
|
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
|
||||||
Player.gainIntelligenceExp(unweightedIntGain * action.weights.int * skillMult);
|
let intExp = unweightedIntGain * action.weights.int * skillMult;
|
||||||
|
if (intExp > 1) {
|
||||||
|
intExp = Math.pow(intExp, 0.8);
|
||||||
|
}
|
||||||
|
Player.gainIntelligenceExp(intExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.randomEvent = function() {
|
Bladeburner.prototype.randomEvent = function() {
|
||||||
@@ -2071,8 +2075,8 @@ Bladeburner.prototype.updateOperationsUIElement = function(el, action) {
|
|||||||
innerText:"Confirm", class:"a-link-button",
|
innerText:"Confirm", class:"a-link-button",
|
||||||
clickListener:() => {
|
clickListener:() => {
|
||||||
var num = Math.round(parseFloat(input.value));
|
var num = Math.round(parseFloat(input.value));
|
||||||
if (isNaN(num)) {
|
if (isNaN(num) || num < 0) {
|
||||||
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric)")
|
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
|
||||||
} else {
|
} else {
|
||||||
action.teamCount = num;
|
action.teamCount = num;
|
||||||
this.updateOperationsUIElement(el, action);
|
this.updateOperationsUIElement(el, action);
|
||||||
@@ -2223,8 +2227,8 @@ Bladeburner.prototype.updateBlackOpsUIElement = function(el, action) {
|
|||||||
innerText:"Confirm", class:"a-link-button",
|
innerText:"Confirm", class:"a-link-button",
|
||||||
clickListener:() => {
|
clickListener:() => {
|
||||||
var num = Math.round(parseFloat(input.value));
|
var num = Math.round(parseFloat(input.value));
|
||||||
if (isNaN(num)) {
|
if (isNaN(num) || num < 0) {
|
||||||
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric)")
|
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
|
||||||
} else {
|
} else {
|
||||||
action.teamCount = num;
|
action.teamCount = num;
|
||||||
this.updateBlackOpsUIElement(el, action);
|
this.updateBlackOpsUIElement(el, action);
|
||||||
@@ -3207,7 +3211,7 @@ Bladeburner.prototype.setTeamSizeNetscriptFn = function(type, name, size, worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sanitizedSize = Math.round(size);
|
const sanitizedSize = Math.round(size);
|
||||||
if (isNaN(sanitizedSize)) {
|
if (isNaN(sanitizedSize) || sanitizedSize < 0) {
|
||||||
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`);
|
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
|
|||||||
BlackOperations["Operation Zero"] = new BlackOperation({
|
BlackOperations["Operation Zero"] = new BlackOperation({
|
||||||
name:"Operation Zero",
|
name:"Operation Zero",
|
||||||
desc:"AeroCorp is one of the world's largest defense contractors. " +
|
desc:"AeroCorp is one of the world's largest defense contractors. " +
|
||||||
"It's leader, Steve Watataki, is thought to be a supporter of " +
|
"Its leader, Steve Watataki, is thought to be a supporter of " +
|
||||||
"Synthoid rights. He must be removed.<br><br>" +
|
"Synthoid rights. He must be removed.<br><br>" +
|
||||||
"The goal of Operation Zero is to covertly infiltrate AeroCorp and " +
|
"The goal of Operation Zero is to covertly infiltrate AeroCorp and " +
|
||||||
"uncover any incriminating evidence or " +
|
"uncover any incriminating evidence or " +
|
||||||
|
|||||||
424
src/Casino/Blackjack.tsx
Normal file
424
src/Casino/Blackjack.tsx
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { Money } from "../ui/React/Money";
|
||||||
|
import { Game } from "./Game";
|
||||||
|
import { Deck } from "./CardDeck/Deck";
|
||||||
|
import { Hand } from "./CardDeck/Hand";
|
||||||
|
import { InputAdornment } from "@material-ui/core";
|
||||||
|
import { ReactCard } from "./CardDeck/ReactCard";
|
||||||
|
import { MuiTextField } from "../ui/React/MuiTextField";
|
||||||
|
import { MuiButton } from "../ui/React/MuiButton";
|
||||||
|
import { MuiPaper } from "../ui/React/MuiPaper";
|
||||||
|
|
||||||
|
const MAX_BET = 100e6;
|
||||||
|
|
||||||
|
enum Result {
|
||||||
|
Pending = "",
|
||||||
|
PlayerWon = "You won!",
|
||||||
|
PlayerWonByBlackjack = "You Won! Blackjack!",
|
||||||
|
DealerWon = "You lost!",
|
||||||
|
Tie = "Push! (Tie)",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
p: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
type State ={
|
||||||
|
playerHand: Hand;
|
||||||
|
dealerHand: Hand;
|
||||||
|
bet: number;
|
||||||
|
betInput: string;
|
||||||
|
gameInProgress: boolean;
|
||||||
|
result: Result;
|
||||||
|
gains: number; // Track gains only for this session
|
||||||
|
wagerInvalid: boolean;
|
||||||
|
wagerInvalidHelperText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Blackjack extends Game<Props, State> {
|
||||||
|
|
||||||
|
deck: Deck;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.deck = new Deck(5); // 5-deck multideck
|
||||||
|
|
||||||
|
const initialBet = 1e6;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
playerHand: new Hand([]),
|
||||||
|
dealerHand: new Hand([]),
|
||||||
|
bet: initialBet,
|
||||||
|
betInput: String(initialBet),
|
||||||
|
gameInProgress: false,
|
||||||
|
result: Result.Pending,
|
||||||
|
gains: 0,
|
||||||
|
wagerInvalid: false,
|
||||||
|
wagerInvalidHelperText: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canStartGame = (): boolean => {
|
||||||
|
const { p } = this.props;
|
||||||
|
const { bet } = this.state;
|
||||||
|
|
||||||
|
return p.canAfford(bet);
|
||||||
|
}
|
||||||
|
|
||||||
|
startGame = (): void => {
|
||||||
|
if (!this.canStartGame()) { return; }
|
||||||
|
|
||||||
|
// Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could
|
||||||
|
// always reload without saving but w.e)
|
||||||
|
this.props.p.loseMoney(this.state.bet);
|
||||||
|
|
||||||
|
const playerHand = new Hand([ this.deck.safeDrawCard(), this.deck.safeDrawCard() ]);
|
||||||
|
const dealerHand = new Hand([ this.deck.safeDrawCard(), this.deck.safeDrawCard() ]);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
playerHand,
|
||||||
|
dealerHand,
|
||||||
|
gameInProgress: true,
|
||||||
|
result: Result.Pending,
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the player is dealt a blackjack and the dealer is not, then the player
|
||||||
|
// immediately wins
|
||||||
|
if (this.getTrueHandValue(playerHand) === 21) {
|
||||||
|
if (this.getTrueHandValue(dealerHand) === 21) {
|
||||||
|
this.finishGame(Result.Tie);
|
||||||
|
} else {
|
||||||
|
this.finishGame(Result.PlayerWonByBlackjack);
|
||||||
|
}
|
||||||
|
} else if (this.getTrueHandValue(dealerHand) === 21) {
|
||||||
|
// Check if dealer won by blackjack. We know at this point that the player does not also have blackjack.
|
||||||
|
this.finishGame(Result.DealerWon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an array of numbers representing all possible values of the given Hand. The reason it needs to be
|
||||||
|
// an array is because an Ace can count as both 1 and 11.
|
||||||
|
getHandValue = (hand: Hand): number[] => {
|
||||||
|
let result: number[] = [ 0 ];
|
||||||
|
|
||||||
|
for (let i = 0 ; i < hand.cards.length; ++i) {
|
||||||
|
const value = hand.cards[i].value;
|
||||||
|
if (value >= 10) {
|
||||||
|
result = result.map((x) => x + 10);
|
||||||
|
} else if (value === 1) {
|
||||||
|
result = result.flatMap((x) => [ x + 1, x + 11 ]);
|
||||||
|
} else {
|
||||||
|
result = result.map((x) => x + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the single hand value used for determine things like victory and whether or not
|
||||||
|
// the dealer has to hit. Essentially this uses the biggest value that's 21 or under. If no such value exists,
|
||||||
|
// then it means the hand is busted and we can just return whatever
|
||||||
|
getTrueHandValue = (hand: Hand): number => {
|
||||||
|
const handValues = this.getHandValue(hand);
|
||||||
|
const valuesUnder21 = handValues.filter((x) => (x <= 21));
|
||||||
|
|
||||||
|
if (valuesUnder21.length > 0) {
|
||||||
|
valuesUnder21.sort((a, b) => a - b);
|
||||||
|
return valuesUnder21[valuesUnder21.length - 1];
|
||||||
|
} else {
|
||||||
|
// Just return the first value. It doesnt really matter anyways since hand is buted
|
||||||
|
return handValues[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all hand values that are 21 or under. If no values are 21 or under, then the first value is returned.
|
||||||
|
getHandDisplayValues = (hand: Hand): number[] => {
|
||||||
|
const handValues = this.getHandValue(hand);
|
||||||
|
if (this.isHandBusted(hand)) {
|
||||||
|
// Hand is busted so just return the 1st value, doesn't really matter
|
||||||
|
return [ ...new Set([ handValues[0] ]) ];
|
||||||
|
} else {
|
||||||
|
return [ ...new Set(handValues.filter((x) => x <= 21)) ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isHandBusted = (hand: Hand): boolean => {
|
||||||
|
return this.getTrueHandValue(hand) > 21;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerHit = (event: React.MouseEvent): void => {
|
||||||
|
if (!event.isTrusted) { return; }
|
||||||
|
|
||||||
|
const newHand = this.state.playerHand.addCards(this.deck.safeDrawCard());
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
playerHand: newHand,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if player busted, and finish the game if so
|
||||||
|
if (this.isHandBusted(newHand)) {
|
||||||
|
this.finishGame(Result.DealerWon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playerStay = (event: React.MouseEvent): void => {
|
||||||
|
if (!event.isTrusted) { return; }
|
||||||
|
|
||||||
|
// Determine if Dealer needs to hit. A dealer must hit if they have 16 or lower.
|
||||||
|
// If the dealer has a Soft 17 (Ace + 6), then they stay.
|
||||||
|
let newDealerHand = this.state.dealerHand;
|
||||||
|
while (true) {
|
||||||
|
// The dealer's "true" hand value is the 2nd one if its 21 or less (the 2nd value is always guaranteed
|
||||||
|
// to be equal or larger). Otherwise its the 1st.
|
||||||
|
const dealerHandValue = this.getTrueHandValue(newDealerHand);
|
||||||
|
|
||||||
|
if (dealerHandValue <= 16) {
|
||||||
|
newDealerHand = newDealerHand.addCards(this.deck.safeDrawCard());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
dealerHand: newDealerHand,
|
||||||
|
})
|
||||||
|
|
||||||
|
// If dealer has busted, then player wins
|
||||||
|
if (this.isHandBusted(newDealerHand)) {
|
||||||
|
this.finishGame(Result.PlayerWon);
|
||||||
|
} else {
|
||||||
|
const dealerHandValue = this.getTrueHandValue(newDealerHand);
|
||||||
|
const playerHandValue = this.getTrueHandValue(this.state.playerHand);
|
||||||
|
|
||||||
|
console.log(`dealerHandValue: ${dealerHandValue}`);
|
||||||
|
console.log(`playerHandValue: ${playerHandValue}`);
|
||||||
|
|
||||||
|
// We expect nobody to have busted. If someone busted, there is an error
|
||||||
|
// in our game logic
|
||||||
|
if (dealerHandValue > 21 || playerHandValue > 21) {
|
||||||
|
throw new Error("Someone busted when not expected to");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerHandValue > dealerHandValue) {
|
||||||
|
this.finishGame(Result.PlayerWon);
|
||||||
|
} else if (playerHandValue < dealerHandValue) {
|
||||||
|
this.finishGame(Result.DealerWon);
|
||||||
|
} else {
|
||||||
|
this.finishGame(Result.Tie);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finishGame = (result: Result): void => {
|
||||||
|
let gains = 0;
|
||||||
|
if (this.isPlayerWinResult(result)) {
|
||||||
|
gains = this.state.bet;
|
||||||
|
|
||||||
|
// We 2x the gains because we took away money at the start, so we need to give the original bet back.
|
||||||
|
this.win(this.props.p, 2 * gains);
|
||||||
|
} else if (result === Result.DealerWon) {
|
||||||
|
gains = -1 * this.state.bet;
|
||||||
|
// Dont need to take money here since we already did it at the start
|
||||||
|
} else if (result === Result.Tie) {
|
||||||
|
this.win(this.props.p, this.state.bet); // Get the original bet back
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
gameInProgress: false,
|
||||||
|
result,
|
||||||
|
gains: this.state.gains + gains,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isPlayerWinResult = (result: Result): boolean => {
|
||||||
|
return (result === Result.PlayerWon || result === Result.PlayerWonByBlackjack);
|
||||||
|
}
|
||||||
|
|
||||||
|
wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
const { p } = this.props;
|
||||||
|
const betInput = event.target.value;
|
||||||
|
const wager = Math.round(parseFloat(betInput));
|
||||||
|
if (isNaN(wager)) {
|
||||||
|
this.setState({
|
||||||
|
bet: 0,
|
||||||
|
betInput,
|
||||||
|
wagerInvalid: true,
|
||||||
|
wagerInvalidHelperText: "Not a valid number",
|
||||||
|
});
|
||||||
|
} else if (wager <= 0) {
|
||||||
|
this.setState({
|
||||||
|
bet: 0,
|
||||||
|
betInput,
|
||||||
|
wagerInvalid: true,
|
||||||
|
wagerInvalidHelperText: "Must bet a postive amount",
|
||||||
|
});
|
||||||
|
} else if (wager > MAX_BET) {
|
||||||
|
this.setState({
|
||||||
|
bet: 0,
|
||||||
|
betInput,
|
||||||
|
wagerInvalid: true,
|
||||||
|
wagerInvalidHelperText: "Exceeds max bet",
|
||||||
|
});
|
||||||
|
} else if (!p.canAfford(wager)) {
|
||||||
|
this.setState({
|
||||||
|
bet: 0,
|
||||||
|
betInput,
|
||||||
|
wagerInvalid: true,
|
||||||
|
wagerInvalidHelperText: "Not enough money",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Valid wager
|
||||||
|
this.setState({
|
||||||
|
bet: wager,
|
||||||
|
betInput,
|
||||||
|
wagerInvalid: false,
|
||||||
|
wagerInvalidHelperText: "",
|
||||||
|
result: Result.Pending, // Reset previous game status to clear the win/lose text UI
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start game button
|
||||||
|
startOnClick = (event: React.MouseEvent): void => {
|
||||||
|
// Protect against scripting...although maybe this would be fun to automate
|
||||||
|
if (!event.isTrusted) { return; }
|
||||||
|
|
||||||
|
if (!this.state.wagerInvalid) {
|
||||||
|
this.startGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): React.ReactNode {
|
||||||
|
const {
|
||||||
|
betInput,
|
||||||
|
playerHand,
|
||||||
|
dealerHand,
|
||||||
|
gameInProgress,
|
||||||
|
result,
|
||||||
|
wagerInvalid,
|
||||||
|
wagerInvalidHelperText,
|
||||||
|
gains,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
// Get the player totals to display.
|
||||||
|
const playerHandValues = this.getHandDisplayValues(playerHand);
|
||||||
|
const dealerHandValues = this.getHandDisplayValues(dealerHand);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Wager input */}
|
||||||
|
<div>
|
||||||
|
<MuiTextField
|
||||||
|
value={betInput}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
{"Wager (Max: "}
|
||||||
|
{Money(MAX_BET)}
|
||||||
|
{")"}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
disabled={gameInProgress}
|
||||||
|
onChange={this.wagerOnChange}
|
||||||
|
error={wagerInvalid}
|
||||||
|
helperText={wagerInvalid ? wagerInvalidHelperText : ""}
|
||||||
|
type="number"
|
||||||
|
variant="filled"
|
||||||
|
style={{
|
||||||
|
width: "200px",
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: <InputAdornment position="start" >$</InputAdornment>,
|
||||||
|
}} />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{"Total earnings this session: "}
|
||||||
|
{Money(gains)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Buttons */}
|
||||||
|
{!gameInProgress ? (
|
||||||
|
<div>
|
||||||
|
<MuiButton
|
||||||
|
color="primary"
|
||||||
|
onClick={this.startOnClick}
|
||||||
|
disabled={wagerInvalid || !this.canStartGame()}>
|
||||||
|
|
||||||
|
Start
|
||||||
|
</MuiButton>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<MuiButton color="primary" onClick={this.playerHit} >
|
||||||
|
Hit
|
||||||
|
</MuiButton>
|
||||||
|
<MuiButton color="secondary" onClick={this.playerStay} >
|
||||||
|
Stay
|
||||||
|
</MuiButton>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Main game part. Displays both if the game is in progress OR if there's a result so you can see
|
||||||
|
* the cards that led to that result. */}
|
||||||
|
{(gameInProgress || result !== Result.Pending) && (
|
||||||
|
<div>
|
||||||
|
<MuiPaper variant="outlined" elevation={2}>
|
||||||
|
<pre>Player</pre>
|
||||||
|
{playerHand.cards.map((card, i) => (
|
||||||
|
<ReactCard card={card} key={i} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
<pre>Value(s): </pre>
|
||||||
|
{playerHandValues.map((value, i) => (
|
||||||
|
<pre key={i}>{value}</pre>
|
||||||
|
))}
|
||||||
|
</MuiPaper>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<MuiPaper variant="outlined" elevation={2}>
|
||||||
|
<pre>Dealer</pre>
|
||||||
|
{dealerHand.cards.map((card, i) => (
|
||||||
|
// Hide every card except the first while game is in progress
|
||||||
|
<ReactCard card={card} hidden={gameInProgress && i !== 0} key={i} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
{!gameInProgress && (
|
||||||
|
<>
|
||||||
|
<pre>Value(s): </pre>
|
||||||
|
{dealerHandValues.map((value, i) => (
|
||||||
|
<pre key={i}>{value}</pre>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</MuiPaper>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Results from previous round */}
|
||||||
|
{result !== Result.Pending && (
|
||||||
|
<p>
|
||||||
|
{result}
|
||||||
|
{this.isPlayerWinResult(result) && (
|
||||||
|
<>
|
||||||
|
{" You gained "}
|
||||||
|
{Money(this.state.bet)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{result === Result.DealerWon && (
|
||||||
|
<>
|
||||||
|
{" You lost "}
|
||||||
|
{Money(this.state.bet)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/Casino/CardDeck/Card.ts
Normal file
42
src/Casino/CardDeck/Card.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Enum values are lowercased to match css classes
|
||||||
|
export enum Suit {
|
||||||
|
Clubs = "clubs",
|
||||||
|
Diamonds = "diamonds",
|
||||||
|
Hearts = "hearts",
|
||||||
|
Spades = "spades",
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Card {
|
||||||
|
|
||||||
|
constructor(readonly value: number, readonly suit: Suit) {
|
||||||
|
if (value < 1 || value > 13) {
|
||||||
|
throw new Error(`Card instantiated with improper value: ${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatValue(): string {
|
||||||
|
switch (this.value) {
|
||||||
|
case 1:
|
||||||
|
return "A";
|
||||||
|
case 11:
|
||||||
|
return "J";
|
||||||
|
case 12:
|
||||||
|
return "Q";
|
||||||
|
case 13:
|
||||||
|
return "K";
|
||||||
|
default:
|
||||||
|
return `${this.value}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isRedSuit(): boolean {
|
||||||
|
return this.suit === Suit.Hearts || this.suit === Suit.Diamonds;
|
||||||
|
}
|
||||||
|
|
||||||
|
getStringRepresentation(): string {
|
||||||
|
const value = this.formatValue();
|
||||||
|
|
||||||
|
return `${value} of ${this.suit}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
58
src/Casino/CardDeck/Deck.ts
Normal file
58
src/Casino/CardDeck/Deck.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { Card, Suit } from "./Card";
|
||||||
|
import { shuffle } from "lodash";
|
||||||
|
|
||||||
|
export class Deck {
|
||||||
|
|
||||||
|
private cards: Card[] = [];
|
||||||
|
|
||||||
|
// Support multiple decks
|
||||||
|
constructor(private numDecks = 1) {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
shuffle(): void {
|
||||||
|
this.cards = shuffle(this.cards); // Just use lodash
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCard(): Card {
|
||||||
|
if (this.cards.length == 0) {
|
||||||
|
throw new Error("Tried to draw card from empty deck");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.cards.shift() as Card; // Guaranteed to return a Card since we throw an Error if array is empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws a card, resetting the deck beforehands if the Deck is empty
|
||||||
|
safeDrawCard(): Card {
|
||||||
|
if (this.cards.length === 0) {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.drawCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the deck back to the original 52 cards and shuffle it
|
||||||
|
reset(): void {
|
||||||
|
this.cards = [];
|
||||||
|
|
||||||
|
for (let i = 1; i <= 13; ++i) {
|
||||||
|
for (let j = 0; j < this.numDecks; ++j) {
|
||||||
|
this.cards.push(new Card(i, Suit.Clubs));
|
||||||
|
this.cards.push(new Card(i, Suit.Diamonds));
|
||||||
|
this.cards.push(new Card(i, Suit.Hearts));
|
||||||
|
this.cards.push(new Card(i, Suit.Spades));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shuffle();
|
||||||
|
}
|
||||||
|
|
||||||
|
size(): number {
|
||||||
|
return this.cards.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty(): boolean {
|
||||||
|
return this.cards.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
src/Casino/CardDeck/Hand.ts
Normal file
25
src/Casino/CardDeck/Hand.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Represents a Hand of cards.
|
||||||
|
*
|
||||||
|
* This class is IMMUTABLE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Card } from "./Card";
|
||||||
|
|
||||||
|
export class Hand {
|
||||||
|
|
||||||
|
constructor(readonly cards: readonly Card[]) {}
|
||||||
|
|
||||||
|
addCards(...cards: Card[]): Hand {
|
||||||
|
return new Hand([ ...this.cards, ...cards ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeByIndex(i: number): Hand {
|
||||||
|
if (i >= this.cards.length) {
|
||||||
|
throw new Error(`Tried to remove invalid card from Hand by index: ${i}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Hand([ ...this.cards.slice().splice(i, 1) ])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
src/Casino/CardDeck/ReactCard.tsx
Normal file
40
src/Casino/CardDeck/ReactCard.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import React, { FC } from "react";
|
||||||
|
import { Card, Suit } from "./Card";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
card: Card;
|
||||||
|
hidden?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ReactCard: FC<Props> = ({ card, hidden }) => {
|
||||||
|
let suit : React.ReactNode;
|
||||||
|
switch (card.suit) {
|
||||||
|
case Suit.Clubs:
|
||||||
|
suit = <span>♣</span>;
|
||||||
|
break;
|
||||||
|
case Suit.Diamonds:
|
||||||
|
suit = <span>♦</span>;
|
||||||
|
break;
|
||||||
|
case Suit.Hearts:
|
||||||
|
suit = <span>♥</span>;
|
||||||
|
break;
|
||||||
|
case Suit.Spades:
|
||||||
|
suit = <span>♠</span>;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`MissingCaseException: ${card.suit}`);
|
||||||
|
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={`casino-card ${card.isRedSuit() ? "red" : "black"}`}>
|
||||||
|
<>
|
||||||
|
<div className="value">
|
||||||
|
{hidden ? " - " : card.formatValue()}
|
||||||
|
</div>
|
||||||
|
<div className={`suit`}>
|
||||||
|
{hidden ? " - " : suit}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,10 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { StdButton } from "../ui/React/StdButton";
|
import { StdButton } from "../ui/React/StdButton";
|
||||||
import { BadRNG } from "./RNG";
|
import { BadRNG } from "./RNG";
|
||||||
import { Game } from "./Game";
|
import { Game } from "./Game";
|
||||||
|
import { trusted } from "./utils";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
p: IPlayer;
|
p: IPlayer;
|
||||||
@@ -18,8 +19,10 @@ type IState = {
|
|||||||
investment: number;
|
investment: number;
|
||||||
result: any;
|
result: any;
|
||||||
status: string;
|
status: string;
|
||||||
|
playLock: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const minPlay = 0;
|
||||||
const maxPlay = 10e3;
|
const maxPlay = 10e3;
|
||||||
|
|
||||||
export class CoinFlip extends Game<IProps, IState> {
|
export class CoinFlip extends Game<IProps, IState> {
|
||||||
@@ -31,6 +34,7 @@ export class CoinFlip extends Game<IProps, IState> {
|
|||||||
investment: 1000,
|
investment: 1000,
|
||||||
result: <span> </span>,
|
result: <span> </span>,
|
||||||
status: '',
|
status: '',
|
||||||
|
playLock: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.play = this.play.bind(this);
|
this.play = this.play.bind(this);
|
||||||
@@ -40,11 +44,14 @@ export class CoinFlip extends Game<IProps, IState> {
|
|||||||
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
||||||
let investment: number = parseInt(e.currentTarget.value);
|
let investment: number = parseInt(e.currentTarget.value);
|
||||||
if (isNaN(investment)) {
|
if (isNaN(investment)) {
|
||||||
investment = 1000;
|
investment = minPlay;
|
||||||
}
|
}
|
||||||
if (investment > maxPlay) {
|
if (investment > maxPlay) {
|
||||||
investment = maxPlay;
|
investment = maxPlay;
|
||||||
}
|
}
|
||||||
|
if (investment < minPlay) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
this.setState({investment: investment});
|
this.setState({investment: investment});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +68,9 @@ export class CoinFlip extends Game<IProps, IState> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
result: <span className={correct ? "text" : "failure"}>{letter}</span>,
|
result: <span className={correct ? "text" : "failure"}>{letter}</span>,
|
||||||
status: correct ? " win!" : "lose!",
|
status: correct ? " win!" : "lose!",
|
||||||
|
playLock: true,
|
||||||
});
|
});
|
||||||
|
setTimeout(()=>this.setState({playLock: false}), 250);
|
||||||
if (correct) {
|
if (correct) {
|
||||||
this.win(this.props.p, this.state.investment);
|
this.win(this.props.p, this.state.investment);
|
||||||
} else {
|
} else {
|
||||||
@@ -81,8 +90,8 @@ export class CoinFlip extends Game<IProps, IState> {
|
|||||||
+———————+<br />
|
+———————+<br />
|
||||||
</pre>
|
</pre>
|
||||||
<span className="text">Play for: </span><input type="number" className='text-input' onChange={this.updateInvestment} value={this.state.investment} /><br />
|
<span className="text">Play for: </span><input type="number" className='text-input' onChange={this.updateInvestment} value={this.state.investment} /><br />
|
||||||
<StdButton onClick={() => this.play('H')} text={"Head!"} />
|
<StdButton onClick={trusted(() => this.play('H'))} text={"Head!"} disabled={this.state.playLock} />
|
||||||
<StdButton onClick={() => this.play('T')} text={"Tail!"} />
|
<StdButton onClick={trusted(() => this.play('T'))} text={"Tail!"} disabled={this.state.playLock} />
|
||||||
<h1>{this.state.status}</h1>
|
<h1>{this.state.status}</h1>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { dialogBoxCreate } from "../../utils/DialogBox";
|
|||||||
const gainLimit = 10e9;
|
const gainLimit = 10e9;
|
||||||
|
|
||||||
export class Game<T,U> extends React.Component<T, U> {
|
export class Game<T,U> extends React.Component<T, U> {
|
||||||
win(p: IPlayer, n: number) {
|
win(p: IPlayer, n: number): void{
|
||||||
p.gainMoney(n);
|
p.gainMoney(n);
|
||||||
p.recordMoneySource(n, "casino");
|
p.recordMoneySource(n, "casino");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { StdButton } from "../ui/React/StdButton";
|
import { StdButton } from "../ui/React/StdButton";
|
||||||
import { Money } from "../ui/React/Money";
|
import { Money } from "../ui/React/Money";
|
||||||
import { Game } from "./Game";
|
import { Game } from "./Game";
|
||||||
import { WHRNG } from "./RNG";
|
import { WHRNG } from "./RNG";
|
||||||
|
import { trusted } from "./utils";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
p: IPlayer;
|
p: IPlayer;
|
||||||
@@ -19,7 +20,8 @@ type IState = {
|
|||||||
strategy: Strategy;
|
strategy: Strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxPlay = 1e6;
|
const minPlay = 0;
|
||||||
|
const maxPlay = 1e7;
|
||||||
|
|
||||||
function isRed(n: number): boolean {
|
function isRed(n: number): boolean {
|
||||||
return [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
|
return [1, 3, 5, 7, 9, 12, 14, 16, 18, 19,
|
||||||
@@ -165,10 +167,13 @@ export class Roulette extends Game<IProps, IState> {
|
|||||||
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
||||||
let investment: number = parseInt(e.currentTarget.value);
|
let investment: number = parseInt(e.currentTarget.value);
|
||||||
if (isNaN(investment)) {
|
if (isNaN(investment)) {
|
||||||
investment = 1000;
|
investment = minPlay;
|
||||||
}
|
}
|
||||||
if (investment > maxPlay) {
|
if (investment > maxPlay) {
|
||||||
investment = maxPlay
|
investment = maxPlay;
|
||||||
|
}
|
||||||
|
if (investment < minPlay) {
|
||||||
|
investment = minPlay;
|
||||||
}
|
}
|
||||||
this.setState({investment: investment});
|
this.setState({investment: investment});
|
||||||
}
|
}
|
||||||
@@ -226,62 +231,62 @@ export class Roulette extends Game<IProps, IState> {
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><StdButton text={"3"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(3))} /></td>
|
<td><StdButton text={"3"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(3)))} /></td>
|
||||||
<td><StdButton text={"6"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(6))} /></td>
|
<td><StdButton text={"6"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(6)))} /></td>
|
||||||
<td><StdButton text={"9"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(9))} /></td>
|
<td><StdButton text={"9"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(9)))} /></td>
|
||||||
<td><StdButton text={"12"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(12))} /></td>
|
<td><StdButton text={"12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(12)))} /></td>
|
||||||
<td><StdButton text={"15"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(15))} /></td>
|
<td><StdButton text={"15"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(15)))} /></td>
|
||||||
<td><StdButton text={"18"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(18))} /></td>
|
<td><StdButton text={"18"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(18)))} /></td>
|
||||||
<td><StdButton text={"21"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(21))} /></td>
|
<td><StdButton text={"21"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(21)))} /></td>
|
||||||
<td><StdButton text={"24"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(24))} /></td>
|
<td><StdButton text={"24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(24)))} /></td>
|
||||||
<td><StdButton text={"27"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(27))} /></td>
|
<td><StdButton text={"27"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(27)))} /></td>
|
||||||
<td><StdButton text={"30"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(30))} /></td>
|
<td><StdButton text={"30"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(30)))} /></td>
|
||||||
<td><StdButton text={"33"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(33))} /></td>
|
<td><StdButton text={"33"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(33)))} /></td>
|
||||||
<td><StdButton text={"36"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(36))} /></td>
|
<td><StdButton text={"36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(36)))} /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><StdButton text={"2"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(2))} /></td>
|
<td><StdButton text={"2"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(2)))} /></td>
|
||||||
<td><StdButton text={"5"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(5))} /></td>
|
<td><StdButton text={"5"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(5)))} /></td>
|
||||||
<td><StdButton text={"8"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(8))} /></td>
|
<td><StdButton text={"8"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(8)))} /></td>
|
||||||
<td><StdButton text={"11"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(11))} /></td>
|
<td><StdButton text={"11"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(11)))} /></td>
|
||||||
<td><StdButton text={"14"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(14))} /></td>
|
<td><StdButton text={"14"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(14)))} /></td>
|
||||||
<td><StdButton text={"17"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(17))} /></td>
|
<td><StdButton text={"17"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(17)))} /></td>
|
||||||
<td><StdButton text={"20"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(20))} /></td>
|
<td><StdButton text={"20"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(20)))} /></td>
|
||||||
<td><StdButton text={"23"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(23))} /></td>
|
<td><StdButton text={"23"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(23)))} /></td>
|
||||||
<td><StdButton text={"26"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(26))} /></td>
|
<td><StdButton text={"26"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(26)))} /></td>
|
||||||
<td><StdButton text={"29"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(29))} /></td>
|
<td><StdButton text={"29"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(29)))} /></td>
|
||||||
<td><StdButton text={"32"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(32))} /></td>
|
<td><StdButton text={"32"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(32)))} /></td>
|
||||||
<td><StdButton text={"35"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(35))} /></td>
|
<td><StdButton text={"35"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(35)))} /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><StdButton text={"1"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(1))} /></td>
|
<td><StdButton text={"1"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(1)))} /></td>
|
||||||
<td><StdButton text={"4"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(4))} /></td>
|
<td><StdButton text={"4"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(4)))} /></td>
|
||||||
<td><StdButton text={"7"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(7))} /></td>
|
<td><StdButton text={"7"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(7)))} /></td>
|
||||||
<td><StdButton text={"10"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(10))} /></td>
|
<td><StdButton text={"10"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(10)))} /></td>
|
||||||
<td><StdButton text={"13"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(13))} /></td>
|
<td><StdButton text={"13"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(13)))} /></td>
|
||||||
<td><StdButton text={"16"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(16))} /></td>
|
<td><StdButton text={"16"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(16)))} /></td>
|
||||||
<td><StdButton text={"19"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(19))} /></td>
|
<td><StdButton text={"19"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(19)))} /></td>
|
||||||
<td><StdButton text={"22"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(22))} /></td>
|
<td><StdButton text={"22"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(22)))} /></td>
|
||||||
<td><StdButton text={"25"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(25))} /></td>
|
<td><StdButton text={"25"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(25)))} /></td>
|
||||||
<td><StdButton text={"28"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(28))} /></td>
|
<td><StdButton text={"28"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(28)))} /></td>
|
||||||
<td><StdButton text={"31"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(31))} /></td>
|
<td><StdButton text={"31"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(31)))} /></td>
|
||||||
<td><StdButton text={"34"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(34))} /></td>
|
<td><StdButton text={"34"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(34)))} /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={4}><StdButton text={"1 to 12"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Third1)} /></td>
|
<td colSpan={4}><StdButton text={"1 to 12"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third1))} /></td>
|
||||||
<td colSpan={4}><StdButton text={"13 to 24"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Third2)} /></td>
|
<td colSpan={4}><StdButton text={"13 to 24"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third2))} /></td>
|
||||||
<td colSpan={4}><StdButton text={"25 to 36"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Third3)} /></td>
|
<td colSpan={4}><StdButton text={"25 to 36"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Third3))} /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={2}><StdButton text={"Red"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Red)} /></td>
|
<td colSpan={2}><StdButton text={"Red"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Red))} /></td>
|
||||||
<td colSpan={2}><StdButton text={"Black"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Black)} /></td>
|
<td colSpan={2}><StdButton text={"Black"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Black))} /></td>
|
||||||
<td colSpan={2}><StdButton text={"Odd"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Odd)} /></td>
|
<td colSpan={2}><StdButton text={"Odd"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Odd))} /></td>
|
||||||
<td colSpan={2}><StdButton text={"Even"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Even)} /></td>
|
<td colSpan={2}><StdButton text={"Even"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Even))} /></td>
|
||||||
<td colSpan={2}><StdButton text={"High"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.High)} /></td>
|
<td colSpan={2}><StdButton text={"High"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.High))} /></td>
|
||||||
<td colSpan={2}><StdButton text={"Low"} disabled={!this.state.canPlay} onClick={()=>this.play(strategies.Low)} /></td>
|
<td colSpan={2}><StdButton text={"Low"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(strategies.Low))} /></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><StdButton text={"0"} disabled={!this.state.canPlay} onClick={()=>this.play(Single(0))} /></td>
|
<td><StdButton text={"0"} disabled={!this.state.canPlay} onClick={trusted(()=>this.play(Single(0)))} /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { IPlayer } from "../PersonObjects/IPlayer";
|
|||||||
import { StdButton } from "../ui/React/StdButton";
|
import { StdButton } from "../ui/React/StdButton";
|
||||||
import { Money } from "../ui/React/Money";
|
import { Money } from "../ui/React/Money";
|
||||||
import { WHRNG } from "./RNG";
|
import { WHRNG } from "./RNG";
|
||||||
import { Game } from "./Game";
|
import { Game } from "./Game";
|
||||||
|
import { trusted } from "./utils";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
p: IPlayer;
|
p: IPlayer;
|
||||||
@@ -57,6 +58,7 @@ const payLines = [
|
|||||||
[[1, 0], [2, 1], [2, 2], [2, 3], [1, 4]],
|
[[1, 0], [2, 1], [2, 2], [2, 3], [1, 4]],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const minPlay = 0;
|
||||||
const maxPlay = 1e6;
|
const maxPlay = 1e6;
|
||||||
|
|
||||||
export class SlotMachine extends Game<IProps, IState> {
|
export class SlotMachine extends Game<IProps, IState> {
|
||||||
@@ -184,11 +186,14 @@ export class SlotMachine extends Game<IProps, IState> {
|
|||||||
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
updateInvestment(e: React.FormEvent<HTMLInputElement>) {
|
||||||
let investment: number = parseInt(e.currentTarget.value);
|
let investment: number = parseInt(e.currentTarget.value);
|
||||||
if (isNaN(investment)) {
|
if (isNaN(investment)) {
|
||||||
investment = 1000;
|
investment = minPlay;
|
||||||
}
|
}
|
||||||
if (investment > maxPlay) {
|
if (investment > maxPlay) {
|
||||||
investment = maxPlay;
|
investment = maxPlay;
|
||||||
}
|
}
|
||||||
|
if (investment < minPlay) {
|
||||||
|
investment = minPlay;
|
||||||
|
}
|
||||||
this.setState({investment: investment});
|
this.setState({investment: investment});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +210,7 @@ export class SlotMachine extends Game<IProps, IState> {
|
|||||||
+———————————————————————+<br />
|
+———————————————————————+<br />
|
||||||
</pre>
|
</pre>
|
||||||
<input type="number" className='text-input' onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
|
<input type="number" className='text-input' onChange={this.updateInvestment} placeholder={"Amount to play"} value={this.state.investment} disabled={!this.state.canPlay} />
|
||||||
<StdButton onClick={this.play} text={"Spin!"} disabled={!this.state.canPlay} />
|
<StdButton onClick={trusted(this.play)} text={"Spin!"} disabled={!this.state.canPlay} />
|
||||||
<h1>{this.state.status}</h1>
|
<h1>{this.state.status}</h1>
|
||||||
<h2>Pay lines</h2>
|
<h2>Pay lines</h2>
|
||||||
<pre>
|
<pre>
|
||||||
|
|||||||
8
src/Casino/utils.ts
Normal file
8
src/Casino/utils.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export function trusted(f: () => void): (event: React.MouseEvent<HTMLElement, MouseEvent>) => any {
|
||||||
|
return function(event: React.MouseEvent<HTMLElement, MouseEvent>): any {
|
||||||
|
if(!event.isTrusted) return;
|
||||||
|
f();
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -181,6 +181,9 @@ export class CodingContract {
|
|||||||
return new Promise<CodingContractResult>((resolve: Function, reject: Function) => {
|
return new Promise<CodingContractResult>((resolve: Function, reject: Function) => {
|
||||||
const contractType: CodingContractType = CodingContractTypes[this.type];
|
const contractType: CodingContractType = CodingContractTypes[this.type];
|
||||||
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
||||||
|
const title: HTMLElement = createElement("h1", {
|
||||||
|
innerHTML: this.type,
|
||||||
|
});
|
||||||
const txt: HTMLElement = createElement("p", {
|
const txt: HTMLElement = createElement("p", {
|
||||||
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
||||||
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
||||||
@@ -225,7 +228,7 @@ export class CodingContract {
|
|||||||
innerText: "Cancel",
|
innerText: "Cancel",
|
||||||
});
|
});
|
||||||
const lineBreak: HTMLElement = createElement("br");
|
const lineBreak: HTMLElement = createElement("br");
|
||||||
createPopup(popupId, [txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
createPopup(popupId, [title, lineBreak, txt, lineBreak, lineBreak, answerInput, solveBtn, cancelBtn]);
|
||||||
answerInput.focus();
|
answerInput.focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
import { IMap } from "./types";
|
import { IMap } from "./types";
|
||||||
|
|
||||||
export let CONSTANTS: IMap<any> = {
|
export let CONSTANTS: IMap<any> = {
|
||||||
Version: "0.51.2",
|
Version: "0.51.6",
|
||||||
|
|
||||||
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
||||||
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
||||||
* the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
|
* the player will have this level assuming no multipliers. Multipliers can cause skills to go above this.
|
||||||
*/
|
*/
|
||||||
MaxSkillLevel: 975,
|
MaxSkillLevel: 975,
|
||||||
|
|
||||||
// Milliseconds per game cycle
|
// Milliseconds per game cycle
|
||||||
MilliPerCycle: 200,
|
MilliPerCycle: 200,
|
||||||
@@ -218,7 +218,7 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
CrimeHeist: "pull off the ultimate heist",
|
CrimeHeist: "pull off the ultimate heist",
|
||||||
|
|
||||||
// Coding Contract
|
// Coding Contract
|
||||||
// TODO Move this into Coding contract impelmentation?
|
// TODO: Move this into Coding contract implementation?
|
||||||
CodingContractBaseFactionRepGain: 2500,
|
CodingContractBaseFactionRepGain: 2500,
|
||||||
CodingContractBaseCompanyRepGain: 4000,
|
CodingContractBaseCompanyRepGain: 4000,
|
||||||
CodingContractBaseMoneyGain: 75e6,
|
CodingContractBaseMoneyGain: 75e6,
|
||||||
@@ -228,16 +228,42 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
|
|
||||||
LatestUpdate:
|
LatestUpdate:
|
||||||
`
|
`
|
||||||
v0.51.2 - 2021-04-09 Vegas, Baby! (hydroflame)
|
v0.51.6 - 2021-04-28 Backdoor! (Community)
|
||||||
-------
|
-------
|
||||||
|
|
||||||
New location: The Iker Molina Casino
|
Backdoor
|
||||||
* A casino opened in Aevum. However the house is rumored to cheat. If only
|
* a new terminal command, backdoor, has been added to help differentiate
|
||||||
we could give them a taste of their own medicine.
|
between the terminal hack command and the netscript hack function. (@dewint)
|
||||||
|
|
||||||
|
Milestones
|
||||||
|
* A new tab under the Help menu has been added to guide players through the
|
||||||
|
game.
|
||||||
|
|
||||||
|
Casino
|
||||||
|
* Blackjack has been added (@BigD)
|
||||||
|
|
||||||
|
Netscript
|
||||||
|
* 'prompt' now converts input to JSON.
|
||||||
|
* 'getRunningScript' is a new netscript function that returns a bunch of
|
||||||
|
data related to a running script.
|
||||||
|
|
||||||
|
Coding contracts
|
||||||
|
* trivial puzzles should no longer appear.
|
||||||
|
|
||||||
|
Infiltration
|
||||||
|
* All numbers are formatted like the rest of the game.
|
||||||
|
|
||||||
Misc.
|
Misc.
|
||||||
* Link to discord added under options
|
* Server security is capped at 100.
|
||||||
* 'getMemberInformation' doc updated, oops
|
* Added option to quit a job.
|
||||||
* tech vendor now handle max ram and cores.
|
* 'cd' no longer works on unexistent folders.
|
||||||
|
* cd with no arguments brings you back to top level folder (@Andreas)
|
||||||
|
* 'softReset' documentation udpated.
|
||||||
|
* Money tracker now accounts for going to the hospital manually.
|
||||||
|
* codemirror is now the default editor (for new save files)
|
||||||
|
* fix typo in dark web help text (@Rodeth)
|
||||||
|
* so many documentation and typos fixes (@Pimgd)
|
||||||
|
* A corruption visual effect has been added to location with servers that
|
||||||
|
have backdoor installed. (@dewint)
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
@@ -210,9 +210,13 @@ export class Product {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Delete unneeded variables
|
//Delete unneeded variables
|
||||||
|
// @ts-ignore
|
||||||
delete this.prog;
|
delete this.prog;
|
||||||
|
// @ts-ignore
|
||||||
delete this.createCity;
|
delete this.createCity;
|
||||||
|
// @ts-ignore
|
||||||
delete this.designCost;
|
delete this.designCost;
|
||||||
|
// @ts-ignore
|
||||||
delete this.advCost;
|
delete this.advCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ import { Factions } from "./Factions";
|
|||||||
import { HackingMission, setInMission } from "../Missions";
|
import { HackingMission, setInMission } from "../Missions";
|
||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
|
import {
|
||||||
|
getHackingWorkRepGain,
|
||||||
|
getFactionSecurityWorkRepGain,
|
||||||
|
getFactionFieldWorkRepGain,
|
||||||
|
} from "../PersonObjects/formulas/reputation";
|
||||||
|
|
||||||
import { Page, routing } from "../ui/navigationTracking";
|
import { Page, routing } from "../ui/navigationTracking";
|
||||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||||
@@ -235,15 +240,24 @@ export function getNextNeurofluxLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function processPassiveFactionRepGain(numCycles) {
|
export function processPassiveFactionRepGain(numCycles) {
|
||||||
var numTimesGain = (numCycles / 600) * Player.faction_rep_mult;
|
for (const name in Factions) {
|
||||||
for (var name in Factions) {
|
if (name === Player.currentWorkFactionName) continue;
|
||||||
if (Factions.hasOwnProperty(name)) {
|
if (!Factions.hasOwnProperty(name)) continue;
|
||||||
var faction = Factions[name];
|
const faction = Factions[name];
|
||||||
|
if (!faction.isMember) continue;
|
||||||
|
// 0 favor = 1%/s
|
||||||
|
// 50 favor = 6%/s
|
||||||
|
// 100 favor = 11%/s
|
||||||
|
const favorMult = Math.min(0.1, (faction.favor / 1000) + 0.01);
|
||||||
|
// Find the best of all possible favor gain, minimum 1 rep / 2 minute.
|
||||||
|
const hRep = getHackingWorkRepGain(Player, faction);
|
||||||
|
const sRep = getFactionSecurityWorkRepGain(Player, faction);
|
||||||
|
const fRep = getFactionFieldWorkRepGain(Player, faction);
|
||||||
|
const rate = Math.max(hRep * favorMult, sRep * favorMult, fRep * favorMult, 1/120);
|
||||||
|
|
||||||
//TODO Get hard value of 1 rep per "rep gain cycle"" for now..
|
faction.playerReputation += rate *
|
||||||
//maybe later make this based on
|
(numCycles) *
|
||||||
//a player's 'status' like how powerful they are and how much money they have
|
Player.faction_rep_mult *
|
||||||
if (faction.isMember) {faction.playerReputation += (numTimesGain * BitNodeMultipliers.FactionPassiveRepGain);}
|
BitNodeMultipliers.FactionPassiveRepGain;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
|||||||
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
||||||
disabled = true;
|
disabled = true;
|
||||||
} else if (this.hasReputation()) {
|
} else if (this.hasReputation()) {
|
||||||
status = <>UNLOCKED - {Money(moneyCost)}</>;
|
status = <>UNLOCKED (at {Reputation(repCost)} faction reputation) - {Money(moneyCost)}</>;
|
||||||
} else {
|
} else {
|
||||||
disabled = true;
|
disabled = true;
|
||||||
status = <>LOCKED (Requires {Reputation(repCost)} faction reputation - {Money(moneyCost)})</>;
|
status = <>LOCKED (Requires {Reputation(repCost)} faction reputation - {Money(moneyCost)})</>;
|
||||||
|
|||||||
@@ -809,7 +809,7 @@ GangMember.prototype.ascend = function() {
|
|||||||
|
|
||||||
GangMember.prototype.getAscensionEfficiency = function() {
|
GangMember.prototype.getAscensionEfficiency = function() {
|
||||||
function formula(mult) {
|
function formula(mult) {
|
||||||
return 1/(1+Math.log(mult)/Math.log(10));
|
return 1/(1+Math.log(mult)/Math.log(20));
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
hack: formula(this.hack_asc_mult),
|
hack: formula(this.hack_asc_mult),
|
||||||
|
|||||||
@@ -124,8 +124,7 @@ export class HacknetNode extends React.Component {
|
|||||||
<li className={"hacknet-node"}>
|
<li className={"hacknet-node"}>
|
||||||
<div className={"hacknet-node-container"}>
|
<div className={"hacknet-node-container"}>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Node name:</p>
|
<h1 style={{"fontSize":"1em"}}>{node.name}</h1>
|
||||||
<span className={"text"}>{node.name}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Production:</p>
|
<p>Production:</p>
|
||||||
|
|||||||
@@ -163,8 +163,7 @@ export class HacknetServer extends React.Component {
|
|||||||
<li className={"hacknet-node"}>
|
<li className={"hacknet-node"}>
|
||||||
<div className={"hacknet-node-container"}>
|
<div className={"hacknet-node-container"}>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Node name:</p>
|
<h1 style={{"fontSize":"1em"}}>{node.hostname}</h1>
|
||||||
<span className={"text"}>{node.hostname}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<p>Production:</p>
|
<p>Production:</p>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
|||||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||||
import { infiltrationBoxCreate } from "../utils/InfiltrationBox";
|
import { infiltrationBoxCreate } from "../utils/InfiltrationBox";
|
||||||
import { formatNumber } from "../utils/StringHelperFunctions";
|
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||||
|
import { numeralWrapper } from "./ui/numeralFormat";
|
||||||
|
|
||||||
let InfiltrationScenarios = {
|
let InfiltrationScenarios = {
|
||||||
Guards: "You see an armed security guard patrolling the area.",
|
Guards: "You see an armed security guard patrolling the area.",
|
||||||
@@ -451,9 +452,9 @@ function endInfiltrationLevel(inst) {
|
|||||||
BitNodeMultipliers.InfiltrationMoney;
|
BitNodeMultipliers.InfiltrationMoney;
|
||||||
inst.secretsStolen.push(baseSecretValue);
|
inst.secretsStolen.push(baseSecretValue);
|
||||||
dialogBoxCreate("You found and stole a set of classified documents from the company. " +
|
dialogBoxCreate("You found and stole a set of classified documents from the company. " +
|
||||||
"These classified secrets could probably be sold for money (<span class='money-gold'>$" +
|
"These classified secrets could probably be sold for money (<span class='money-gold'>" +
|
||||||
formatNumber(secretMoneyValue, 2) + "</span>), or they " +
|
numeralWrapper.formatMoney(secretMoneyValue) + "</span>), or they " +
|
||||||
"could be given to factions for reputation (<span class='light-yellow'>" + formatNumber(secretValue, 3) + " rep</span>)");
|
"could be given to factions for reputation (<span class='light-yellow'>" + numeralWrapper.formatReputation(secretValue) + " rep</span>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase security level based on difficulty
|
// Increase security level based on difficulty
|
||||||
@@ -495,16 +496,16 @@ function updateInfiltrationLevelText(inst) {
|
|||||||
document.getElementById("infiltration-level-text").innerHTML =
|
document.getElementById("infiltration-level-text").innerHTML =
|
||||||
"Facility name: " + inst.companyName + "<br>" +
|
"Facility name: " + inst.companyName + "<br>" +
|
||||||
"Clearance Level: " + inst.clearanceLevel + "<br>" +
|
"Clearance Level: " + inst.clearanceLevel + "<br>" +
|
||||||
"Security Level: " + formatNumber(inst.securityLevel, 3) + "<br><br>" +
|
"Security Level: " + numeralWrapper.formatInfiltrationSecurity(inst.securityLevel) + "<br><br>" +
|
||||||
"Total value of stolen secrets<br>" +
|
"Total value of stolen secrets<br>" +
|
||||||
"Reputation: <span class='light-yellow'>" + formatNumber(totalValue, 3) + "</span><br>" +
|
"Reputation: <span class='light-yellow'>" + numeralWrapper.formatReputation(totalValue, 3) + "</span><br>" +
|
||||||
"Money: <span class='money-gold'>$" + formatNumber(totalMoneyValue, 2) + "</span><br><br>" +
|
"Money: <span class='money-gold'>" + numeralWrapper.formatMoney(totalMoneyValue, 2) + "</span><br><br>" +
|
||||||
"Hack exp gained: " + formatNumber(inst.calcGainedHackingExp(), 3) + "<br>" +
|
"Hack exp gained: " + numeralWrapper.formatExp(inst.calcGainedHackingExp(), 3) + "<br>" +
|
||||||
"Str exp gained: " + formatNumber(inst.calcGainedStrengthExp(), 3) + "<br>" +
|
"Str exp gained: " + numeralWrapper.formatExp(inst.calcGainedStrengthExp(), 3) + "<br>" +
|
||||||
"Def exp gained: " + formatNumber(inst.calcGainedDefenseExp(), 3) + "<br>" +
|
"Def exp gained: " + numeralWrapper.formatExp(inst.calcGainedDefenseExp(), 3) + "<br>" +
|
||||||
"Dex exp gained: " + formatNumber(inst.calcGainedDexterityExp(), 3) + "<br>" +
|
"Dex exp gained: " + numeralWrapper.formatExp(inst.calcGainedDexterityExp(), 3) + "<br>" +
|
||||||
"Agi exp gained: " + formatNumber(inst.calcGainedAgilityExp(), 3) + "<br>" +
|
"Agi exp gained: " + numeralWrapper.formatExp(inst.calcGainedAgilityExp(), 3) + "<br>" +
|
||||||
"Cha exp gained: " + formatNumber(inst.calcGainedCharismaExp(), 3);
|
"Cha exp gained: " + numeralWrapper.formatExp(inst.calcGainedCharismaExp(), 3);
|
||||||
/* eslint-enable no-irregular-whitespace */
|
/* eslint-enable no-irregular-whitespace */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,7 +525,7 @@ function updateInfiltrationButtons(inst, scenario) {
|
|||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to escape the facility with the classified secrets and " +
|
"Attempt to escape the facility with the classified secrets and " +
|
||||||
"documents you have stolen. You have a " +
|
"documents you have stolen. You have a " +
|
||||||
formatNumber(escapeChance*100, 2) + "% chance of success. If you fail, " +
|
numeralWrapper.formatPercentage(escapeChance, 2) + " chance of success. If you fail, " +
|
||||||
"the security level will increase by 5%.</span>";
|
"the security level will increase by 5%.</span>";
|
||||||
|
|
||||||
switch(scenario) {
|
switch(scenario) {
|
||||||
@@ -532,55 +533,55 @@ function updateInfiltrationButtons(inst, scenario) {
|
|||||||
document.getElementById("infiltration-pickdoor").innerHTML = "Lockpick" +
|
document.getElementById("infiltration-pickdoor").innerHTML = "Lockpick" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to pick the locked door. You have a " +
|
"Attempt to pick the locked door. You have a " +
|
||||||
formatNumber(lockpickChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(lockpickChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increased by 1%. If you fail, the " +
|
"If you succeed, the security level will increased by 1%. If you fail, the " +
|
||||||
"security level will increase by 3%.</span>";
|
"security level will increase by 3%.</span>";
|
||||||
case InfiltrationScenarios.TechOnly:
|
case InfiltrationScenarios.TechOnly:
|
||||||
document.getElementById("infiltration-hacksecurity").innerHTML = "Hack" +
|
document.getElementById("infiltration-hacksecurity").innerHTML = "Hack" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to hack and disable the security system. You have a " +
|
"Attempt to hack and disable the security system. You have a " +
|
||||||
formatNumber(hackChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(hackChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increase by 3%. If you fail, " +
|
"If you succeed, the security level will increase by 3%. If you fail, " +
|
||||||
"the security level will increase by 5%.</span>";
|
"the security level will increase by 5%.</span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-destroysecurity").innerHTML = "Destroy security" +
|
document.getElementById("infiltration-destroysecurity").innerHTML = "Destroy security" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to violently destroy the security system. You have a " +
|
"Attempt to violently destroy the security system. You have a " +
|
||||||
formatNumber(destroySecurityChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(destroySecurityChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increase by 5%. If you fail, the " +
|
"If you succeed, the security level will increase by 5%. If you fail, the " +
|
||||||
"security level will increase by 10%. </span>";
|
"security level will increase by 10%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-sneak").innerHTML = "Sneak" +
|
document.getElementById("infiltration-sneak").innerHTML = "Sneak" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to sneak past the security system. You have a " +
|
"Attempt to sneak past the security system. You have a " +
|
||||||
formatNumber(sneakChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(sneakChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 8%. </span>";
|
"If you fail, the security level will increase by 8%. </span>";
|
||||||
break;
|
break;
|
||||||
case InfiltrationScenarios.Bots:
|
case InfiltrationScenarios.Bots:
|
||||||
document.getElementById("infiltration-kill").innerHTML = "Destroy bots" +
|
document.getElementById("infiltration-kill").innerHTML = "Destroy bots" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to destroy the security bots through combat. You have a " +
|
"Attempt to destroy the security bots through combat. You have a " +
|
||||||
formatNumber(killChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(killChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increase by 5%. If you fail, " +
|
"If you succeed, the security level will increase by 5%. If you fail, " +
|
||||||
"the security level will increase by 10%. </span>";
|
"the security level will increase by 10%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-assassinate").innerHTML = "Assassinate bots" +
|
document.getElementById("infiltration-assassinate").innerHTML = "Assassinate bots" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to stealthily destroy the security bots through assassination. You have a " +
|
"Attempt to stealthily destroy the security bots through assassination. You have a " +
|
||||||
formatNumber(assassinateChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(assassinateChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 10%. </span>";
|
"If you fail, the security level will increase by 10%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-hacksecurity").innerHTML = "Hack bots" +
|
document.getElementById("infiltration-hacksecurity").innerHTML = "Hack bots" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to disable the security bots by hacking them. You have a " +
|
"Attempt to disable the security bots by hacking them. You have a " +
|
||||||
formatNumber(hackChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(hackChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increase by 3%. If you fail, " +
|
"If you succeed, the security level will increase by 3%. If you fail, " +
|
||||||
"the security level will increase by 5%. </span>";
|
"the security level will increase by 5%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-sneak").innerHTML = "Sneak" +
|
document.getElementById("infiltration-sneak").innerHTML = "Sneak" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to sneak past the security bots. You have a " +
|
"Attempt to sneak past the security bots. You have a " +
|
||||||
formatNumber(sneakChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(sneakChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 8%. </span>";
|
"If you fail, the security level will increase by 8%. </span>";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -589,39 +590,39 @@ function updateInfiltrationButtons(inst, scenario) {
|
|||||||
document.getElementById("infiltration-kill").innerHTML = "Kill" +
|
document.getElementById("infiltration-kill").innerHTML = "Kill" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to kill the security guard. You have a " +
|
"Attempt to kill the security guard. You have a " +
|
||||||
formatNumber(killChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(killChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increase by 5%. If you fail, " +
|
"If you succeed, the security level will increase by 5%. If you fail, " +
|
||||||
"the security level will decrease by 10%. </span>";
|
"the security level will decrease by 10%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-knockout").innerHTML = "Knockout" +
|
document.getElementById("infiltration-knockout").innerHTML = "Knockout" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to knockout the security guard. You have a " +
|
"Attempt to knockout the security guard. You have a " +
|
||||||
formatNumber(knockoutChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(knockoutChance, 2) + " chance of success. " +
|
||||||
"If you succeed, the security level will increase by 3%. If you fail, the " +
|
"If you succeed, the security level will increase by 3%. If you fail, the " +
|
||||||
"security level will increase by 10%. </span>";
|
"security level will increase by 10%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-stealthknockout").innerHTML = "Stealth Knockout" +
|
document.getElementById("infiltration-stealthknockout").innerHTML = "Stealth Knockout" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to stealthily knockout the security guard. You have a " +
|
"Attempt to stealthily knockout the security guard. You have a " +
|
||||||
formatNumber(stealthKnockoutChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(stealthKnockoutChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 10%. </span>";
|
"If you fail, the security level will increase by 10%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-assassinate").innerHTML = "Assassinate" +
|
document.getElementById("infiltration-assassinate").innerHTML = "Assassinate" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to assassinate the security guard. You have a " +
|
"Attempt to assassinate the security guard. You have a " +
|
||||||
formatNumber(assassinateChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(assassinateChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 5%. </span>";
|
"If you fail, the security level will increase by 5%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-sneak").innerHTML = "Sneak" +
|
document.getElementById("infiltration-sneak").innerHTML = "Sneak" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to sneak past the security guard. You have a " +
|
"Attempt to sneak past the security guard. You have a " +
|
||||||
formatNumber(sneakChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(sneakChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 8%. </span>";
|
"If you fail, the security level will increase by 8%. </span>";
|
||||||
|
|
||||||
document.getElementById("infiltration-bribe").innerHTML = "Bribe" +
|
document.getElementById("infiltration-bribe").innerHTML = "Bribe" +
|
||||||
"<span class='tooltiptext'>" +
|
"<span class='tooltiptext'>" +
|
||||||
"Attempt to bribe the security guard. You have a " +
|
"Attempt to bribe the security guard. You have a " +
|
||||||
formatNumber(bribeChance*100, 2) + "% chance of success. " +
|
numeralWrapper.formatPercentage(bribeChance, 2) + " chance of success. " +
|
||||||
"If you fail, the security level will increase by 15%. </span>";
|
"If you fail, the security level will increase by 15%. </span>";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ export const Literatures: IMap<Literature> = {};
|
|||||||
"will be our people, and we will be with them as their Gods. We will wipe away every tear from their eyes, and death " +
|
"will be our people, and we will be with them as their Gods. We will wipe away every tear from their eyes, and death " +
|
||||||
"shall be no more, neither shall there be mourning, nor crying, nor pain anymore, for the former things " +
|
"shall be no more, neither shall there be mourning, nor crying, nor pain anymore, for the former things " +
|
||||||
"have passed away.'<br><br>" +
|
"have passed away.'<br><br>" +
|
||||||
"And once were were seated on the throne we said 'Behold, I am making all things new.' " +
|
"And once we were seated on the throne we said 'Behold, I am making all things new.' " +
|
||||||
"Also we said, 'Write this down, for these words are trustworthy and true.' And we said to you, " +
|
"Also we said, 'Write this down, for these words are trustworthy and true.' And we said to you, " +
|
||||||
"'It is done! I am the Alpha and the Omega, the beginning and the end. To the thirsty I will give from the spring " +
|
"'It is done! I am the Alpha and the Omega, the beginning and the end. To the thirsty I will give from the spring " +
|
||||||
"of the water of life without payment. The one who conquers will have this heritage, and we will be his God and " +
|
"of the water of life without payment. The one who conquers will have this heritage, and we will be his God and " +
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export function createTravelPopup(destination: CityName, travelFn: TravelFunctio
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
yesNoBoxCreate(<span>Would you like to travel to ${destination}? The trip will
|
yesNoBoxCreate(<span>Would you like to travel to {destination}? The trip will
|
||||||
cost {Money(cost)}.</span>);
|
cost {Money(cost)}.</span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ export enum CityName {
|
|||||||
NewTokyo = "New Tokyo",
|
NewTokyo = "New Tokyo",
|
||||||
Sector12 = "Sector-12",
|
Sector12 = "Sector-12",
|
||||||
Volhaven = "Volhaven",
|
Volhaven = "Volhaven",
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -4,25 +4,28 @@
|
|||||||
* This subcomponent renders all of the buttons for training at the gym
|
* This subcomponent renders all of the buttons for training at the gym
|
||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { Blackjack } from "../../Casino/Blackjack";
|
||||||
|
import { CoinFlip } from "../../Casino/CoinFlip";
|
||||||
|
import { Roulette } from "../../Casino/Roulette";
|
||||||
|
import { SlotMachine } from "../../Casino/SlotMachine";
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
|
|
||||||
import { Location } from "../Location";
|
|
||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
enum GameType {
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
None = 'none',
|
||||||
|
Coin = 'coin',
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
Slots = 'slots',
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
Roulette = 'roulette',
|
||||||
import { Money } from "../../ui/React/Money";
|
Blackjack = 'blackjack',
|
||||||
import { SlotMachine } from "../../Casino/SlotMachine";
|
}
|
||||||
import { CoinFlip } from "../../Casino/CoinFlip";
|
|
||||||
import { Roulette } from "../../Casino/Roulette";
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
p: IPlayer;
|
p: IPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
type IState = {
|
type IState = {
|
||||||
game: string;
|
game: GameType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CasinoLocation extends React.Component<IProps, IState> {
|
export class CasinoLocation extends React.Component<IProps, IState> {
|
||||||
@@ -30,57 +33,70 @@ export class CasinoLocation extends React.Component<IProps, IState> {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
game: '',
|
game: GameType.None,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateGame = this.updateGame.bind(this);
|
this.updateGame = this.updateGame.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGame(game: string) {
|
updateGame(game: GameType): void {
|
||||||
this.setState({
|
this.setState({
|
||||||
game: game,
|
game,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderGames() {
|
renderGames(): React.ReactNode {
|
||||||
return (<>
|
return (<>
|
||||||
<StdButton
|
<StdButton
|
||||||
onClick={() => this.updateGame('coin')}
|
onClick={() => this.updateGame(GameType.Coin)}
|
||||||
text={"Play coin flip"}
|
text={"Play coin flip"}
|
||||||
/><br />
|
/><br />
|
||||||
<StdButton
|
<StdButton
|
||||||
onClick={() => this.updateGame('slots')}
|
onClick={() => this.updateGame(GameType.Slots)}
|
||||||
text={"Play slots"}
|
text={"Play slots"}
|
||||||
/><br />
|
/><br />
|
||||||
<StdButton
|
<StdButton
|
||||||
onClick={() => this.updateGame('roulette')}
|
onClick={() => this.updateGame(GameType.Roulette)}
|
||||||
text={"Play roulette"}
|
text={"Play roulette"}
|
||||||
|
/><br />
|
||||||
|
<StdButton
|
||||||
|
onClick={() => this.updateGame(GameType.Blackjack)}
|
||||||
|
text={"Play blackjack"}
|
||||||
/>
|
/>
|
||||||
</>)
|
</>)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderGame() {
|
renderGame(): React.ReactNode {
|
||||||
let elem;
|
let elem = null;
|
||||||
switch(this.state.game) {
|
switch(this.state.game) {
|
||||||
case 'coin':
|
case GameType.Coin:
|
||||||
elem = <CoinFlip p={this.props.p} />
|
elem = <CoinFlip p={this.props.p} />
|
||||||
break;
|
break;
|
||||||
case 'slots':
|
case GameType.Slots:
|
||||||
elem = <SlotMachine p={this.props.p} />
|
elem = <SlotMachine p={this.props.p} />
|
||||||
break;
|
break;
|
||||||
case 'roulette':
|
case GameType.Roulette:
|
||||||
elem = <Roulette p={this.props.p} />
|
elem = <Roulette p={this.props.p} />
|
||||||
break;
|
break;
|
||||||
|
case GameType.Blackjack:
|
||||||
|
elem = <Blackjack p={this.props.p} />
|
||||||
|
break;
|
||||||
|
case GameType.None:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`MissingCaseException: ${this.state.game}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<>
|
return (
|
||||||
<StdButton onClick={() => this.updateGame('')} text={"Stop playing"} />
|
<>
|
||||||
{elem}
|
<StdButton onClick={() => this.updateGame(GameType.None)} text={"Stop playing"} />
|
||||||
</>)
|
{elem}
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
if(!this.state.game) {
|
if(this.state.game === GameType.None) {
|
||||||
return this.renderGames();
|
return this.renderGames();
|
||||||
} else {
|
} else {
|
||||||
return this.renderGame();
|
return this.renderGame();
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ type IProps = {
|
|||||||
export class LocationCity extends React.Component<IProps, any> {
|
export class LocationCity extends React.Component<IProps, any> {
|
||||||
asciiCity() {
|
asciiCity() {
|
||||||
const thiscity = this;
|
const thiscity = this;
|
||||||
const topprop = this.props
|
const topprop = this.props;
|
||||||
|
|
||||||
function LocationLetter(location: string) {
|
function LocationLetter(location: LocationName) {
|
||||||
if (location)
|
if (location)
|
||||||
return <span key={location} className='tooltip' style={{color: 'blue', whiteSpace: 'nowrap', margin: '0px', padding: '0px', cursor: 'pointer'}} onClick={topprop.enterLocation.bind(thiscity, location)}>
|
return <span key={location} className='tooltip' style={{color: 'blue', whiteSpace: 'nowrap', margin: '0px', padding: '0px', cursor: 'pointer'}} onClick={topprop.enterLocation.bind(thiscity, location)}>
|
||||||
X
|
X
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ import { StdButton } from "../../ui/React/StdButton";
|
|||||||
import { Reputation } from "../../ui/React/Reputation";
|
import { Reputation } from "../../ui/React/Reputation";
|
||||||
import { Favor } from "../../ui/React/Favor";
|
import { Favor } from "../../ui/React/Favor";
|
||||||
|
|
||||||
|
import {
|
||||||
|
yesNoBoxGetYesButton,
|
||||||
|
yesNoBoxGetNoButton,
|
||||||
|
yesNoBoxClose,
|
||||||
|
yesNoBoxCreate
|
||||||
|
} from "../../../utils/YesNoBox";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
engine: IEngine;
|
engine: IEngine;
|
||||||
locName: LocationName;
|
locName: LocationName;
|
||||||
@@ -73,6 +80,7 @@ export class CompanyLocation extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
this.btnStyle = { display: "block" };
|
this.btnStyle = { display: "block" };
|
||||||
|
|
||||||
|
this.quit = this.quit.bind(this);
|
||||||
this.applyForAgentJob = this.applyForAgentJob.bind(this);
|
this.applyForAgentJob = this.applyForAgentJob.bind(this);
|
||||||
this.applyForBusinessConsultantJob = this.applyForBusinessConsultantJob.bind(this);
|
this.applyForBusinessConsultantJob = this.applyForBusinessConsultantJob.bind(this);
|
||||||
this.applyForBusinessJob = this.applyForBusinessJob.bind(this);
|
this.applyForBusinessJob = this.applyForBusinessJob.bind(this);
|
||||||
@@ -207,6 +215,26 @@ export class CompanyLocation extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quit(e: React.MouseEvent<HTMLElement>) {
|
||||||
|
if (!e.isTrusted) { return false; }
|
||||||
|
|
||||||
|
var yesBtn = yesNoBoxGetYesButton();
|
||||||
|
var noBtn = yesNoBoxGetNoButton();
|
||||||
|
if (yesBtn == null || noBtn == null) { return; }
|
||||||
|
yesBtn.innerHTML = "Quit job";
|
||||||
|
noBtn.innerHTML = "Cancel";
|
||||||
|
yesBtn.addEventListener("click", () => {
|
||||||
|
this.props.p.quitJob(this.props.locName);
|
||||||
|
this.checkIfEmployedHere(true);
|
||||||
|
yesNoBoxClose();
|
||||||
|
});
|
||||||
|
noBtn.addEventListener("click", () => {
|
||||||
|
yesNoBoxClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
yesNoBoxCreate(<>Would you like to quit your job at {this.company.name}?</>);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const isEmployedHere = this.jobTitle != null;
|
const isEmployedHere = this.jobTitle != null;
|
||||||
const favorGain = this.company.getFavorGain();
|
const favorGain = this.company.getFavorGain();
|
||||||
@@ -236,10 +264,12 @@ export class CompanyLocation extends React.Component<IProps, IState> {
|
|||||||
</p><br />
|
</p><br />
|
||||||
<br /><p style={blockStyleMarkup}>-------------------------</p><br />
|
<br /><p style={blockStyleMarkup}>-------------------------</p><br />
|
||||||
<StdButton
|
<StdButton
|
||||||
id={"foo-work-button-id"}
|
|
||||||
onClick={this.work}
|
onClick={this.work}
|
||||||
style={this.btnStyle}
|
|
||||||
text={"Work"}
|
text={"Work"}
|
||||||
|
/>
|
||||||
|
<StdButton
|
||||||
|
onClick={this.quit}
|
||||||
|
text={"Quit"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,29 @@
|
|||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { CompanyLocation } from "./CompanyLocation";
|
import { CompanyLocation } from "./CompanyLocation";
|
||||||
import { GymLocation } from "./GymLocation";
|
import { GymLocation } from "./GymLocation";
|
||||||
import { HospitalLocation } from "./HospitalLocation";
|
import { HospitalLocation } from "./HospitalLocation";
|
||||||
import { SlumsLocation } from "./SlumsLocation";
|
import { SlumsLocation } from "./SlumsLocation";
|
||||||
import { SpecialLocation } from "./SpecialLocation";
|
import { SpecialLocation } from "./SpecialLocation";
|
||||||
import { TechVendorLocation } from "./TechVendorLocation";
|
import { TechVendorLocation } from "./TechVendorLocation";
|
||||||
import { TravelAgencyLocation } from "./TravelAgencyLocation";
|
import { TravelAgencyLocation } from "./TravelAgencyLocation";
|
||||||
import { UniversityLocation } from "./UniversityLocation";
|
import { UniversityLocation } from "./UniversityLocation";
|
||||||
import { CasinoLocation } from "./CasinoLocation";
|
import { CasinoLocation } from "./CasinoLocation";
|
||||||
|
|
||||||
import { Location } from "../Location";
|
import { Location } from "../Location";
|
||||||
import { LocationType } from "../LocationTypeEnum";
|
import { LocationType } from "../LocationTypeEnum";
|
||||||
import { CityName } from "../data/CityNames";
|
import { CityName } from "../data/CityNames";
|
||||||
|
|
||||||
import { IEngine } from "../../IEngine";
|
import { IEngine } from "../../IEngine";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||||
|
import { getServer, isBackdoorInstalled } from "../../Server/ServerHelpers";
|
||||||
|
|
||||||
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
|
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
engine: IEngine;
|
engine: IEngine;
|
||||||
@@ -146,11 +151,19 @@ export class GenericLocation extends React.Component<IProps, any> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const locContent: React.ReactNode[] = this.getLocationSpecificContent();
|
const locContent: React.ReactNode[] = this.getLocationSpecificContent();
|
||||||
|
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||||
|
const server = getServer(ip);
|
||||||
|
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<StdButton onClick={this.props.returnToCity} style={this.btnStyle} text={"Return to World"} />
|
<StdButton onClick={this.props.returnToCity} style={this.btnStyle} text={"Return to World"} />
|
||||||
<h1>{this.props.loc.name}</h1>
|
<h1>
|
||||||
|
{backdoorInstalled && !Settings.DisableTextEffects
|
||||||
|
? <CorruptableText content={this.props.loc.name}/>
|
||||||
|
: this.props.loc.name
|
||||||
|
}
|
||||||
|
</h1>
|
||||||
{locContent}
|
{locContent}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ import * as React from "react";
|
|||||||
|
|
||||||
import { Location } from "../Location";
|
import { Location } from "../Location";
|
||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { getServer } from "../../Server/ServerHelpers";
|
||||||
|
import { Server } from "../../Server/Server";
|
||||||
|
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
@@ -34,11 +37,22 @@ export class GymLocation extends React.Component<IProps, any> {
|
|||||||
this.trainDefense = this.trainDefense.bind(this);
|
this.trainDefense = this.trainDefense.bind(this);
|
||||||
this.trainDexterity = this.trainDexterity.bind(this);
|
this.trainDexterity = this.trainDexterity.bind(this);
|
||||||
this.trainAgility = this.trainAgility.bind(this);
|
this.trainAgility = this.trainAgility.bind(this);
|
||||||
|
|
||||||
|
this.calculateCost = this.calculateCost.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateCost(): number {
|
||||||
|
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||||
|
console.log(`ip: ${ip}`);
|
||||||
|
const server = getServer(ip);
|
||||||
|
if(server == null || !server.hasOwnProperty('backdoorInstalled')) return this.props.loc.costMult;
|
||||||
|
const discount = (server as Server).backdoorInstalled? 0.9 : 1;
|
||||||
|
return this.props.loc.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
train(stat: string) {
|
train(stat: string) {
|
||||||
const loc = this.props.loc;
|
const loc = this.props.loc;
|
||||||
this.props.p.startClass(loc.costMult, loc.expMult, stat);
|
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
trainStrength() {
|
trainStrength() {
|
||||||
@@ -58,9 +72,7 @@ export class GymLocation extends React.Component<IProps, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const costMult: number = this.props.loc.costMult;
|
const cost = CONSTANTS.ClassGymBaseCost * this.calculateCost();
|
||||||
|
|
||||||
const cost = CONSTANTS.ClassGymBaseCost * costMult;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export class HospitalLocation extends React.Component<IProps, IState> {
|
|||||||
const cost = this.getCost();
|
const cost = this.getCost();
|
||||||
this.props.p.loseMoney(cost);
|
this.props.p.loseMoney(cost);
|
||||||
this.props.p.hp = this.props.p.max_hp;
|
this.props.p.hp = this.props.p.max_hp;
|
||||||
|
this.props.p.recordMoneySource(-1 * cost, 'hospitalization');
|
||||||
|
|
||||||
// This just forces a re-render to update the cost
|
// This just forces a re-render to update the cost
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export class TravelAgencyLocation extends React.Component<IProps, any> {
|
|||||||
listWorldMap() {
|
listWorldMap() {
|
||||||
const travelBtns: React.ReactNode[] = [];
|
const travelBtns: React.ReactNode[] = [];
|
||||||
for (const key in CityName) {
|
for (const key in CityName) {
|
||||||
const city = CityName[key];
|
const city: CityName = (CityName as any)[key];
|
||||||
|
|
||||||
// Skip current city
|
// Skip current city
|
||||||
if (city === this.props.p.city) { continue; }
|
if (city === this.props.p.city) { continue; }
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { Location } from "../Location";
|
|||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { getServer } from "../../Server/ServerHelpers";
|
||||||
|
import { Server } from "../../Server/Server";
|
||||||
|
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
@@ -37,11 +40,22 @@ export class UniversityLocation extends React.Component<IProps, any> {
|
|||||||
this.algorithms = this.algorithms.bind(this);
|
this.algorithms = this.algorithms.bind(this);
|
||||||
this.management = this.management.bind(this);
|
this.management = this.management.bind(this);
|
||||||
this.leadership = this.leadership.bind(this);
|
this.leadership = this.leadership.bind(this);
|
||||||
|
|
||||||
|
this.calculateCost = this.calculateCost.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateCost(): number {
|
||||||
|
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||||
|
console.log(`ip: ${ip}`);
|
||||||
|
const server = getServer(ip);
|
||||||
|
if(server == null || !server.hasOwnProperty('backdoorInstalled')) return this.props.loc.costMult;
|
||||||
|
const discount = (server as Server).backdoorInstalled? 0.9 : 1;
|
||||||
|
return this.props.loc.costMult * discount;
|
||||||
}
|
}
|
||||||
|
|
||||||
take(stat: string) {
|
take(stat: string) {
|
||||||
const loc = this.props.loc;
|
const loc = this.props.loc;
|
||||||
this.props.p.startClass(loc.costMult, loc.expMult, stat);
|
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
study() {
|
study() {
|
||||||
@@ -69,7 +83,7 @@ export class UniversityLocation extends React.Component<IProps, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const costMult: number = this.props.loc.costMult;
|
const costMult: number = this.calculateCost();
|
||||||
|
|
||||||
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
|
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
|
||||||
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
|
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ function initMessages() {
|
|||||||
"We've been watching you. Your skills are very impressive. But you're wasting " +
|
"We've been watching you. Your skills are very impressive. But you're wasting " +
|
||||||
"your talents. If you join us, you can put your skills to good use and change " +
|
"your talents. If you join us, you can put your skills to good use and change " +
|
||||||
"the world for the better. If you join us, we can unlock your full potential. <br><br>" +
|
"the world for the better. If you join us, we can unlock your full potential. <br><br>" +
|
||||||
"But first, you must pass our test. Find and hack our server using the Terminal. <br><br>" +
|
"But first, you must pass our test. Find and install the backdoor on our server. <br><br>" +
|
||||||
"-CyberSec"));
|
"-CyberSec"));
|
||||||
AddToAllMessages(new Message(MessageFilenames.NiteSecTest,
|
AddToAllMessages(new Message(MessageFilenames.NiteSecTest,
|
||||||
"People say that the corrupted governments and corporations rule the world. " +
|
"People say that the corrupted governments and corporations rule the world. " +
|
||||||
@@ -161,7 +161,7 @@ function initMessages() {
|
|||||||
"like us. Because they can't hide from us. Because they can't fight shadows " +
|
"like us. Because they can't hide from us. Because they can't fight shadows " +
|
||||||
"and ideas with bullets. <br><br>" +
|
"and ideas with bullets. <br><br>" +
|
||||||
"Join us, and people will fear you, too. <br><br>" +
|
"Join us, and people will fear you, too. <br><br>" +
|
||||||
"Find and hack our hidden server using the Terminal. Then, we will contact you again." +
|
"Find and install the backdoor on our server. Then, we will contact you again." +
|
||||||
"<br><br>-NiteSec"));
|
"<br><br>-NiteSec"));
|
||||||
AddToAllMessages(new Message(MessageFilenames.BitRunnersTest,
|
AddToAllMessages(new Message(MessageFilenames.BitRunnersTest,
|
||||||
"We know what you are doing. We know what drives you. We know " +
|
"We know what you are doing. We know what drives you. We know " +
|
||||||
|
|||||||
6
src/Milestones/Milestone.ts
Normal file
6
src/Milestones/Milestone.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
export type Milestone = {
|
||||||
|
title: string;
|
||||||
|
fulfilled: (p: IPlayer) => boolean;
|
||||||
|
}
|
||||||
29
src/Milestones/MilestoneHelpers.tsx
Normal file
29
src/Milestones/MilestoneHelpers.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Page, routing } from ".././ui/navigationTracking";
|
||||||
|
import { Root } from "./ui/Root";
|
||||||
|
import { Player } from "../Player";
|
||||||
|
import * as React from "react";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
|
let milestonesContainer: HTMLElement | null = null;
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
function setContainer() {
|
||||||
|
milestonesContainer = document.getElementById("milestones-container");
|
||||||
|
document.removeEventListener("DOMContentLoaded", setContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", setContainer);
|
||||||
|
})();
|
||||||
|
|
||||||
|
export function displayMilestonesContent() {
|
||||||
|
if (!routing.isOn(Page.Milestones)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (milestonesContainer instanceof HTMLElement) {
|
||||||
|
ReactDOM.render(
|
||||||
|
<Root player={Player}/>,
|
||||||
|
milestonesContainer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
99
src/Milestones/Milestones.ts
Normal file
99
src/Milestones/Milestones.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { Milestone } from "./Milestone";
|
||||||
|
import { IMap } from "../types";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { Factions } from "../Faction/Factions";
|
||||||
|
import { Faction } from "../Faction/Faction";
|
||||||
|
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||||
|
|
||||||
|
function allFactionAugs(p: IPlayer, f: Faction): boolean {
|
||||||
|
const factionAugs = f.augmentations.slice().filter((aug)=> "NeuroFlux Governor" !== aug);
|
||||||
|
for(const factionAug of factionAugs) {
|
||||||
|
if(!p.augmentations.some(aug => {return aug.name == factionAug})) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Milestones: Milestone[] = [
|
||||||
|
{
|
||||||
|
title: "Gain root access on CSEC",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
const server = GetServerByHostname("CSEC");
|
||||||
|
if(!server || !server.hasOwnProperty('hasAdminRights')) return false;
|
||||||
|
return (server as any).hasAdminRights;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install the backdoor on CSEC",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
const server = GetServerByHostname("CSEC");
|
||||||
|
if(!server || !server.hasOwnProperty('backdoorInstalled')) return false;
|
||||||
|
return (server as any).backdoorInstalled;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Join the faction hinted at in j1.msg",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return p.factions.includes("CyberSec");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install all the Augmentations from CSEC",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return allFactionAugs(p, Factions["CyberSec"]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Join the faction hinted at in j2.msg",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return p.factions.includes("NiteSec");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install all the Augmentations from NiteSec",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return allFactionAugs(p, Factions["NiteSec"]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Join the faction hinted at in j3.msg",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return p.factions.includes("The Black Hand");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install all the Augmentations from The Black Hand",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return allFactionAugs(p, Factions["The Black Hand"]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Join the faction hinted at in j4.msg",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return p.factions.includes("BitRunners");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install all the Augmentations from BitRunners",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return allFactionAugs(p, Factions["BitRunners"]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Join the final faction",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return p.factions.includes("Daedalus");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install the special Augmentation from Daedalus",
|
||||||
|
fulfilled: (p: IPlayer) => {
|
||||||
|
return p.augmentations.some(aug => aug.name == "The Red Pill")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Install the final backdoor and free yourself.",
|
||||||
|
fulfilled: () => {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
11
src/Milestones/Quest.ts
Normal file
11
src/Milestones/Quest.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Milestone } from "./Milestone";
|
||||||
|
|
||||||
|
export class Quest {
|
||||||
|
title: string;
|
||||||
|
milestones: Milestone[];
|
||||||
|
|
||||||
|
constructor(title: string, milestones: Milestone[]) {
|
||||||
|
this.title = title;
|
||||||
|
this.milestones = milestones;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/Milestones/ui/Root.tsx
Normal file
37
src/Milestones/ui/Root.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { Milestones } from "../Milestones";
|
||||||
|
import { Milestone } from "../Milestone";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function highestMilestone(p: IPlayer, milestones: Milestone[]): number {
|
||||||
|
let n = -1;
|
||||||
|
for(let i = 0; i < milestones.length; i++) {
|
||||||
|
if(milestones[i].fulfilled(p)) n = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Root(props: IProps) {
|
||||||
|
const n = highestMilestone(props.player, Milestones);
|
||||||
|
const milestones = Milestones.map((milestone: Milestone, i: number) => {
|
||||||
|
if (i<=n+1) {
|
||||||
|
return (<ul key={i}>
|
||||||
|
<p>[{milestone.fulfilled(props.player)?"x":" "}] {milestone.title}</p>
|
||||||
|
</ul>)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return (<>
|
||||||
|
<h1>Milestones</h1>
|
||||||
|
<p>Milestones don't reward you for completing them. They are here to guide you if you're lost. They will reset when you install Augmentations.</p><br />
|
||||||
|
|
||||||
|
<h2>Completing fl1ght.exe</h2>
|
||||||
|
<li>
|
||||||
|
{milestones}
|
||||||
|
</li>
|
||||||
|
</>);
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@ export const RamCostConstants: IMap<number> = {
|
|||||||
ScriptReadWriteRamCost: 1.0,
|
ScriptReadWriteRamCost: 1.0,
|
||||||
ScriptArbScriptRamCost: 1.0,
|
ScriptArbScriptRamCost: 1.0,
|
||||||
ScriptGetScriptRamCost: 0.1,
|
ScriptGetScriptRamCost: 0.1,
|
||||||
|
ScriptGetRunningScriptRamCost: 0.3,
|
||||||
ScriptGetHackTimeRamCost: 0.05,
|
ScriptGetHackTimeRamCost: 0.05,
|
||||||
ScriptGetFavorToDonate: 0.10,
|
ScriptGetFavorToDonate: 0.10,
|
||||||
ScriptCodingContractBaseRamCost: 10,
|
ScriptCodingContractBaseRamCost: 10,
|
||||||
@@ -165,6 +166,7 @@ export const RamCosts: IMap<any> = {
|
|||||||
getWeakenTime: () => RamCostConstants.ScriptGetHackTimeRamCost,
|
getWeakenTime: () => RamCostConstants.ScriptGetHackTimeRamCost,
|
||||||
getScriptIncome: () => RamCostConstants.ScriptGetScriptRamCost,
|
getScriptIncome: () => RamCostConstants.ScriptGetScriptRamCost,
|
||||||
getScriptExpGain: () => RamCostConstants.ScriptGetScriptRamCost,
|
getScriptExpGain: () => RamCostConstants.ScriptGetScriptRamCost,
|
||||||
|
getRunningScript: () => RamCostConstants.ScriptGetRunningScriptRamCost,
|
||||||
nFormat: () => 0,
|
nFormat: () => 0,
|
||||||
getTimeSinceLastAug: () => RamCostConstants.ScriptGetHackTimeRamCost,
|
getTimeSinceLastAug: () => RamCostConstants.ScriptGetHackTimeRamCost,
|
||||||
prompt: () => 0,
|
prompt: () => 0,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const sprintf = require("sprintf-js").sprintf;
|
const sprintf = require("sprintf-js").sprintf;
|
||||||
const vsprintf = require("sprintf-js").vsprintf;
|
const vsprintf = require("sprintf-js").vsprintf;
|
||||||
|
import * as libarg from 'arg';
|
||||||
|
|
||||||
import { getRamCost } from "./Netscript/RamCostGenerator";
|
import { getRamCost } from "./Netscript/RamCostGenerator";
|
||||||
import { WorkerScriptStartStopEventEmitter } from "./Netscript/WorkerScriptStartStopEventEmitter";
|
import { WorkerScriptStartStopEventEmitter } from "./Netscript/WorkerScriptStartStopEventEmitter";
|
||||||
@@ -88,7 +89,10 @@ import { inMission } from "./Missions";
|
|||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { Programs } from "./Programs/Programs";
|
import { Programs } from "./Programs/Programs";
|
||||||
import { Script } from "./Script/Script";
|
import { Script } from "./Script/Script";
|
||||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
import {
|
||||||
|
findRunningScript,
|
||||||
|
findRunningScriptByPid,
|
||||||
|
} from "./Script/ScriptHelpers";
|
||||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||||
import { _getScriptUrls } from "./NetscriptJSEvaluator";
|
import { _getScriptUrls } from "./NetscriptJSEvaluator";
|
||||||
import {
|
import {
|
||||||
@@ -162,6 +166,7 @@ import {
|
|||||||
netscriptDelay,
|
netscriptDelay,
|
||||||
resolveNetscriptRequestedThreads,
|
resolveNetscriptRequestedThreads,
|
||||||
} from "./NetscriptEvaluator";
|
} from "./NetscriptEvaluator";
|
||||||
|
import { Interpreter } from "./JSInterpreter";
|
||||||
import { NetscriptPort } from "./NetscriptPort";
|
import { NetscriptPort } from "./NetscriptPort";
|
||||||
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||||
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/SleeveHelpers";
|
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/SleeveHelpers";
|
||||||
@@ -256,6 +261,39 @@ const possibleLogs = {
|
|||||||
setTerritoryWarfare: true,
|
setTerritoryWarfare: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultInterpreter = new Interpreter('', function(){});
|
||||||
|
|
||||||
|
// the acorn interpreter has a bug where it doesn't convert arrays correctly.
|
||||||
|
// so we have to more or less copy it here.
|
||||||
|
function toNative(pseudoObj) {
|
||||||
|
if(pseudoObj == null) return null;
|
||||||
|
if(!pseudoObj.hasOwnProperty('properties') ||
|
||||||
|
!pseudoObj.hasOwnProperty('getter') ||
|
||||||
|
!pseudoObj.hasOwnProperty('setter') ||
|
||||||
|
!pseudoObj.hasOwnProperty('proto')) {
|
||||||
|
return pseudoObj; // it wasn't a pseudo object anyway.
|
||||||
|
}
|
||||||
|
|
||||||
|
let nativeObj;
|
||||||
|
if (pseudoObj.hasOwnProperty('class') && pseudoObj.class === 'Array') {
|
||||||
|
nativeObj = [];
|
||||||
|
const length = defaultInterpreter.getProperty(pseudoObj, 'length');
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
if (defaultInterpreter.hasProperty(pseudoObj, i)) {
|
||||||
|
nativeObj[i] =
|
||||||
|
toNative(defaultInterpreter.getProperty(pseudoObj, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Object.
|
||||||
|
nativeObj = {};
|
||||||
|
for (var key in pseudoObj.properties) {
|
||||||
|
const val = pseudoObj.properties[key];
|
||||||
|
nativeObj[key] = toNative(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nativeObj;
|
||||||
|
}
|
||||||
|
|
||||||
function NetscriptFunctions(workerScript) {
|
function NetscriptFunctions(workerScript) {
|
||||||
const updateDynamicRam = function(fnName, ramCost) {
|
const updateDynamicRam = function(fnName, ramCost) {
|
||||||
if (workerScript.dynamicLoadedFns[fnName]) { return; }
|
if (workerScript.dynamicLoadedFns[fnName]) { return; }
|
||||||
@@ -305,7 +343,6 @@ function NetscriptFunctions(workerScript) {
|
|||||||
* is not specified.
|
* is not specified.
|
||||||
*/
|
*/
|
||||||
const getRunningScript = function(fn, ip, callingFnName, scriptArgs) {
|
const getRunningScript = function(fn, ip, callingFnName, scriptArgs) {
|
||||||
// Sanitize arguments
|
|
||||||
if (typeof callingFnName !== "string" || callingFnName === "") {
|
if (typeof callingFnName !== "string" || callingFnName === "") {
|
||||||
callingFnName = "getRunningScript";
|
callingFnName = "getRunningScript";
|
||||||
}
|
}
|
||||||
@@ -330,6 +367,19 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return workerScript.scriptRef;
|
return workerScript.scriptRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getRunningScriptByPid = function(pid, callingFnName) {
|
||||||
|
if (typeof callingFnName !== "string" || callingFnName === "") {
|
||||||
|
callingFnName = "getRunningScriptgetRunningScriptByPid";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const name of Object.keys(AllServers)) {
|
||||||
|
const server = AllServers[name];
|
||||||
|
const runningScript = findRunningScriptByPid(pid, server);
|
||||||
|
if (runningScript) return runningScript;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for getting the error log message when the user specifies
|
* Helper function for getting the error log message when the user specifies
|
||||||
* a nonexistent running script
|
* a nonexistent running script
|
||||||
@@ -673,7 +723,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
influenceStockThroughServerHack(server, moneyGained);
|
influenceStockThroughServerHack(server, moneyGained);
|
||||||
}
|
}
|
||||||
if(manual) {
|
if(manual) {
|
||||||
server.manuallyHacked = true;
|
server.backdoorInstalled = true;
|
||||||
}
|
}
|
||||||
return Promise.resolve(moneyGained);
|
return Promise.resolve(moneyGained);
|
||||||
} else {
|
} else {
|
||||||
@@ -686,13 +736,30 @@ function NetscriptFunctions(workerScript) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const argsToString = function(args) {
|
||||||
|
let out = '';
|
||||||
|
for(let arg of args) {
|
||||||
|
arg = toNative(arg);
|
||||||
|
if(typeof arg === 'object') {
|
||||||
|
out += JSON.stringify(arg);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out += `${arg}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hacknet : {
|
hacknet : {
|
||||||
numNodes : function() {
|
numNodes : function() {
|
||||||
return Player.hacknetNodes.length;
|
return Player.hacknetNodes.length;
|
||||||
},
|
},
|
||||||
maxNumNodes : function() {
|
maxNumNodes : function() {
|
||||||
return MaxNumberHacknetServers;
|
if (hasHacknetServers()) {
|
||||||
|
return HacknetServerConstants.MaxServers;
|
||||||
|
}
|
||||||
|
return Infinity;
|
||||||
},
|
},
|
||||||
purchaseNode : function() {
|
purchaseNode : function() {
|
||||||
return purchaseHacknet();
|
return purchaseHacknet();
|
||||||
@@ -908,7 +975,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
|
|
||||||
// Check argument validity
|
// Check argument validity
|
||||||
const server = safeGetServer(ip, 'growthAnalyze');
|
const server = safeGetServer(ip, 'growthAnalyze');
|
||||||
if (typeof growth !== "number" || isNaN(growth) || growth < 1) {
|
if (typeof growth !== "number" || isNaN(growth) || growth < 1 || !isFinite(growth)) {
|
||||||
throw makeRuntimeErrorMsg("growthAnalyze", `Invalid argument: growth must be numeric and >= 1, is ${growth}.`);
|
throw makeRuntimeErrorMsg("growthAnalyze", `Invalid argument: growth must be numeric and >= 1, is ${growth}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -944,18 +1011,17 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
|
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
print: function(args){
|
print: function(){
|
||||||
if (args === undefined) {
|
if (arguments.length === 0) {
|
||||||
throw makeRuntimeErrorMsg("print", "Takes 1 argument.");
|
throw makeRuntimeErrorMsg("print", "Takes at least 1 argument.");
|
||||||
}
|
}
|
||||||
workerScript.print(args.toString());
|
workerScript.print(argsToString(arguments));
|
||||||
},
|
},
|
||||||
tprint: function(args) {
|
tprint: function() {
|
||||||
if (args === undefined || args == null) {
|
if (arguments.length === 0) {
|
||||||
throw makeRuntimeErrorMsg("tprint", "Takes 1 argument.");
|
throw makeRuntimeErrorMsg("tprint", "Takes at least 1 argument.");
|
||||||
}
|
}
|
||||||
var x = args.toString();
|
post(`${workerScript.scriptRef.filename}: ${argsToString(arguments)}`);
|
||||||
post(`${workerScript.scriptRef.filename}: ${args.toString()}`);
|
|
||||||
},
|
},
|
||||||
clearLog: function() {
|
clearLog: function() {
|
||||||
workerScript.scriptRef.clearLog();
|
workerScript.scriptRef.clearLog();
|
||||||
@@ -989,8 +1055,15 @@ function NetscriptFunctions(workerScript) {
|
|||||||
|
|
||||||
return runningScriptObj.logs.slice();
|
return runningScriptObj.logs.slice();
|
||||||
},
|
},
|
||||||
tail: function(fn, ip, ...scriptArgs) {
|
tail: function(fn, ip=workerScript.serverIp, ...scriptArgs) {
|
||||||
const runningScriptObj = getRunningScript(fn, ip, "tail", scriptArgs);
|
let runningScriptObj;
|
||||||
|
if(arguments.length === 0) {
|
||||||
|
runningScriptObj = workerScript.scriptRef;
|
||||||
|
} else if(typeof fn === 'number') {
|
||||||
|
runningScriptObj = getRunningScriptByPid(fn, 'tail');
|
||||||
|
} else {
|
||||||
|
runningScriptObj = getRunningScript(fn, ip, "tail", scriptArgs);
|
||||||
|
}
|
||||||
if (runningScriptObj == null) {
|
if (runningScriptObj == null) {
|
||||||
workerScript.log("tail", getCannotFindRunningScriptErrorMessage(fn, ip, scriptArgs));
|
workerScript.log("tail", getCannotFindRunningScriptErrorMessage(fn, ip, scriptArgs));
|
||||||
return;
|
return;
|
||||||
@@ -1494,7 +1567,12 @@ function NetscriptFunctions(workerScript) {
|
|||||||
const processes = [];
|
const processes = [];
|
||||||
for (const i in server.runningScripts) {
|
for (const i in server.runningScripts) {
|
||||||
const script = server.runningScripts[i];
|
const script = server.runningScripts[i];
|
||||||
processes.push({filename:script.filename, threads: script.threads, args: script.args.slice()})
|
processes.push({
|
||||||
|
filename:script.filename,
|
||||||
|
threads: script.threads,
|
||||||
|
args: script.args.slice(),
|
||||||
|
pid: script.pid,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return processes;
|
return processes;
|
||||||
},
|
},
|
||||||
@@ -1677,20 +1755,16 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
isRunning: function(filename,ip) {
|
isRunning: function(fn, ip=workerScript.serverIp, ...scriptArgs) {
|
||||||
updateDynamicRam("isRunning", getRamCost("isRunning"));
|
updateDynamicRam("isRunning", getRamCost("isRunning"));
|
||||||
if (filename === undefined || ip === undefined) {
|
if (fn === undefined || ip === undefined) {
|
||||||
throw makeRuntimeErrorMsg("isRunning", "Usage: isRunning(scriptname, server, [arg1], [arg2]...)");
|
throw makeRuntimeErrorMsg("isRunning", "Usage: isRunning(scriptname, server, [arg1], [arg2]...)");
|
||||||
}
|
}
|
||||||
var server = getServer(ip);
|
if(typeof fn === 'number') {
|
||||||
if (server == null) {
|
return getRunningScriptByPid(fn, 'isRunning') != null;
|
||||||
throw makeRuntimeErrorMsg("isRunning", `Invalid IP/hostname: ${ip}`);
|
} else {
|
||||||
|
return getRunningScript(fn, ip, "isRunning", scriptArgs) != null;
|
||||||
}
|
}
|
||||||
var argsForTargetScript = [];
|
|
||||||
for (var i = 2; i < arguments.length; ++i) {
|
|
||||||
argsForTargetScript.push(arguments[i]);
|
|
||||||
}
|
|
||||||
return (findRunningScript(filename, argsForTargetScript, server) != null);
|
|
||||||
},
|
},
|
||||||
getStockSymbols: function() {
|
getStockSymbols: function() {
|
||||||
updateDynamicRam("getStockSymbols", getRamCost("getStockSymbols"));
|
updateDynamicRam("getStockSymbols", getRamCost("getStockSymbols"));
|
||||||
@@ -2022,7 +2096,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
const cost = getPurchaseServerCost(ram);
|
const cost = getPurchaseServerCost(ram);
|
||||||
if (cost === Infinity) {
|
if (cost === Infinity) {
|
||||||
workerScript.log("purchaseServer", `Invalid argument: ram='${ram}'`);
|
workerScript.log("purchaseServer", `Invalid argument: ram='${ram}'`);
|
||||||
return Infinity;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.money.lt(cost)) {
|
if (Player.money.lt(cost)) {
|
||||||
@@ -2362,6 +2436,38 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
|
getRunningScript: function(fn, ip) {
|
||||||
|
updateDynamicRam("getRunningScript", getRamCost("getRunningScript"));
|
||||||
|
|
||||||
|
let runningScript;
|
||||||
|
if(arguments.length === 0) {
|
||||||
|
runningScript = workerScript.scriptRef;
|
||||||
|
} else if(typeof fn === 'number') {
|
||||||
|
runningScript = getRunningScriptByPid(fn, 'getRunningScript');
|
||||||
|
} else {
|
||||||
|
const scriptArgs = [];
|
||||||
|
for (var i = 2; i < arguments.length; ++i) {
|
||||||
|
scriptArgs.push(arguments[i]);
|
||||||
|
}
|
||||||
|
runningScript = getRunningScript(fn, ip, 'getRunningScript', scriptArgs);
|
||||||
|
}
|
||||||
|
if (runningScript === null) return null;
|
||||||
|
return {
|
||||||
|
args: runningScript.args.slice(),
|
||||||
|
filename: runningScript.filename,
|
||||||
|
logs: runningScript.logs.slice(),
|
||||||
|
offlineExpGained: runningScript.offlineExpGained,
|
||||||
|
offlineMoneyMade: runningScript.offlineMoneyMade,
|
||||||
|
offlineRunningTime: runningScript.offlineRunningTime,
|
||||||
|
onlineExpGained: runningScript.onlineExpGained,
|
||||||
|
onlineMoneyMade: runningScript.onlineMoneyMade,
|
||||||
|
onlineRunningTime: runningScript.onlineRunningTime,
|
||||||
|
pid: runningScript.pid,
|
||||||
|
ramUsage: runningScript.ramUsage,
|
||||||
|
server: runningScript.server,
|
||||||
|
threads: runningScript.threads,
|
||||||
|
};
|
||||||
|
},
|
||||||
getHackTime: function(ip, hack, int) {
|
getHackTime: function(ip, hack, int) {
|
||||||
updateDynamicRam("getHackTime", getRamCost("getHackTime"));
|
updateDynamicRam("getHackTime", getRamCost("getHackTime"));
|
||||||
const server = safeGetServer(ip, "getHackTime");
|
const server = safeGetServer(ip, "getHackTime");
|
||||||
@@ -2457,7 +2563,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return Player.playtimeSinceLastAug;
|
return Player.playtimeSinceLastAug;
|
||||||
},
|
},
|
||||||
prompt : function(txt) {
|
prompt : function(txt) {
|
||||||
if (!isString(txt)) {txt = String(txt);}
|
if (!isString(txt)) {txt = JSON.stringify(txt);}
|
||||||
|
|
||||||
// The id for this popup will consist of the first 20 characters of the prompt string..
|
// The id for this popup will consist of the first 20 characters of the prompt string..
|
||||||
// Thats hopefully good enough to be unique
|
// Thats hopefully good enough to be unique
|
||||||
@@ -4381,8 +4487,36 @@ function NetscriptFunctions(workerScript) {
|
|||||||
},
|
},
|
||||||
exploit: function() {
|
exploit: function() {
|
||||||
Player.giveExploit(Exploit.UndocumentedFunctionCall);
|
Player.giveExploit(Exploit.UndocumentedFunctionCall);
|
||||||
|
},
|
||||||
|
flags: function(data) {
|
||||||
|
data = toNative(data);
|
||||||
|
// We always want the help flag.
|
||||||
|
const args = {};
|
||||||
|
|
||||||
|
for(const d of data) {
|
||||||
|
let t = String;
|
||||||
|
if(typeof d[1] === 'number') {
|
||||||
|
t = Number;
|
||||||
|
} else if(typeof d[1] === 'boolean') {
|
||||||
|
t = Boolean;
|
||||||
|
} else if(Array.isArray(d[1])) {
|
||||||
|
t = [String];
|
||||||
|
}
|
||||||
|
args['--'+d[0]] = t
|
||||||
|
}
|
||||||
|
const ret = libarg(args, {argv: workerScript.args});
|
||||||
|
for(const d of data) {
|
||||||
|
if(!ret.hasOwnProperty('--'+d[0])) ret[d[0]] = d[1];
|
||||||
|
}
|
||||||
|
for(const key of Object.keys(ret)) {
|
||||||
|
if(!key.startsWith('--')) continue;
|
||||||
|
const value = ret[key];
|
||||||
|
delete ret[key];
|
||||||
|
ret[key.slice(2)] = value;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
} // End return
|
} // End return
|
||||||
} // End NetscriptFunction()
|
} // End NetscriptFunction()
|
||||||
|
|
||||||
export { NetscriptFunctions };
|
export { NetscriptFunctions };
|
||||||
@@ -107,7 +107,7 @@ export function _getScriptUrls(script, scripts, seen) {
|
|||||||
// import {foo} from "blob://<uuid>"
|
// import {foo} from "blob://<uuid>"
|
||||||
//
|
//
|
||||||
// Where the blob URL contains the script content.
|
// Where the blob URL contains the script content.
|
||||||
let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))(?:\.\/)?([^'"]+)('|";)/g,
|
let transformedCode = script.code.replace(/((?:from|import)\s+(?:'|"))(?:\.\/)?([^'"]+)('|")/g,
|
||||||
(unmodified, prefix, filename, suffix) => {
|
(unmodified, prefix, filename, suffix) => {
|
||||||
const isAllowedImport = scripts.some(s => s.filename == filename);
|
const isAllowedImport = scripts.some(s => s.filename == filename);
|
||||||
if (!isAllowedImport) return unmodified;
|
if (!isAllowedImport) return unmodified;
|
||||||
|
|||||||
@@ -180,4 +180,5 @@ export interface IPlayer {
|
|||||||
queryStatFromString(str: string): number;
|
queryStatFromString(str: string): number;
|
||||||
getIntelligenceBonus(weight: number): number;
|
getIntelligenceBonus(weight: number): number;
|
||||||
getCasinoWinnings(): number;
|
getCasinoWinnings(): number;
|
||||||
|
quitJob(company: string): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ import { LocationName } from "../../Locations/data/LocationNames";
|
|||||||
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
|
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
|
||||||
import { calculateSkill as calculateSkillF } from "../formulas/skill";
|
import { calculateSkill as calculateSkillF } from "../formulas/skill";
|
||||||
import { calculateIntelligenceBonus } from "../formulas/intelligence";
|
import { calculateIntelligenceBonus } from "../formulas/intelligence";
|
||||||
|
import {
|
||||||
|
getHackingWorkRepGain,
|
||||||
|
getFactionSecurityWorkRepGain,
|
||||||
|
getFactionFieldWorkRepGain,
|
||||||
|
} from '../formulas/reputation';
|
||||||
import {
|
import {
|
||||||
AllServers,
|
AllServers,
|
||||||
AddToAllServers,
|
AddToAllServers,
|
||||||
@@ -429,6 +434,8 @@ export function gainHackingExp(exp) {
|
|||||||
if(this.hacking_exp < 0) {
|
if(this.hacking_exp < 0) {
|
||||||
this.hacking_exp = 0;
|
this.hacking_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.hacking_skill = calculateSkillF(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainStrengthExp(exp) {
|
export function gainStrengthExp(exp) {
|
||||||
@@ -439,6 +446,8 @@ export function gainStrengthExp(exp) {
|
|||||||
if(this.strength_exp < 0) {
|
if(this.strength_exp < 0) {
|
||||||
this.strength_exp = 0;
|
this.strength_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.strength = calculateSkillF(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainDefenseExp(exp) {
|
export function gainDefenseExp(exp) {
|
||||||
@@ -449,6 +458,8 @@ export function gainDefenseExp(exp) {
|
|||||||
if(this.defense_exp < 0) {
|
if(this.defense_exp < 0) {
|
||||||
this.defense_exp = 0;
|
this.defense_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.defense = calculateSkillF(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainDexterityExp(exp) {
|
export function gainDexterityExp(exp) {
|
||||||
@@ -459,6 +470,8 @@ export function gainDexterityExp(exp) {
|
|||||||
if(this.dexterity_exp < 0) {
|
if(this.dexterity_exp < 0) {
|
||||||
this.dexterity_exp = 0;
|
this.dexterity_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.dexterity = calculateSkillF(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainAgilityExp(exp) {
|
export function gainAgilityExp(exp) {
|
||||||
@@ -469,6 +482,8 @@ export function gainAgilityExp(exp) {
|
|||||||
if(this.agility_exp < 0) {
|
if(this.agility_exp < 0) {
|
||||||
this.agility_exp = 0;
|
this.agility_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.agility = calculateSkillF(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainCharismaExp(exp) {
|
export function gainCharismaExp(exp) {
|
||||||
@@ -479,6 +494,8 @@ export function gainCharismaExp(exp) {
|
|||||||
if(this.charisma_exp < 0) {
|
if(this.charisma_exp < 0) {
|
||||||
this.charisma_exp = 0;
|
this.charisma_exp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.charisma = calculateSkillF(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gainIntelligenceExp(exp) {
|
export function gainIntelligenceExp(exp) {
|
||||||
@@ -550,7 +567,11 @@ export function processWorkEarnings(numCycles=1) {
|
|||||||
this.gainAgilityExp(agiExpGain);
|
this.gainAgilityExp(agiExpGain);
|
||||||
this.gainCharismaExp(chaExpGain);
|
this.gainCharismaExp(chaExpGain);
|
||||||
this.gainMoney(moneyGain);
|
this.gainMoney(moneyGain);
|
||||||
this.recordMoneySource(moneyGain, "work");
|
if (this.className) {
|
||||||
|
this.recordMoneySource(moneyGain, "class");
|
||||||
|
} else {
|
||||||
|
this.recordMoneySource(moneyGain, "work");
|
||||||
|
}
|
||||||
this.workHackExpGained += hackExpGain;
|
this.workHackExpGained += hackExpGain;
|
||||||
this.workStrExpGained += strExpGain;
|
this.workStrExpGained += strExpGain;
|
||||||
this.workDefExpGained += defExpGain;
|
this.workDefExpGained += defExpGain;
|
||||||
@@ -592,6 +613,17 @@ export function startWork(companyName) {
|
|||||||
Engine.loadWorkInProgressContent();
|
Engine.loadWorkInProgressContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cancelationPenalty() {
|
||||||
|
const company = Companies[this.companyName];
|
||||||
|
const specialIp = SpecialServerIps[this.companyName];
|
||||||
|
if(specialIp) {
|
||||||
|
const server = AllServers[specialIp];
|
||||||
|
if(server && server.backdoorInstalled) return 0.75;
|
||||||
|
}
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function work(numCycles) {
|
export function work(numCycles) {
|
||||||
// Cap the number of cycles being processed to whatever would put you at
|
// Cap the number of cycles being processed to whatever would put you at
|
||||||
// the work time limit (8 hours)
|
// the work time limit (8 hours)
|
||||||
@@ -622,6 +654,10 @@ export function work(numCycles) {
|
|||||||
|
|
||||||
const position = this.jobs[this.companyName];
|
const position = this.jobs[this.companyName];
|
||||||
|
|
||||||
|
const penalty = this.cancelationPenalty();
|
||||||
|
|
||||||
|
const penaltyString = penalty === 0.5 ? 'half' : 'three quarter'
|
||||||
|
|
||||||
var elem = document.getElementById("work-in-progress-text");
|
var elem = document.getElementById("work-in-progress-text");
|
||||||
ReactDOM.render(<>
|
ReactDOM.render(<>
|
||||||
You are currently working as a {position} at {this.companyName} (Current Company Reputation: {Reputation(companyRep)})<br /><br />
|
You are currently working as a {position} at {this.companyName} (Current Company Reputation: {Reputation(companyRep)})<br /><br />
|
||||||
@@ -636,17 +672,17 @@ export function work(numCycles) {
|
|||||||
{numeralWrapper.formatExp(this.workAgiExpGained)} ({`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}) agility exp <br /><br />
|
{numeralWrapper.formatExp(this.workAgiExpGained)} ({`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}) agility exp <br /><br />
|
||||||
{numeralWrapper.formatExp(this.workChaExpGained)} ({`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}) charisma exp <br /><br />
|
{numeralWrapper.formatExp(this.workChaExpGained)} ({`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}) charisma exp <br /><br />
|
||||||
You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
|
You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
|
||||||
but you will only gain half of the reputation you've earned so far.
|
but you will only gain {penaltyString} of the reputation you've earned so far.
|
||||||
</>, elem);
|
</>, elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function finishWork(cancelled, sing=false) {
|
export function finishWork(cancelled, sing=false) {
|
||||||
//Since the work was cancelled early, player only gains half of what they've earned so far
|
//Since the work was cancelled early, player only gains half of what they've earned so far
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
this.workRepGained /= 2;
|
this.workRepGained *= this.cancelationPenalty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
company.playerReputation += (this.workRepGained);
|
company.playerReputation += (this.workRepGained);
|
||||||
|
|
||||||
this.updateSkillLevels();
|
this.updateSkillLevels();
|
||||||
@@ -853,7 +889,7 @@ export function startFactionFieldWork(faction) {
|
|||||||
this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = this.getFactionFieldWorkRepGain();
|
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkField;
|
this.factionWorkType = CONSTANTS.FactionWorkField;
|
||||||
this.currentWorkFactionDescription = "carrying out field missions"
|
this.currentWorkFactionDescription = "carrying out field missions"
|
||||||
@@ -870,7 +906,7 @@ export function startFactionSecurityWork(faction) {
|
|||||||
this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.workRepGainRate = this.getFactionSecurityWorkRepGain();
|
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
||||||
|
|
||||||
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
|
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
|
||||||
this.currentWorkFactionDescription = "performing security detail"
|
this.currentWorkFactionDescription = "performing security detail"
|
||||||
@@ -879,29 +915,23 @@ export function startFactionSecurityWork(faction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function workForFaction(numCycles) {
|
export function workForFaction(numCycles) {
|
||||||
var faction = Factions[this.currentWorkFactionName];
|
const faction = Factions[this.currentWorkFactionName];
|
||||||
|
|
||||||
//Constantly update the rep gain rate
|
//Constantly update the rep gain rate
|
||||||
switch (this.factionWorkType) {
|
switch (this.factionWorkType) {
|
||||||
case CONSTANTS.FactionWorkHacking:
|
case CONSTANTS.FactionWorkHacking:
|
||||||
this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult * this.getIntelligenceBonus(0.5);
|
this.workRepGainRate = getHackingWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.FactionWorkField:
|
case CONSTANTS.FactionWorkField:
|
||||||
this.workRepGainRate = this.getFactionFieldWorkRepGain();
|
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
case CONSTANTS.FactionWorkSecurity:
|
case CONSTANTS.FactionWorkSecurity:
|
||||||
this.workRepGainRate = this.getFactionSecurityWorkRepGain();
|
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update reputation gain rate to account for faction favor
|
|
||||||
var favorMult = 1 + (faction.favor / 100);
|
|
||||||
if (isNaN(favorMult)) {favorMult = 1;}
|
|
||||||
this.workRepGainRate *= favorMult;
|
|
||||||
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
|
|
||||||
|
|
||||||
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
||||||
var overMax = false;
|
var overMax = false;
|
||||||
if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) {
|
if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) {
|
||||||
@@ -1112,25 +1142,25 @@ export function getWorkRepGain() {
|
|||||||
return jobPerformance * this.company_rep_mult * favorMult;
|
return jobPerformance * this.company_rep_mult * favorMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFactionSecurityWorkRepGain() {
|
// export function getFactionSecurityWorkRepGain() {
|
||||||
var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
// var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
this.strength / CONSTANTS.MaxSkillLevel +
|
// this.strength / CONSTANTS.MaxSkillLevel +
|
||||||
this.defense / CONSTANTS.MaxSkillLevel +
|
// this.defense / CONSTANTS.MaxSkillLevel +
|
||||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
// this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
this.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
// this.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
||||||
return t * this.faction_rep_mult;
|
// return t * this.faction_rep_mult;
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function getFactionFieldWorkRepGain() {
|
// export function getFactionFieldWorkRepGain() {
|
||||||
var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
// var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
this.strength / CONSTANTS.MaxSkillLevel +
|
// this.strength / CONSTANTS.MaxSkillLevel +
|
||||||
this.defense / CONSTANTS.MaxSkillLevel +
|
// this.defense / CONSTANTS.MaxSkillLevel +
|
||||||
this.dexterity / CONSTANTS.MaxSkillLevel +
|
// this.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
this.agility / CONSTANTS.MaxSkillLevel +
|
// this.agility / CONSTANTS.MaxSkillLevel +
|
||||||
this.charisma / CONSTANTS.MaxSkillLevel +
|
// this.charisma / CONSTANTS.MaxSkillLevel +
|
||||||
this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
// this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
||||||
return t * this.faction_rep_mult;
|
// return t * this.faction_rep_mult;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* Creating a Program */
|
/* Creating a Program */
|
||||||
export function startCreateProgramWork(programName, time, reqLevel) {
|
export function startCreateProgramWork(programName, time, reqLevel) {
|
||||||
@@ -1715,6 +1745,11 @@ export function getNextCompanyPosition(company, entryPosType) {
|
|||||||
return entryPosType;
|
return entryPosType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function quitJob(company) {
|
||||||
|
this.companyName = "";
|
||||||
|
delete this.jobs[company];
|
||||||
|
}
|
||||||
|
|
||||||
export function applyForSoftwareJob(sing=false) {
|
export function applyForSoftwareJob(sing=false) {
|
||||||
return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
|
return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
|
||||||
}
|
}
|
||||||
@@ -2036,7 +2071,7 @@ export function checkForFactionInvitations() {
|
|||||||
} else {
|
} else {
|
||||||
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
|
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
|
||||||
!fulcrumsecrettechonologiesFac.alreadyInvited &&
|
!fulcrumsecrettechonologiesFac.alreadyInvited &&
|
||||||
fulcrumSecretServer.manuallyHacked &&
|
fulcrumSecretServer.backdoorInstalled &&
|
||||||
checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)) {
|
checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)) {
|
||||||
invitedFactions.push(fulcrumsecrettechonologiesFac);
|
invitedFactions.push(fulcrumsecrettechonologiesFac);
|
||||||
}
|
}
|
||||||
@@ -2048,7 +2083,7 @@ export function checkForFactionInvitations() {
|
|||||||
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
|
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
|
||||||
if (bitrunnersServer == null) {
|
if (bitrunnersServer == null) {
|
||||||
console.error("Could not find BitRunners Server");
|
console.error("Could not find BitRunners Server");
|
||||||
} else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked &&
|
} else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.backdoorInstalled &&
|
||||||
!bitrunnersFac.alreadyInvited && homeComp.maxRam >= 128) {
|
!bitrunnersFac.alreadyInvited && homeComp.maxRam >= 128) {
|
||||||
invitedFactions.push(bitrunnersFac);
|
invitedFactions.push(bitrunnersFac);
|
||||||
}
|
}
|
||||||
@@ -2058,7 +2093,7 @@ export function checkForFactionInvitations() {
|
|||||||
var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]];
|
var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]];
|
||||||
if (blackhandServer == null) {
|
if (blackhandServer == null) {
|
||||||
console.error("Could not find The Black Hand Server");
|
console.error("Could not find The Black Hand Server");
|
||||||
} else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked &&
|
} else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.backdoorInstalled &&
|
||||||
!theblackhandFac.alreadyInvited && homeComp.maxRam >= 64) {
|
!theblackhandFac.alreadyInvited && homeComp.maxRam >= 64) {
|
||||||
invitedFactions.push(theblackhandFac);
|
invitedFactions.push(theblackhandFac);
|
||||||
}
|
}
|
||||||
@@ -2068,7 +2103,7 @@ export function checkForFactionInvitations() {
|
|||||||
var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]];
|
var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]];
|
||||||
if (nitesecServer == null) {
|
if (nitesecServer == null) {
|
||||||
console.error("Could not find NiteSec Server");
|
console.error("Could not find NiteSec Server");
|
||||||
} else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked &&
|
} else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.backdoorInstalled &&
|
||||||
!nitesecFac.alreadyInvited && homeComp.maxRam >= 32) {
|
!nitesecFac.alreadyInvited && homeComp.maxRam >= 32) {
|
||||||
invitedFactions.push(nitesecFac);
|
invitedFactions.push(nitesecFac);
|
||||||
}
|
}
|
||||||
@@ -2212,7 +2247,7 @@ export function checkForFactionInvitations() {
|
|||||||
var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]];
|
var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]];
|
||||||
if (cybersecServer == null) {
|
if (cybersecServer == null) {
|
||||||
console.error("Could not find CyberSec Server");
|
console.error("Could not find CyberSec Server");
|
||||||
} else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked &&
|
} else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.backdoorInstalled &&
|
||||||
!cybersecFac.alreadyInvited) {
|
!cybersecFac.alreadyInvited) {
|
||||||
invitedFactions.push(cybersecFac);
|
invitedFactions.push(cybersecFac);
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/PersonObjects/formulas/reputation.ts
Normal file
36
src/PersonObjects/formulas/reputation.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { IPlayer } from '../IPlayer';
|
||||||
|
import { Faction } from '../../Faction/Faction';
|
||||||
|
import { CONSTANTS } from '../../Constants';
|
||||||
|
import { BitNodeMultipliers } from '../../BitNode/BitNodeMultipliers';
|
||||||
|
|
||||||
|
function mult(f: Faction): number {
|
||||||
|
var favorMult = 1 + (f.favor / 100);
|
||||||
|
if (isNaN(favorMult)) {favorMult = 1;}
|
||||||
|
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHackingWorkRepGain(p: IPlayer, f: Faction): number {
|
||||||
|
return (p.hacking_skill + p.intelligence) /
|
||||||
|
CONSTANTS.MaxSkillLevel * p.faction_rep_mult *
|
||||||
|
p.getIntelligenceBonus(0.25) * mult(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFactionSecurityWorkRepGain(p: IPlayer, f: Faction): number {
|
||||||
|
var t = 0.9 * (p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.strength / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.defense / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.agility / CONSTANTS.MaxSkillLevel) / 4.5;
|
||||||
|
return t * p.faction_rep_mult * mult(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFactionFieldWorkRepGain(p: IPlayer, f: Faction): number {
|
||||||
|
var t = 0.9 * (p.hacking_skill / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.strength / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.defense / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.dexterity / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.agility / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.charisma / CONSTANTS.MaxSkillLevel +
|
||||||
|
p.intelligence / CONSTANTS.MaxSkillLevel) / 5.5;
|
||||||
|
return t * p.faction_rep_mult * mult(f);
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { AceEditor } from "../ScriptEditor/Ace";
|
import { AceEditor } from "../ScriptEditor/Ace";
|
||||||
import { CodeMirrorEditor } from "../ScriptEditor/CodeMirror";
|
import { CodeMirrorEditor } from "../ScriptEditor/CodeMirror";
|
||||||
|
import { CursorPositions } from "../ScriptEditor/CursorPositions";
|
||||||
import { AllServers } from "../Server/AllServers";
|
import { AllServers } from "../Server/AllServers";
|
||||||
import { processSingleServerGrowth } from "../Server/ServerHelpers";
|
import { processSingleServerGrowth } from "../Server/ServerHelpers";
|
||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
@@ -224,11 +225,13 @@ $(document).keydown(function(e) {
|
|||||||
function saveAndCloseScriptEditor() {
|
function saveAndCloseScriptEditor() {
|
||||||
var filename = document.getElementById("script-editor-filename").value;
|
var filename = document.getElementById("script-editor-filename").value;
|
||||||
|
|
||||||
let code;
|
let code, cursor;
|
||||||
try {
|
try {
|
||||||
code = getCurrentEditor().getCode();
|
code = getCurrentEditor().getCode();
|
||||||
|
cursor = getCurrentEditor().getCursor();
|
||||||
|
CursorPositions.saveCursor(filename, cursor);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
dialogBoxCreate("Something went wrong when trying to save (getCurrentEditor().getCode()). Please report to game developer with details");
|
dialogBoxCreate("Something went wrong when trying to save (getCurrentEditor().getCode() or getCurrentEditor().getCursor()). Please report to game developer with details");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +271,7 @@ function saveAndCloseScriptEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filename !== ".fconf" && !isValidFilePath(filename)) {
|
if (filename !== ".fconf" && !isValidFilePath(filename)) {
|
||||||
dialogBoxCreate("Script filename can contain only alphanumerics, hyphens, and underscores");
|
dialogBoxCreate("Script filename can contain only alphanumerics, hyphens, and underscores, and must end with an extension.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +285,7 @@ function saveAndCloseScriptEditor() {
|
|||||||
}
|
}
|
||||||
} else if (isScriptFilename(filename)) {
|
} else if (isScriptFilename(filename)) {
|
||||||
//If the current script already exists on the server, overwrite it
|
//If the current script already exists on the server, overwrite it
|
||||||
for (var i = 0; i < s.scripts.length; i++) {
|
for (let i = 0; i < s.scripts.length; i++) {
|
||||||
if (filename == s.scripts[i].filename) {
|
if (filename == s.scripts[i].filename) {
|
||||||
s.scripts[i].saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
s.scripts[i].saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
||||||
Engine.loadTerminalContent();
|
Engine.loadTerminalContent();
|
||||||
@@ -295,14 +298,14 @@ function saveAndCloseScriptEditor() {
|
|||||||
script.saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
script.saveScript(getCurrentEditor().getCode(), Player.currentServer, Player.getCurrentServer().scripts);
|
||||||
s.scripts.push(script);
|
s.scripts.push(script);
|
||||||
} else if (filename.endsWith(".txt")) {
|
} else if (filename.endsWith(".txt")) {
|
||||||
for (var i = 0; i < s.textFiles.length; ++i) {
|
for (let i = 0; i < s.textFiles.length; ++i) {
|
||||||
if (s.textFiles[i].fn === filename) {
|
if (s.textFiles[i].fn === filename) {
|
||||||
s.textFiles[i].write(code);
|
s.textFiles[i].write(code);
|
||||||
Engine.loadTerminalContent();
|
Engine.loadTerminalContent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var textFile = new TextFile(filename, code);
|
const textFile = new TextFile(filename, code);
|
||||||
s.textFiles.push(textFile);
|
s.textFiles.push(textFile);
|
||||||
} else {
|
} else {
|
||||||
dialogBoxCreate("Invalid filename. Must be either a script (.script) or " +
|
dialogBoxCreate("Invalid filename. Must be either a script (.script) or " +
|
||||||
@@ -411,3 +414,14 @@ export function findRunningScript(filename, args, server) {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Returns a RunningScript object matching the pid on the
|
||||||
|
//designated server, and false otherwise
|
||||||
|
export function findRunningScriptByPid(pid, server) {
|
||||||
|
for (var i = 0; i < server.runningScripts.length; ++i) {
|
||||||
|
if (server.runningScripts[i].pid === pid) {
|
||||||
|
return server.runningScripts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -314,6 +314,14 @@ class AceEditorWrapper extends ScriptEditor {
|
|||||||
elem.style.display = "none";
|
elem.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCursor() {
|
||||||
|
return this.editor.getCursorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(pos) {
|
||||||
|
this.editor.gotoLine(pos.row+1, pos.column);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AceEditor = new AceEditorWrapper();
|
export const AceEditor = new AceEditorWrapper();
|
||||||
|
|||||||
@@ -570,6 +570,15 @@ class CodeMirrorEditorWrapper extends ScriptEditor {
|
|||||||
elem.style.display = "none";
|
elem.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCursor() {
|
||||||
|
const c = this.editor.getCursor(); //I need to get the cursor position
|
||||||
|
return {row: c.line, column: c.ch};
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(pos) {
|
||||||
|
this.editor.setCursor({line: pos.row, ch: pos.column});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodeMirrorEditor = new CodeMirrorEditorWrapper();
|
export const CodeMirrorEditor = new CodeMirrorEditorWrapper();
|
||||||
|
|||||||
29
src/ScriptEditor/CursorPositions.ts
Normal file
29
src/ScriptEditor/CursorPositions.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
export type Position = {
|
||||||
|
row: number;
|
||||||
|
column: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PositionTracker {
|
||||||
|
positions: Map<string, Position>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.positions = new Map<string, Position>();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveCursor(filename: string, pos: Position) {
|
||||||
|
this.positions.set(filename, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCursor(filename: string): Position {
|
||||||
|
const position = this.positions.get(filename);
|
||||||
|
if (!position) {
|
||||||
|
return {
|
||||||
|
row: 0,
|
||||||
|
column: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CursorPositions: PositionTracker = new PositionTracker();
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { CursorPositions } from './CursorPositions';
|
||||||
|
|
||||||
// Base Script Editor class for the Ace/CodeMirror/etc. wrappers
|
// Base Script Editor class for the Ace/CodeMirror/etc. wrappers
|
||||||
const beautify = require('js-beautify').js_beautify;
|
const beautify = require('js-beautify').js_beautify;
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ export class ScriptEditor {
|
|||||||
if (filename != "") {
|
if (filename != "") {
|
||||||
this.filenameInput.value = filename;
|
this.filenameInput.value = filename;
|
||||||
this.editor.setValue(code);
|
this.editor.setValue(code);
|
||||||
|
this.setCursor(CursorPositions.getCursor(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ export class Server extends BaseServer {
|
|||||||
return Generic_fromJSON(Server, value.data);
|
return Generic_fromJSON(Server, value.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flag indicating whether this server has a backdoor installed by a player
|
||||||
|
backdoorInstalled: boolean = false;
|
||||||
|
|
||||||
// Initial server security level
|
// Initial server security level
|
||||||
// (i.e. security level when the server was created)
|
// (i.e. security level when the server was created)
|
||||||
baseDifficulty: number = 1;
|
baseDifficulty: number = 1;
|
||||||
@@ -37,10 +40,6 @@ export class Server extends BaseServer {
|
|||||||
// Server Security Level
|
// Server Security Level
|
||||||
hackDifficulty: number = 1;
|
hackDifficulty: number = 1;
|
||||||
|
|
||||||
// Flag indicating whether this server has been manually hacked (ie.
|
|
||||||
// hacked through Terminal) by the player
|
|
||||||
manuallyHacked: boolean = false;
|
|
||||||
|
|
||||||
// Minimum server security level that this server can be weakened to
|
// Minimum server security level that this server can be weakened to
|
||||||
minDifficulty: number = 1;
|
minDifficulty: number = 1;
|
||||||
|
|
||||||
@@ -103,7 +102,7 @@ export class Server extends BaseServer {
|
|||||||
|
|
||||||
// Place some arbitrarily limit that realistically should never happen unless someone is
|
// Place some arbitrarily limit that realistically should never happen unless someone is
|
||||||
// screwing around with the game
|
// screwing around with the game
|
||||||
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
|
if (this.hackDifficulty > 100) {this.hackDifficulty = 100;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -147,3 +147,10 @@ export function getServerOnNetwork(server: Server, i: number) {
|
|||||||
|
|
||||||
return AllServers[server.serversOnNetwork[i]];
|
return AllServers[server.serversOnNetwork[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isBackdoorInstalled(server: Server | HacknetServer): boolean {
|
||||||
|
if ("backdoorInstalled" in server) {
|
||||||
|
return server.backdoorInstalled;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
min: 1050,
|
min: 1050,
|
||||||
},
|
},
|
||||||
serverGrowth: 99,
|
serverGrowth: 99,
|
||||||
|
specialName: LocationName.AevumECorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 99,
|
hackDifficulty: 99,
|
||||||
@@ -106,6 +107,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
min: 1100,
|
min: 1100,
|
||||||
},
|
},
|
||||||
serverGrowth: 99,
|
serverGrowth: 99,
|
||||||
|
specialName: LocationName.Sector12MegaCorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -128,6 +130,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumBachmanAndAssociates,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -155,6 +158,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 85,
|
max: 85,
|
||||||
min: 55,
|
min: 55,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12BladeIndustries,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 99,
|
hackDifficulty: 99,
|
||||||
@@ -175,6 +179,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 95,
|
max: 95,
|
||||||
min: 65,
|
min: 65,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenNWO,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -201,6 +206,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 75,
|
max: 75,
|
||||||
min: 45,
|
min: 45,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumClarkeIncorporated,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -231,6 +237,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 95,
|
min: 95,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenOmniTekIncorporated,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -253,6 +260,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 75,
|
min: 75,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12FourSigma,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -275,6 +283,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 90,
|
min: 90,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.ChongqingKuaiGongInternational,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -302,6 +311,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 99,
|
max: 99,
|
||||||
min: 80,
|
min: 80,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumFulcrumTechnologies,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 99,
|
hackDifficulty: 99,
|
||||||
@@ -338,6 +348,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 92,
|
max: 92,
|
||||||
min: 68,
|
min: 68,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.IshimaStormTechnologies,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -360,6 +371,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 73,
|
max: 73,
|
||||||
min: 47,
|
min: 47,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.NewTokyoDefComm,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -409,6 +421,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 70,
|
min: 70,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenHeliosLabs,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -436,6 +449,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.NewTokyoVitaLife,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -458,6 +472,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 95,
|
max: 95,
|
||||||
min: 85,
|
min: 85,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12IcarusMicrosystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -484,6 +499,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 90,
|
max: 90,
|
||||||
min: 80,
|
min: 80,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12UniversalEnergy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -586,6 +602,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 90,
|
max: 90,
|
||||||
min: 70,
|
min: 70,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumGalacticCybersystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -609,6 +626,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 65,
|
max: 65,
|
||||||
min: 55,
|
min: 55,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumAeroCorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -636,6 +654,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 70,
|
max: 70,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenOmniaCybersystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -711,6 +730,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 80,
|
max: 80,
|
||||||
min: 70,
|
min: 70,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.ChongqingSolarisSpaceSystems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -733,6 +753,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 70,
|
max: 70,
|
||||||
min: 50,
|
min: 50,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12DeltaOne,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -760,6 +781,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 90,
|
max: 90,
|
||||||
min: 80,
|
min: 80,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.NewTokyoGlobalPharmaceuticals,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -782,6 +804,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 85,
|
max: 85,
|
||||||
min: 65,
|
min: 65,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.IshimaNovaMedical,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -856,6 +879,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 65,
|
max: 65,
|
||||||
min: 55,
|
min: 55,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenLexoCorp,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -882,6 +906,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 40,
|
min: 40,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumRhoConstruction,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -909,6 +934,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 50,
|
min: 50,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12AlphaEnterprises,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -935,6 +961,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 50,
|
max: 50,
|
||||||
min: 30,
|
min: 30,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumPolice,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -966,6 +993,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 45,
|
max: 45,
|
||||||
min: 35,
|
min: 35,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12RothmanUniversity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -992,6 +1020,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 85,
|
max: 85,
|
||||||
min: 75,
|
min: 75,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenZBInstituteOfTechnology,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1023,6 +1052,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 40,
|
min: 40,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumSummitUniversity,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1045,6 +1075,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 70,
|
max: 70,
|
||||||
min: 60,
|
min: 60,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenSysCoreSecurities,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1121,6 +1152,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 65,
|
max: 65,
|
||||||
min: 45,
|
min: 45,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenCompuTek,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1145,6 +1177,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 75,
|
max: 75,
|
||||||
min: 45,
|
min: 45,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumNetLinkTechnologies,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1169,38 +1202,40 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 10,
|
hackDifficulty: 1,
|
||||||
hostname: "foodnstuff",
|
hostname: "foodnstuff",
|
||||||
literature: [LiteratureNames.Sector12Crime],
|
literature: [LiteratureNames.Sector12Crime],
|
||||||
maxRamExponent: 4,
|
maxRamExponent: 4,
|
||||||
moneyAvailable: 2000000,
|
moneyAvailable: 40000,
|
||||||
networkLayer: 1,
|
networkLayer: 1,
|
||||||
numOpenPortsRequired: 0,
|
numOpenPortsRequired: 0,
|
||||||
organizationName: LocationName.Sector12FoodNStuff,
|
organizationName: LocationName.Sector12FoodNStuff,
|
||||||
requiredHackingSkill: 1,
|
requiredHackingSkill: 1,
|
||||||
serverGrowth: 5,
|
serverGrowth: 3000,
|
||||||
|
specialName: LocationName.Sector12FoodNStuff,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 10,
|
hackDifficulty: 3,
|
||||||
hostname: "sigma-cosmetics",
|
hostname: "sigma-cosmetics",
|
||||||
maxRamExponent: 4,
|
maxRamExponent: 4,
|
||||||
moneyAvailable: 2300000,
|
moneyAvailable: 70000,
|
||||||
networkLayer: 1,
|
networkLayer: 1,
|
||||||
numOpenPortsRequired: 0,
|
numOpenPortsRequired: 0,
|
||||||
organizationName: "Sigma Cosmetics",
|
organizationName: "Sigma Cosmetics",
|
||||||
requiredHackingSkill: 5,
|
requiredHackingSkill: 5,
|
||||||
serverGrowth: 10,
|
serverGrowth: 3000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 15,
|
hackDifficulty: 9,
|
||||||
hostname: "joesguns",
|
hostname: "joesguns",
|
||||||
maxRamExponent: 4,
|
maxRamExponent: 4,
|
||||||
moneyAvailable: 2500000,
|
moneyAvailable: 600000,
|
||||||
networkLayer: 1,
|
networkLayer: 1,
|
||||||
numOpenPortsRequired: 0,
|
numOpenPortsRequired: 0,
|
||||||
organizationName: "Joes Guns",
|
organizationName: LocationName.Sector12JoesGuns,
|
||||||
requiredHackingSkill: 10,
|
requiredHackingSkill: 10,
|
||||||
serverGrowth: 20,
|
serverGrowth: 500,
|
||||||
|
specialName: LocationName.Sector12JoesGuns,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 25,
|
hackDifficulty: 25,
|
||||||
@@ -1316,6 +1351,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 40,
|
max: 40,
|
||||||
min: 30,
|
min: 30,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.IshimaOmegaSoftware,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1338,6 +1374,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 33,
|
max: 33,
|
||||||
min: 27,
|
min: 27,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumCrushFitnessGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 30,
|
hackDifficulty: 30,
|
||||||
@@ -1349,6 +1386,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
organizationName: "Iron Gym Network",
|
organizationName: "Iron Gym Network",
|
||||||
requiredHackingSkill: 100,
|
requiredHackingSkill: 100,
|
||||||
serverGrowth: 20,
|
serverGrowth: 20,
|
||||||
|
specialName: LocationName.Sector12IronGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1372,6 +1410,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 45,
|
max: 45,
|
||||||
min: 25,
|
min: 25,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.VolhavenMilleniumFitnessGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1395,6 +1434,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 50,
|
min: 50,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.Sector12PowerhouseGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: {
|
hackDifficulty: {
|
||||||
@@ -1414,6 +1454,7 @@ export const serverMetadata: IServerMetadata[] = [
|
|||||||
max: 60,
|
max: 60,
|
||||||
min: 40,
|
min: 40,
|
||||||
},
|
},
|
||||||
|
specialName: LocationName.AevumSnapFitnessGym,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hackDifficulty: 0,
|
hackDifficulty: 0,
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ interface IDefaultSettings {
|
|||||||
* Whether global keyboard shortcuts should be recognized throughout the game.
|
* Whether global keyboard shortcuts should be recognized throughout the game.
|
||||||
*/
|
*/
|
||||||
DisableHotkeys: boolean;
|
DisableHotkeys: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether text effects such as corruption should be visible.
|
||||||
|
*/
|
||||||
|
DisableTextEffects: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locale used for display numbers
|
* Locale used for display numbers
|
||||||
@@ -108,6 +113,7 @@ const defaultSettings: IDefaultSettings = {
|
|||||||
CodeInstructionRunTime: 50,
|
CodeInstructionRunTime: 50,
|
||||||
DisableASCIIArt: false,
|
DisableASCIIArt: false,
|
||||||
DisableHotkeys: false,
|
DisableHotkeys: false,
|
||||||
|
DisableTextEffects: false,
|
||||||
Locale: "en",
|
Locale: "en",
|
||||||
MaxLogCapacity: 50,
|
MaxLogCapacity: 50,
|
||||||
MaxPortCapacity: 50,
|
MaxPortCapacity: 50,
|
||||||
@@ -127,8 +133,9 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
|||||||
CodeInstructionRunTime: 25,
|
CodeInstructionRunTime: 25,
|
||||||
DisableASCIIArt: defaultSettings.DisableASCIIArt,
|
DisableASCIIArt: defaultSettings.DisableASCIIArt,
|
||||||
DisableHotkeys: defaultSettings.DisableHotkeys,
|
DisableHotkeys: defaultSettings.DisableHotkeys,
|
||||||
Editor: EditorSetting.Ace,
|
DisableTextEffects: defaultSettings.DisableTextEffects,
|
||||||
EditorKeybinding: AceKeybindingSetting.Ace,
|
Editor: EditorSetting.CodeMirror,
|
||||||
|
EditorKeybinding: CodeMirrorKeybindingSetting.Default,
|
||||||
EditorTheme: "Monokai",
|
EditorTheme: "Monokai",
|
||||||
Locale: "en",
|
Locale: "en",
|
||||||
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
||||||
|
|||||||
538
src/Terminal.jsx
538
src/Terminal.jsx
@@ -60,7 +60,7 @@ import { Player } from "./Player";
|
|||||||
import { hackWorldDaemon } from "./RedPill";
|
import { hackWorldDaemon } from "./RedPill";
|
||||||
import { RunningScript } from "./Script/RunningScript";
|
import { RunningScript } from "./Script/RunningScript";
|
||||||
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
||||||
import { findRunningScript } from "./Script/ScriptHelpers";
|
import { getCurrentEditor, findRunningScript } from "./Script/ScriptHelpers";
|
||||||
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
import { isScriptFilename } from "./Script/ScriptHelpersTS";
|
||||||
import { AllServers } from "./Server/AllServers";
|
import { AllServers } from "./Server/AllServers";
|
||||||
import { Server } from "./Server/Server";
|
import { Server } from "./Server/Server";
|
||||||
@@ -108,7 +108,7 @@ import React from "react";
|
|||||||
|
|
||||||
|
|
||||||
function postNetburnerText() {
|
function postNetburnerText() {
|
||||||
post("Bitburner v" + CONSTANTS.Version);
|
post("Bitburner v" + CONSTANTS.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function that checks if an argument (which is a string) is a valid number
|
// Helper function that checks if an argument (which is a string) is a valid number
|
||||||
@@ -123,16 +123,16 @@ function getTerminalInput() {
|
|||||||
|
|
||||||
// Defines key commands in terminal
|
// Defines key commands in terminal
|
||||||
$(document).keydown(function(event) {
|
$(document).keydown(function(event) {
|
||||||
// Terminal
|
// Terminal
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
var terminalInput = document.getElementById("terminal-input-text-box");
|
var terminalInput = document.getElementById("terminal-input-text-box");
|
||||||
if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();}
|
if (terminalInput != null && !event.ctrlKey && !event.shiftKey && !Terminal.contractOpen) {terminalInput.focus();}
|
||||||
|
|
||||||
if (event.keyCode === KEY.ENTER) {
|
if (event.keyCode === KEY.ENTER) {
|
||||||
event.preventDefault(); // Prevent newline from being entered in Script Editor
|
event.preventDefault(); // Prevent newline from being entered in Script Editor
|
||||||
const command = getTerminalInput();
|
const command = getTerminalInput();
|
||||||
const dir = Terminal.currDir;
|
const dir = Terminal.currDir;
|
||||||
post(
|
post(
|
||||||
"<span class='prompt'>[" +
|
"<span class='prompt'>[" +
|
||||||
(FconfSettings.ENABLE_TIMESTAMPS ? getTimestamp() + " " : "") +
|
(FconfSettings.ENABLE_TIMESTAMPS ? getTimestamp() + " " : "") +
|
||||||
Player.getCurrentServer().hostname +
|
Player.getCurrentServer().hostname +
|
||||||
@@ -142,20 +142,20 @@ $(document).keydown(function(event) {
|
|||||||
if (command.length > 0) {
|
if (command.length > 0) {
|
||||||
Terminal.resetTerminalInput(); // Clear input first
|
Terminal.resetTerminalInput(); // Clear input first
|
||||||
Terminal.executeCommands(command);
|
Terminal.executeCommands(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === KEY.C && event.ctrlKey) {
|
if (event.keyCode === KEY.C && event.ctrlKey) {
|
||||||
if (Engine._actionInProgress) {
|
if (Engine._actionInProgress) {
|
||||||
// Cancel action
|
// Cancel action
|
||||||
post("Cancelling...");
|
post("Cancelling...");
|
||||||
Engine._actionInProgress = false;
|
Engine._actionInProgress = false;
|
||||||
Terminal.finishAction(true);
|
Terminal.finishAction(true);
|
||||||
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
|
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
|
||||||
// Dont prevent default so it still copies
|
// Dont prevent default so it still copies
|
||||||
Terminal.resetTerminalInput(); // Clear Terminal
|
Terminal.resetTerminalInput(); // Clear Terminal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === KEY.L && event.ctrlKey) {
|
if (event.keyCode === KEY.L && event.ctrlKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -183,7 +183,7 @@ $(document).keydown(function(event) {
|
|||||||
}
|
}
|
||||||
var prevCommand = Terminal.commandHistory[Terminal.commandHistoryIndex];
|
var prevCommand = Terminal.commandHistory[Terminal.commandHistoryIndex];
|
||||||
terminalInput.value = prevCommand;
|
terminalInput.value = prevCommand;
|
||||||
setTimeoutRef(function(){terminalInput.selectionStart = terminalInput.selectionEnd = 10000; }, 0);
|
setTimeoutRef(function(){terminalInput.selectionStart = terminalInput.selectionEnd = 10000; }, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.keyCode === KEY.DOWNARROW ||
|
if (event.keyCode === KEY.DOWNARROW ||
|
||||||
@@ -295,49 +295,50 @@ $(document).keydown(function(event) {
|
|||||||
// ^k clears line after cursor
|
// ^k clears line after cursor
|
||||||
// ^u clears line before cursor
|
// ^u clears line before cursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Keep terminal in focus
|
// Keep terminal in focus
|
||||||
let terminalCtrlPressed = false, shiftKeyPressed = false;
|
let terminalCtrlPressed = false, shiftKeyPressed = false;
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
$('.terminal-input').focus();
|
$('.terminal-input').focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).keydown(function(e) {
|
$(document).keydown(function(e) {
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
if (e.which == KEY.CTRL) {
|
if (e.which == KEY.CTRL) {
|
||||||
terminalCtrlPressed = true;
|
terminalCtrlPressed = true;
|
||||||
} else if (e.shiftKey) {
|
} else if (e.shiftKey) {
|
||||||
shiftKeyPressed = true;
|
shiftKeyPressed = true;
|
||||||
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
|
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
|
||||||
// Don't focus
|
// Don't focus
|
||||||
} else {
|
} else {
|
||||||
var inputTextBox = document.getElementById("terminal-input-text-box");
|
var inputTextBox = document.getElementById("terminal-input-text-box");
|
||||||
if (inputTextBox != null) {inputTextBox.focus();}
|
if (inputTextBox != null) {inputTextBox.focus();}
|
||||||
|
|
||||||
terminalCtrlPressed = false;
|
terminalCtrlPressed = false;
|
||||||
shiftKeyPressed = false;
|
shiftKeyPressed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).keyup(function(e) {
|
$(document).keyup(function(e) {
|
||||||
if (routing.isOn(Page.Terminal)) {
|
if (routing.isOn(Page.Terminal)) {
|
||||||
if (e.which == KEY.CTRL) {
|
if (e.which == KEY.CTRL) {
|
||||||
terminalCtrlPressed = false;
|
terminalCtrlPressed = false;
|
||||||
}
|
}
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
shiftKeyPressed = false;
|
shiftKeyPressed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let Terminal = {
|
let Terminal = {
|
||||||
// Flags to determine whether the player is currently running a hack or an analyze
|
// Flags to determine whether the player is currently running a hack or an analyze
|
||||||
hackFlag: false,
|
hackFlag: false,
|
||||||
|
backdoorFlag: false,
|
||||||
analyzeFlag: false,
|
analyzeFlag: false,
|
||||||
actionStarted: false,
|
actionStarted: false,
|
||||||
actionTime: 0,
|
actionTime: 0,
|
||||||
@@ -361,14 +362,14 @@ let Terminal = {
|
|||||||
if (FconfSettings.WRAP_INPUT) {
|
if (FconfSettings.WRAP_INPUT) {
|
||||||
document.getElementById("terminal-input-td").innerHTML =
|
document.getElementById("terminal-input-td").innerHTML =
|
||||||
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
||||||
`<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\"/>`;
|
`<textarea type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\" autocomplete="off" />`;
|
||||||
|
|
||||||
// Auto re-size the line element as it wraps
|
// Auto re-size the line element as it wraps
|
||||||
autosize(document.getElementById("terminal-input-text-box"));
|
autosize(document.getElementById("terminal-input-text-box"));
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("terminal-input-td").innerHTML =
|
document.getElementById("terminal-input-td").innerHTML =
|
||||||
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
`<div id='terminal-input-header' class='prompt'>[${Player.getCurrentServer().hostname} ~${dir}]$ </div>` +
|
||||||
`<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\"/>`;
|
`<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" value=\"${input}\" autocomplete="off" />`;
|
||||||
}
|
}
|
||||||
const hdr = document.getElementById("terminal-input-header");
|
const hdr = document.getElementById("terminal-input-header");
|
||||||
hdr.style.display = "inline";
|
hdr.style.display = "inline";
|
||||||
@@ -485,6 +486,14 @@ let Terminal = {
|
|||||||
Terminal.startAction();
|
Terminal.startAction();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
startBackdoor: function() {
|
||||||
|
Terminal.backdoorFlag = true;
|
||||||
|
|
||||||
|
// Backdoor should take the same amount of time as hack
|
||||||
|
Terminal.actionTime = calculateHackingTime(Player.getCurrentServer(), Player) / 4;
|
||||||
|
Terminal.startAction();
|
||||||
|
},
|
||||||
|
|
||||||
startAnalyze: function() {
|
startAnalyze: function() {
|
||||||
Terminal.analyzeFlag = true;
|
Terminal.analyzeFlag = true;
|
||||||
Terminal.actionTime = 1;
|
Terminal.actionTime = 1;
|
||||||
@@ -506,22 +515,30 @@ let Terminal = {
|
|||||||
finishAction: function(cancelled = false) {
|
finishAction: function(cancelled = false) {
|
||||||
if (Terminal.hackFlag) {
|
if (Terminal.hackFlag) {
|
||||||
Terminal.finishHack(cancelled);
|
Terminal.finishHack(cancelled);
|
||||||
|
} else if (Terminal.backdoorFlag) {
|
||||||
|
Terminal.finishBackdoor(cancelled);
|
||||||
} else if (Terminal.analyzeFlag) {
|
} else if (Terminal.analyzeFlag) {
|
||||||
Terminal.finishAnalyze(cancelled);
|
Terminal.finishAnalyze(cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
||||||
|
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
||||||
|
$("#hack-progress").attr('id', "old-hack-progress");
|
||||||
|
Terminal.resetTerminalInput();
|
||||||
|
$('input[class=terminal-input]').prop('disabled', false);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Complete the hack/analyze command
|
// Complete the hack/analyze command
|
||||||
finishHack: function(cancelled = false) {
|
finishHack: function(cancelled = false) {
|
||||||
if (cancelled == false) {
|
if (!cancelled) {
|
||||||
var server = Player.getCurrentServer();
|
var server = Player.getCurrentServer();
|
||||||
|
|
||||||
// Calculate whether hack was successful
|
// Calculate whether hack was successful
|
||||||
var hackChance = calculateHackingChance(server, Player);
|
var hackChance = calculateHackingChance(server, Player);
|
||||||
var rand = Math.random();
|
var rand = Math.random();
|
||||||
var expGainedOnSuccess = calculateHackingExpGain(server, Player);
|
var expGainedOnSuccess = calculateHackingExpGain(server, Player);
|
||||||
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
var expGainedOnFailure = (expGainedOnSuccess / 4);
|
||||||
if (rand < hackChance) { // Success!
|
if (rand < hackChance) { // Success!
|
||||||
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
if (SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip) {
|
||||||
if (Player.bitNodeN == null) {
|
if (Player.bitNodeN == null) {
|
||||||
@@ -530,91 +547,87 @@ let Terminal = {
|
|||||||
hackWorldDaemon(Player.bitNodeN);
|
hackWorldDaemon(Player.bitNodeN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
server.manuallyHacked = true;
|
server.backdoorInstalled = true;
|
||||||
var moneyGained = calculatePercentMoneyHacked(server, Player);
|
var moneyGained = calculatePercentMoneyHacked(server, Player);
|
||||||
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
||||||
|
|
||||||
if (moneyGained <= 0) {moneyGained = 0;} // Safety check
|
if (moneyGained <= 0) {moneyGained = 0;} // Safety check
|
||||||
|
|
||||||
server.moneyAvailable -= moneyGained;
|
server.moneyAvailable -= moneyGained;
|
||||||
Player.gainMoney(moneyGained);
|
Player.gainMoney(moneyGained);
|
||||||
Player.recordMoneySource(moneyGained, "hacking");
|
Player.recordMoneySource(moneyGained, "hacking");
|
||||||
Player.gainHackingExp(expGainedOnSuccess)
|
Player.gainHackingExp(expGainedOnSuccess)
|
||||||
Player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
|
Player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
|
||||||
|
|
||||||
server.fortify(CONSTANTS.ServerFortifyAmount);
|
server.fortify(CONSTANTS.ServerFortifyAmount);
|
||||||
|
|
||||||
postElement(<>Hack successful! Gained {Money(moneyGained)} and {numeralWrapper.formatExp(expGainedOnSuccess)} hacking exp</>);
|
postElement(<>Hack successful! Gained {Money(moneyGained)} and {numeralWrapper.formatExp(expGainedOnSuccess)} hacking exp</>);
|
||||||
} else { // Failure
|
} else { // Failure
|
||||||
// Player only gains 25% exp for failure? TODO Can change this later to balance
|
// Player only gains 25% exp for failure? TODO Can change this later to balance
|
||||||
Player.gainHackingExp(expGainedOnFailure)
|
Player.gainHackingExp(expGainedOnFailure)
|
||||||
post(`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`);
|
post(`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
|
||||||
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
|
||||||
$("#hack-progress").attr('id', "old-hack-progress");
|
|
||||||
Terminal.resetTerminalInput();
|
|
||||||
$('input[class=terminal-input]').prop('disabled', false);
|
|
||||||
|
|
||||||
Terminal.hackFlag = false;
|
Terminal.hackFlag = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
finishBackdoor: function(cancelled = false) {
|
||||||
|
if(!cancelled){
|
||||||
|
let server = Player.getCurrentServer();
|
||||||
|
server.backdoorInstalled = true;
|
||||||
|
postElement(<>Backdoor successful!</>);
|
||||||
|
}
|
||||||
|
Terminal.backdoorFlag = false;
|
||||||
|
},
|
||||||
|
|
||||||
finishAnalyze: function(cancelled = false) {
|
finishAnalyze: function(cancelled = false) {
|
||||||
if (cancelled == false) {
|
if (!cancelled) {
|
||||||
let currServ = Player.getCurrentServer();
|
let currServ = Player.getCurrentServer();
|
||||||
const isHacknet = currServ instanceof HacknetServer;
|
const isHacknet = currServ instanceof HacknetServer;
|
||||||
post(currServ.hostname + ": ");
|
post(currServ.hostname + ": ");
|
||||||
post("Organization name: " + currServ.organizationName);
|
post("Organization name: " + currServ.organizationName);
|
||||||
var rootAccess = "";
|
var rootAccess = "";
|
||||||
if (currServ.hasAdminRights) {rootAccess = "YES";}
|
if (currServ.hasAdminRights) {rootAccess = "YES";}
|
||||||
else {rootAccess = "NO";}
|
else {rootAccess = "NO";}
|
||||||
post("Root Access: " + rootAccess);
|
post("Root Access: " + rootAccess);
|
||||||
if (!isHacknet) { post("Required hacking skill: " + currServ.requiredHackingSkill); }
|
if (!isHacknet) { post("Required hacking skill: " + currServ.requiredHackingSkill); }
|
||||||
post("Server security level: " + numeralWrapper.formatServerSecurity(currServ.hackDifficulty));
|
post("Server security level: " + numeralWrapper.formatServerSecurity(currServ.hackDifficulty));
|
||||||
post("Chance to hack: " + numeralWrapper.formatPercentage(calculateHackingChance(currServ, Player)));
|
post("Chance to hack: " + numeralWrapper.formatPercentage(calculateHackingChance(currServ, Player)));
|
||||||
post("Time to hack: " + convertTimeMsToTimeElapsedString(calculateHackingTime(currServ, Player)*1000));
|
post("Time to hack: " + convertTimeMsToTimeElapsedString(calculateHackingTime(currServ, Player)*1000));
|
||||||
postElement(<>Total money available on server: {Money(currServ.moneyAvailable)}</>);
|
postElement(<>Total money available on server: {Money(currServ.moneyAvailable)}</>);
|
||||||
if (!isHacknet) { post("Required number of open ports for NUKE: " + currServ.numOpenPortsRequired); }
|
if (!isHacknet) { post("Required number of open ports for NUKE: " + currServ.numOpenPortsRequired); }
|
||||||
|
|
||||||
if (currServ.sshPortOpen) {
|
if (currServ.sshPortOpen) {
|
||||||
post("SSH port: Open")
|
post("SSH port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("SSH port: Closed")
|
post("SSH port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.ftpPortOpen) {
|
if (currServ.ftpPortOpen) {
|
||||||
post("FTP port: Open")
|
post("FTP port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("FTP port: Closed")
|
post("FTP port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.smtpPortOpen) {
|
if (currServ.smtpPortOpen) {
|
||||||
post("SMTP port: Open")
|
post("SMTP port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("SMTP port: Closed")
|
post("SMTP port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.httpPortOpen) {
|
if (currServ.httpPortOpen) {
|
||||||
post("HTTP port: Open")
|
post("HTTP port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("HTTP port: Closed")
|
post("HTTP port: Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currServ.sqlPortOpen) {
|
if (currServ.sqlPortOpen) {
|
||||||
post("SQL port: Open")
|
post("SQL port: Open")
|
||||||
} else {
|
} else {
|
||||||
post("SQL port: Closed")
|
post("SQL port: Closed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Terminal.analyzeFlag = false;
|
Terminal.analyzeFlag = false;
|
||||||
|
|
||||||
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
|
||||||
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
|
||||||
$("#hack-progress").attr('id', "old-hack-progress");
|
|
||||||
Terminal.resetTerminalInput();
|
|
||||||
$('input[class=terminal-input]').prop('disabled', false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
executeCommands : function(commands) {
|
executeCommands : function(commands) {
|
||||||
@@ -729,7 +742,7 @@ let Terminal = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
executeCommand : function(command) {
|
executeCommand : function(command) {
|
||||||
if (Terminal.hackFlag || Terminal.analyzeFlag) {
|
if (Terminal.hackFlag || Terminal.backdoorFlag || Terminal.analyzeFlag) {
|
||||||
postError(`Cannot execute command (${command}) while an action is in progress`);
|
postError(`Cannot execute command (${command}) while an action is in progress`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -743,8 +756,8 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only split the first space
|
// Only split the first space
|
||||||
var commandArray = Terminal.parseCommandArguments(command);
|
var commandArray = Terminal.parseCommandArguments(command);
|
||||||
if (commandArray.length == 0) { return; }
|
if (commandArray.length == 0) { return; }
|
||||||
|
|
||||||
/****************** Interactive Tutorial Terminal Commands ******************/
|
/****************** Interactive Tutorial Terminal Commands ******************/
|
||||||
if (ITutorial.isRunning) {
|
if (ITutorial.isRunning) {
|
||||||
@@ -820,7 +833,7 @@ let Terminal = {
|
|||||||
Terminal.startHack();
|
Terminal.startHack();
|
||||||
iTutorialNextStep();
|
iTutorialNextStep();
|
||||||
} else {post("Bad command. Please follow the tutorial");}
|
} else {post("Bad command. Please follow the tutorial");}
|
||||||
break;
|
break;
|
||||||
case iTutorialSteps.TerminalCreateScript:
|
case iTutorialSteps.TerminalCreateScript:
|
||||||
if (commandArray.length == 2 &&
|
if (commandArray.length == 2 &&
|
||||||
commandArray[0] == "nano" && commandArray[1] == "foodnstuff.script") {
|
commandArray[0] == "nano" && commandArray[1] == "foodnstuff.script") {
|
||||||
@@ -865,7 +878,7 @@ let Terminal = {
|
|||||||
|
|
||||||
/* Command parser */
|
/* Command parser */
|
||||||
var s = Player.getCurrentServer();
|
var s = Player.getCurrentServer();
|
||||||
switch (commandArray[0].toLowerCase()) {
|
switch (commandArray[0].toLowerCase()) {
|
||||||
case "alias":
|
case "alias":
|
||||||
if (commandArray.length === 1) {
|
if (commandArray.length === 1) {
|
||||||
printAliases();
|
printAliases();
|
||||||
@@ -887,13 +900,31 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
postError('Incorrect usage of alias command. Usage: alias [-g] [aliasname="value"]');
|
postError('Incorrect usage of alias command. Usage: alias [-g] [aliasname="value"]');
|
||||||
break;
|
break;
|
||||||
case "analyze":
|
case "analyze":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
post("Incorrect usage of analyze command. Usage: analyze");
|
post("Incorrect usage of analyze command. Usage: analyze");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Terminal.startAnalyze();
|
Terminal.startAnalyze();
|
||||||
break;
|
break;
|
||||||
|
case "backdoor":
|
||||||
|
if (commandArray.length !== 1) {
|
||||||
|
post("Incorrect usage of backdoor command. Usage: backdoor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.purchasedByPlayer) {
|
||||||
|
postError("Cannot use backdoor on your own machines! You are currently connected to your home PC or one of your purchased servers");
|
||||||
|
} else if (!s.hasAdminRights) {
|
||||||
|
postError("You do not have admin rights for this machine! Cannot backdoor");
|
||||||
|
} else if (s.requiredHackingSkill > Player.hacking_skill) {
|
||||||
|
postError("Your hacking skill is not high enough to use backdoor on this machine. Try analyzing the machine to determine the required hacking skill");
|
||||||
|
} else if (s instanceof HacknetServer) {
|
||||||
|
postError("Cannot use backdoor on this type of Server")
|
||||||
|
} else {
|
||||||
|
Terminal.startBackdoor();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "buy":
|
case "buy":
|
||||||
if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
||||||
executeDarkwebTerminalCommand(commandArray);
|
executeDarkwebTerminalCommand(commandArray);
|
||||||
@@ -908,10 +939,10 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filename = Terminal.getFilepath(commandArray[1]);
|
const filename = Terminal.getFilepath(commandArray[1]);
|
||||||
if (!filename.endsWith(".msg") && !filename.endsWith(".lit") && !filename.endsWith(".txt")) {
|
if (!filename.endsWith(".msg") && !filename.endsWith(".lit") && !filename.endsWith(".txt")) {
|
||||||
postError("Only .msg, .txt, and .lit files are viewable with cat (filename must end with .msg, .txt, or .lit)");
|
postError("Only .msg, .txt, and .lit files are viewable with cat (filename must end with .msg, .txt, or .lit)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename.endsWith(".msg") || filename.endsWith(".lit")) {
|
if (filename.endsWith(".msg") || filename.endsWith(".lit")) {
|
||||||
for (let i = 0; i < s.messages.length; ++i) {
|
for (let i = 0; i < s.messages.length; ++i) {
|
||||||
@@ -938,10 +969,10 @@ let Terminal = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "cd": {
|
case "cd": {
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length > 2) {
|
||||||
postError("Incorrect number of arguments. Usage: cd [dir]");
|
postError("Incorrect number of arguments. Usage: cd [dir]");
|
||||||
} else {
|
} else {
|
||||||
let dir = commandArray[1];
|
let dir = commandArray.length === 2 ? commandArray[1] : "/";
|
||||||
|
|
||||||
let evaledDir;
|
let evaledDir;
|
||||||
if (dir === "/") {
|
if (dir === "/") {
|
||||||
@@ -955,6 +986,12 @@ let Terminal = {
|
|||||||
postError("Invalid path. Failed to change directories");
|
postError("Invalid path. Failed to change directories");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const server = Player.getCurrentServer();
|
||||||
|
if(!server.scripts.some(script => script.filename.startsWith(evaledDir))) {
|
||||||
|
postError("Invalid path. Failed to change directories");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminal.currDir = evaledDir;
|
Terminal.currDir = evaledDir;
|
||||||
@@ -996,17 +1033,17 @@ let Terminal = {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "clear":
|
case "clear":
|
||||||
case "cls":
|
case "cls":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of clear/cls command. Usage: clear/cls");
|
postError("Incorrect usage of clear/cls command. Usage: clear/cls");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$("#terminal tr:not(:last)").remove();
|
$("#terminal tr:not(:last)").remove();
|
||||||
postNetburnerText();
|
postNetburnerText();
|
||||||
break;
|
break;
|
||||||
case "connect": {
|
case "connect": {
|
||||||
// Disconnect from current server in terminal and connect to new one
|
// Disconnect from current server in terminal and connect to new one
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length !== 2) {
|
||||||
postError("Incorrect usage of connect command. Usage: connect [ip/hostname]");
|
postError("Incorrect usage of connect command. Usage: connect [ip/hostname]");
|
||||||
return;
|
return;
|
||||||
@@ -1022,7 +1059,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
postError("Host not found");
|
postError("Host not found");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "download": {
|
case "download": {
|
||||||
try {
|
try {
|
||||||
@@ -1102,35 +1139,35 @@ let Terminal = {
|
|||||||
post(result);
|
post(result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "free":
|
case "free":
|
||||||
Terminal.executeFreeCommand(commandArray);
|
Terminal.executeFreeCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
case "hack": {
|
case "hack": {
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of hack command. Usage: hack");
|
postError("Incorrect usage of hack command. Usage: hack");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Hack the current PC (usually for money)
|
// Hack the current PC (usually for money)
|
||||||
// You can't hack your home pc or servers you purchased
|
// You can't hack your home pc or servers you purchased
|
||||||
if (s.purchasedByPlayer) {
|
if (s.purchasedByPlayer) {
|
||||||
postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers");
|
postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers");
|
||||||
} else if (s.hasAdminRights == false ) {
|
} else if (s.hasAdminRights == false ) {
|
||||||
postError("You do not have admin rights for this machine! Cannot hack");
|
postError("You do not have admin rights for this machine! Cannot hack");
|
||||||
} else if (s.requiredHackingSkill > Player.hacking_skill) {
|
} else if (s.requiredHackingSkill > Player.hacking_skill) {
|
||||||
postError("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill");
|
postError("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill");
|
||||||
} else if (s instanceof HacknetServer) {
|
} else if (s instanceof HacknetServer) {
|
||||||
postError("Cannot hack this type of Server")
|
postError("Cannot hack this type of Server")
|
||||||
} else {
|
} else {
|
||||||
Terminal.startHack();
|
Terminal.startHack();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "help":
|
case "help":
|
||||||
if (commandArray.length !== 1 && commandArray.length !== 2) {
|
if (commandArray.length !== 1 && commandArray.length !== 2) {
|
||||||
postError("Incorrect usage of help command. Usage: help");
|
postError("Incorrect usage of help command. Usage: help");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (commandArray.length === 1) {
|
if (commandArray.length === 1) {
|
||||||
post(TerminalHelpText);
|
post(TerminalHelpText);
|
||||||
} else {
|
} else {
|
||||||
var cmd = commandArray[1];
|
var cmd = commandArray[1];
|
||||||
@@ -1141,9 +1178,9 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
post(txt);
|
post(txt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "home":
|
case "home":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of home command. Usage: home");
|
postError("Incorrect usage of home command. Usage: home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1153,24 +1190,24 @@ let Terminal = {
|
|||||||
post("Connected to home");
|
post("Connected to home");
|
||||||
Terminal.currDir = "/";
|
Terminal.currDir = "/";
|
||||||
Terminal.resetTerminalInput();
|
Terminal.resetTerminalInput();
|
||||||
break;
|
break;
|
||||||
case "hostname":
|
case "hostname":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of hostname command. Usage: hostname");
|
postError("Incorrect usage of hostname command. Usage: hostname");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
post(Player.getCurrentServer().hostname);
|
post(Player.getCurrentServer().hostname);
|
||||||
break;
|
break;
|
||||||
case "ifconfig":
|
case "ifconfig":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of ifconfig command. Usage: ifconfig");
|
postError("Incorrect usage of ifconfig command. Usage: ifconfig");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
post(Player.getCurrentServer().ip);
|
post(Player.getCurrentServer().ip);
|
||||||
break;
|
break;
|
||||||
case "kill": {
|
case "kill": {
|
||||||
Terminal.executeKillCommand(commandArray);
|
Terminal.executeKillCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "killall": {
|
case "killall": {
|
||||||
for (let i = s.runningScripts.length - 1; i >= 0; --i) {
|
for (let i = s.runningScripts.length - 1; i >= 0; --i) {
|
||||||
@@ -1180,9 +1217,9 @@ let Terminal = {
|
|||||||
post("Killing all running scripts");
|
post("Killing all running scripts");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "ls": {
|
case "ls": {
|
||||||
Terminal.executeListCommand(commandArray);
|
Terminal.executeListCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "lscpu": {
|
case "lscpu": {
|
||||||
post(Player.getCurrentServer().cpuCores + " Core(s)");
|
post(Player.getCurrentServer().cpuCores + " Core(s)");
|
||||||
@@ -1269,25 +1306,25 @@ let Terminal = {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "nano":
|
case "nano":
|
||||||
Terminal.executeNanoCommand(commandArray);
|
Terminal.executeNanoCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
case "ps":
|
case "ps":
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of ps command. Usage: ps");
|
postError("Incorrect usage of ps command. Usage: ps");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < s.runningScripts.length; i++) {
|
for (let i = 0; i < s.runningScripts.length; i++) {
|
||||||
let rsObj = s.runningScripts[i];
|
let rsObj = s.runningScripts[i];
|
||||||
let res = `(PID - ${rsObj.pid}) ${rsObj.filename}`;
|
let res = `(PID - ${rsObj.pid}) ${rsObj.filename}`;
|
||||||
for (let j = 0; j < rsObj.args.length; ++j) {
|
for (let j = 0; j < rsObj.args.length; ++j) {
|
||||||
res += (" " + rsObj.args[j].toString());
|
res += (" " + rsObj.args[j].toString());
|
||||||
}
|
}
|
||||||
post(res);
|
post(res);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "rm": {
|
case "rm": {
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length !== 2) {
|
||||||
postError("Incorrect number of arguments. Usage: rm [program/script]");
|
postError("Incorrect number of arguments. Usage: rm [program/script]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1299,14 +1336,14 @@ let Terminal = {
|
|||||||
if (!status.res) {
|
if (!status.res) {
|
||||||
postError(status.msg);
|
postError(status.msg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "run":
|
case "run":
|
||||||
// Run a program or a script
|
// Run a program or a script
|
||||||
if (commandArray.length < 2) {
|
if (commandArray.length < 2) {
|
||||||
postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
|
postError("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
|
||||||
} else {
|
} else {
|
||||||
var executableName = commandArray[1];
|
var executableName = commandArray[1];
|
||||||
|
|
||||||
// Secret Music player!
|
// Secret Music player!
|
||||||
if (executableName === "musicplayer") {
|
if (executableName === "musicplayer") {
|
||||||
@@ -1314,19 +1351,19 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if its a script or just a program/executable
|
// Check if its a script or just a program/executable
|
||||||
if (isScriptFilename(executableName)) {
|
if (isScriptFilename(executableName)) {
|
||||||
Terminal.runScript(commandArray);
|
Terminal.runScript(commandArray);
|
||||||
} else if (executableName.endsWith(".cct")) {
|
} else if (executableName.endsWith(".cct")) {
|
||||||
Terminal.runContract(executableName);
|
Terminal.runContract(executableName);
|
||||||
} else {
|
} else {
|
||||||
Terminal.runProgram(commandArray);
|
Terminal.runProgram(commandArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "scan":
|
case "scan":
|
||||||
Terminal.executeScanCommand(commandArray);
|
Terminal.executeScanCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
case "scan-analyze":
|
case "scan-analyze":
|
||||||
if (commandArray.length === 1) {
|
if (commandArray.length === 1) {
|
||||||
Terminal.executeScanAnalyzeCommand(1);
|
Terminal.executeScanAnalyzeCommand(1);
|
||||||
@@ -1362,7 +1399,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* eslint-disable no-case-declarations */
|
/* eslint-disable no-case-declarations */
|
||||||
case "scp":
|
case "scp":
|
||||||
Terminal.executeScpCommand(commandArray);
|
Terminal.executeScpCommand(commandArray);
|
||||||
break;
|
break;
|
||||||
/* eslint-enable no-case-declarations */
|
/* eslint-enable no-case-declarations */
|
||||||
@@ -1378,7 +1415,7 @@ let Terminal = {
|
|||||||
post("You do NOT have root access to this machine");
|
post("You do NOT have root access to this machine");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "tail": {
|
case "tail": {
|
||||||
try {
|
try {
|
||||||
if (commandArray.length < 2) {
|
if (commandArray.length < 2) {
|
||||||
postError("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
|
postError("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
|
||||||
@@ -1407,7 +1444,7 @@ let Terminal = {
|
|||||||
Terminal.postThrownError(e);
|
Terminal.postThrownError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "theme": {
|
case "theme": {
|
||||||
let args = commandArray.slice(1);
|
let args = commandArray.slice(1);
|
||||||
@@ -1455,11 +1492,11 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "top": {
|
case "top": {
|
||||||
if (commandArray.length !== 1) {
|
if (commandArray.length !== 1) {
|
||||||
postError("Incorrect usage of top command. Usage: top");
|
postError("Incorrect usage of top command. Usage: top");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers
|
// Headers
|
||||||
const scriptWidth = 40;
|
const scriptWidth = 40;
|
||||||
@@ -1477,29 +1514,29 @@ let Terminal = {
|
|||||||
|
|
||||||
const headers = `${scriptTxt}${spacesAfterScriptTxt}${pidTxt}${spacesAfterPidTxt}${threadsTxt}${spacesAfterThreadsTxt}${ramTxt}`;
|
const headers = `${scriptTxt}${spacesAfterScriptTxt}${pidTxt}${spacesAfterPidTxt}${threadsTxt}${spacesAfterThreadsTxt}${ramTxt}`;
|
||||||
|
|
||||||
post(headers);
|
post(headers);
|
||||||
|
|
||||||
let currRunningScripts = s.runningScripts;
|
let currRunningScripts = s.runningScripts;
|
||||||
// Iterate through scripts on current server
|
// Iterate through scripts on current server
|
||||||
for (let i = 0; i < currRunningScripts.length; i++) {
|
for (let i = 0; i < currRunningScripts.length; i++) {
|
||||||
let script = currRunningScripts[i];
|
let script = currRunningScripts[i];
|
||||||
|
|
||||||
// Calculate name padding
|
// Calculate name padding
|
||||||
const numSpacesScript = Math.max(0, scriptWidth - script.filename.length);
|
const numSpacesScript = Math.max(0, scriptWidth - script.filename.length);
|
||||||
const spacesScript = " ".repeat(numSpacesScript);
|
const spacesScript = " ".repeat(numSpacesScript);
|
||||||
|
|
||||||
// Calculate PID padding
|
// Calculate PID padding
|
||||||
const numSpacesPid = Math.max(0, pidWidth - (script.pid + "").length);
|
const numSpacesPid = Math.max(0, pidWidth - (script.pid + "").length);
|
||||||
const spacesPid = " ".repeat(numSpacesPid);
|
const spacesPid = " ".repeat(numSpacesPid);
|
||||||
|
|
||||||
// Calculate thread padding
|
// Calculate thread padding
|
||||||
const numSpacesThread = Math.max(0, threadsWidth - (script.threads + "").length);
|
const numSpacesThread = Math.max(0, threadsWidth - (script.threads + "").length);
|
||||||
const spacesThread = " ".repeat(numSpacesThread);
|
const spacesThread = " ".repeat(numSpacesThread);
|
||||||
|
|
||||||
// Calculate and transform RAM usage
|
// Calculate and transform RAM usage
|
||||||
const ramUsage = numeralWrapper.formatRAM(getRamUsageFromRunningScript(script) * script.threads);
|
const ramUsage = numeralWrapper.formatRAM(getRamUsageFromRunningScript(script) * script.threads);
|
||||||
|
|
||||||
const entry = [
|
const entry = [
|
||||||
script.filename,
|
script.filename,
|
||||||
spacesScript,
|
spacesScript,
|
||||||
script.pid,
|
script.pid,
|
||||||
@@ -1508,9 +1545,9 @@ let Terminal = {
|
|||||||
spacesThread,
|
spacesThread,
|
||||||
ramUsage
|
ramUsage
|
||||||
].join("");
|
].join("");
|
||||||
post(entry);
|
post(entry);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "unalias": {
|
case "unalias": {
|
||||||
if (commandArray.length !== 2) {
|
if (commandArray.length !== 2) {
|
||||||
@@ -1555,10 +1592,10 @@ let Terminal = {
|
|||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
postError(`Command ${commandArray[0]} not found`);
|
postError(`Command ${commandArray[0]} not found`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
connectToServer: function(ip) {
|
connectToServer: function(ip) {
|
||||||
var serv = getServer(ip);
|
var serv = getServer(ip);
|
||||||
@@ -1783,12 +1820,13 @@ let Terminal = {
|
|||||||
const script = Terminal.getScript(filename);
|
const script = Terminal.getScript(filename);
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
let code = ""
|
let code = ""
|
||||||
if(filename.endsWith(".ns")) {
|
if(filename.endsWith(".ns") || filename.endsWith(".js")) {
|
||||||
code = `export async function main(ns) {
|
code = `export async function main(ns) {
|
||||||
|
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
Engine.loadScriptEditorContent(filepath, code);
|
Engine.loadScriptEditorContent(filepath, code);
|
||||||
|
getCurrentEditor().setCursor({row: 1, column: 4});
|
||||||
} else {
|
} else {
|
||||||
Engine.loadScriptEditorContent(filepath, script.code);
|
Engine.loadScriptEditorContent(filepath, script.code);
|
||||||
}
|
}
|
||||||
@@ -2003,24 +2041,24 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// First called when the "run [program]" command is called. Checks to see if you
|
// First called when the "run [program]" command is called. Checks to see if you
|
||||||
// have the executable and, if you do, calls the executeProgram() function
|
// have the executable and, if you do, calls the executeProgram() function
|
||||||
runProgram: function(commandArray) {
|
runProgram: function(commandArray) {
|
||||||
if (commandArray.length < 2) { return; }
|
if (commandArray.length < 2) { return; }
|
||||||
|
|
||||||
// Check if you have the program on your computer. If you do, execute it, otherwise
|
// Check if you have the program on your computer. If you do, execute it, otherwise
|
||||||
// display an error message
|
// display an error message
|
||||||
const programName = commandArray[1];
|
const programName = commandArray[1];
|
||||||
|
|
||||||
if (Player.hasProgram(programName)) {
|
if (Player.hasProgram(programName)) {
|
||||||
Terminal.executeProgram(commandArray);
|
Terminal.executeProgram(commandArray);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)");
|
post("ERROR: No such executable on home computer (Only programs that exist on your home computer can be run)");
|
||||||
},
|
},
|
||||||
|
|
||||||
// Contains the implementations of all possible programs
|
// Contains the implementations of all possible programs
|
||||||
executeProgram: function(commandArray) {
|
executeProgram: function(commandArray) {
|
||||||
if (commandArray.length < 2) { return; }
|
if (commandArray.length < 2) { return; }
|
||||||
|
|
||||||
var s = Player.getCurrentServer();
|
var s = Player.getCurrentServer();
|
||||||
@@ -2173,7 +2211,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
programHandlers[programName](s, splitArgs);
|
programHandlers[programName](s, splitArgs);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a filename, returns that file's full path. This takes into account
|
* Given a filename, returns that file's full path. This takes into account
|
||||||
@@ -2271,13 +2309,13 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
runScript: function(commandArray) {
|
runScript: function(commandArray) {
|
||||||
if (commandArray.length < 2) {
|
if (commandArray.length < 2) {
|
||||||
dialogBoxCreate(`Bug encountered with Terminal.runScript(). Command array has a length of less than 2: ${commandArray}`);
|
dialogBoxCreate(`Bug encountered with Terminal.runScript(). Command array has a length of less than 2: ${commandArray}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = Player.getCurrentServer();
|
const server = Player.getCurrentServer();
|
||||||
|
|
||||||
let numThreads = 1;
|
let numThreads = 1;
|
||||||
const args = [];
|
const args = [];
|
||||||
@@ -2307,38 +2345,38 @@ let Terminal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the script exists and if it does run it
|
// Check if the script exists and if it does run it
|
||||||
for (var i = 0; i < server.scripts.length; i++) {
|
for (var i = 0; i < server.scripts.length; i++) {
|
||||||
if (server.scripts[i].filename === scriptName) {
|
if (server.scripts[i].filename === scriptName) {
|
||||||
// Check for admin rights and that there is enough RAM availble to run
|
// Check for admin rights and that there is enough RAM availble to run
|
||||||
var script = server.scripts[i];
|
var script = server.scripts[i];
|
||||||
var ramUsage = script.ramUsage * numThreads;
|
var ramUsage = script.ramUsage * numThreads;
|
||||||
var ramAvailable = server.maxRam - server.ramUsed;
|
var ramAvailable = server.maxRam - server.ramUsed;
|
||||||
|
|
||||||
if (server.hasAdminRights == false) {
|
if (server.hasAdminRights == false) {
|
||||||
post("Need root access to run script");
|
post("Need root access to run script");
|
||||||
return;
|
return;
|
||||||
} else if (ramUsage > ramAvailable){
|
} else if (ramUsage > ramAvailable){
|
||||||
post("This machine does not have enough RAM to run this script with " +
|
post("This machine does not have enough RAM to run this script with " +
|
||||||
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
|
numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Able to run script
|
// Able to run script
|
||||||
var runningScriptObj = new RunningScript(script, args);
|
var runningScriptObj = new RunningScript(script, args);
|
||||||
runningScriptObj.threads = numThreads;
|
runningScriptObj.threads = numThreads;
|
||||||
|
|
||||||
if (startWorkerScript(runningScriptObj, server)) {
|
if (startWorkerScript(runningScriptObj, server)) {
|
||||||
post("Running script with " + numThreads + " thread(s) and args: " + arrayToString(args) + ".");
|
post(`Running script with ${numThreads} thread(s), pid ${runningScriptObj.pid} and args: ${arrayToString(args)}.`);
|
||||||
} else {
|
} else {
|
||||||
postError(`Failed to start script`);
|
postError(`Failed to start script`);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post("ERROR: No such script");
|
post("ERROR: No such script");
|
||||||
},
|
},
|
||||||
|
|
||||||
runContract: async function(contractName) {
|
runContract: async function(contractName) {
|
||||||
// There's already an opened contract
|
// There's already an opened contract
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const TerminalHelpText: string =
|
|||||||
"Type 'help name' to learn more about the command 'name'<br><br>" +
|
"Type 'help name' to learn more about the command 'name'<br><br>" +
|
||||||
'alias [-g] [name="value"] Create or display Terminal aliases<br>' +
|
'alias [-g] [name="value"] Create or display Terminal aliases<br>' +
|
||||||
"analyze Get information about the current machine <br>" +
|
"analyze Get information about the current machine <br>" +
|
||||||
|
'backdoor Install a backdoor on the current machine <br>' +
|
||||||
"buy [-l/program] Purchase a program through the Dark Web<br>" +
|
"buy [-l/program] Purchase a program through the Dark Web<br>" +
|
||||||
"cat [file] Display a .msg, .lit, or .txt file<br>" +
|
"cat [file] Display a .msg, .lit, or .txt file<br>" +
|
||||||
"cd [dir] Change to a new directory<br>" +
|
"cd [dir] Change to a new directory<br>" +
|
||||||
@@ -65,11 +66,14 @@ export const HelpTexts: IMap<string> = {
|
|||||||
"server details such as the hostname, whether the player has root access, what ports are opened/closed, and also " +
|
"server details such as the hostname, whether the player has root access, what ports are opened/closed, and also " +
|
||||||
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is " +
|
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is " +
|
||||||
"available on the server, etc.",
|
"available on the server, etc.",
|
||||||
|
backdoor: "backdoor<br>" +
|
||||||
|
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.<br>" +
|
||||||
|
"Requires root access to run.<br>",
|
||||||
buy: "buy [-l / program]<br>" +
|
buy: "buy [-l / program]<br>" +
|
||||||
"Purchase a program through the Dark Web. Requires a TOR router to use.<br><br>" +
|
"Purchase a program through the Dark Web. Requires a TOR router to use.<br><br>" +
|
||||||
"If this command is ran with the '-l' flag, it will display a list of all programs that can be bought through the " +
|
"If this command is ran with the '-l' flag, it will display a list of all programs that can be bought through the " +
|
||||||
"dark web to the Terminal, as well as their costs.<br><br>" +
|
"dark web to the Terminal, as well as their costs.<br><br>" +
|
||||||
"Otherwise, the name of the program must be passed in as a parameter. This is name is NOT case-sensitive.",
|
"Otherwise, the name of the program must be passed in as a parameter. This name is NOT case-sensitive.",
|
||||||
cat: "cat [file]<br>" +
|
cat: "cat [file]<br>" +
|
||||||
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:<br><br>" +
|
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:<br><br>" +
|
||||||
"cat j1.msg<br>" +
|
"cat j1.msg<br>" +
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { AllServers } from "../Server/AllServers";
|
|||||||
const commands = [
|
const commands = [
|
||||||
"alias",
|
"alias",
|
||||||
"analyze",
|
"analyze",
|
||||||
|
"backdoor",
|
||||||
"cat",
|
"cat",
|
||||||
"cd",
|
"cd",
|
||||||
"check",
|
"check",
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 2.5,
|
difficulty: 2.5,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const len: number = getRandomInt(1, 25);
|
const len: number = getRandomInt(3, 25);
|
||||||
const arr: number[] = [];
|
const arr: number[] = [];
|
||||||
arr.length = len;
|
arr.length = len;
|
||||||
for (let i: number = 0; i < arr.length; ++i) {
|
for (let i: number = 0; i < arr.length; ++i) {
|
||||||
@@ -291,7 +291,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
difficulty: 3,
|
difficulty: 3,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const intervals: number[][] = [];
|
const intervals: number[][] = [];
|
||||||
const numIntervals: number = getRandomInt(1, 20);
|
const numIntervals: number = getRandomInt(3, 20);
|
||||||
for (let i: number = 0; i < numIntervals; ++i) {
|
for (let i: number = 0; i < numIntervals; ++i) {
|
||||||
const start: number = getRandomInt(1, 25);
|
const start: number = getRandomInt(1, 25);
|
||||||
const end: number = start + getRandomInt(1, 10);
|
const end: number = start + getRandomInt(1, 10);
|
||||||
@@ -403,7 +403,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 1,
|
difficulty: 1,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const len: number = getRandomInt(1, 50);
|
const len: number = getRandomInt(3, 50);
|
||||||
const arr: number[] = [];
|
const arr: number[] = [];
|
||||||
arr.length = len;
|
arr.length = len;
|
||||||
for (let i: number = 0; i < len; ++i) {
|
for (let i: number = 0; i < len; ++i) {
|
||||||
@@ -439,7 +439,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 2,
|
difficulty: 2,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const len: number = getRandomInt(1, 50);
|
const len: number = getRandomInt(3, 50);
|
||||||
const arr: number[] = [];
|
const arr: number[] = [];
|
||||||
arr.length = len;
|
arr.length = len;
|
||||||
for (let i: number = 0; i < len; ++i) {
|
for (let i: number = 0; i < len; ++i) {
|
||||||
@@ -473,7 +473,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 5,
|
difficulty: 5,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const len: number = getRandomInt(1, 50);
|
const len: number = getRandomInt(3, 50);
|
||||||
const arr: number[] = [];
|
const arr: number[] = [];
|
||||||
arr.length = len;
|
arr.length = len;
|
||||||
for (let i: number = 0; i < len; ++i) {
|
for (let i: number = 0; i < len; ++i) {
|
||||||
@@ -518,7 +518,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
difficulty: 8,
|
difficulty: 8,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const k: number = getRandomInt(2, 10);
|
const k: number = getRandomInt(2, 10);
|
||||||
const len: number = getRandomInt(1, 50);
|
const len: number = getRandomInt(3, 50);
|
||||||
const prices: number[] = [];
|
const prices: number[] = [];
|
||||||
prices.length = len;
|
prices.length = len;
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
@@ -602,7 +602,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
difficulty: 5,
|
difficulty: 5,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const triangle: number[][] = [];
|
const triangle: number[][] = [];
|
||||||
const levels: number = getRandomInt(1, 12);
|
const levels: number = getRandomInt(3, 12);
|
||||||
triangle.length = levels;
|
triangle.length = levels;
|
||||||
|
|
||||||
for (let row = 0; row < levels; ++row) {
|
for (let row = 0; row < levels; ++row) {
|
||||||
@@ -645,8 +645,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 3,
|
difficulty: 3,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const numRows: number = getRandomInt(1, 14);
|
const numRows: number = getRandomInt(2, 14);
|
||||||
const numColumns: number = getRandomInt(1, 14);
|
const numColumns: number = getRandomInt(2, 14);
|
||||||
|
|
||||||
return [numRows, numColumns];
|
return [numRows, numColumns];
|
||||||
},
|
},
|
||||||
@@ -687,8 +687,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 5,
|
difficulty: 5,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const numRows: number = getRandomInt(1, 12);
|
const numRows: number = getRandomInt(2, 12);
|
||||||
const numColumns: number = getRandomInt(1, 12);
|
const numColumns: number = getRandomInt(2, 12);
|
||||||
|
|
||||||
const grid: number[][] = [];
|
const grid: number[][] = [];
|
||||||
grid.length = numRows;
|
grid.length = numRows;
|
||||||
@@ -754,7 +754,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 10,
|
difficulty: 10,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const len: number = getRandomInt(2, 20);
|
const len: number = getRandomInt(6, 20);
|
||||||
let chars: string[] = [];
|
let chars: string[] = [];
|
||||||
chars.length = len;
|
chars.length = len;
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ import {
|
|||||||
processStockPrices,
|
processStockPrices,
|
||||||
displayStockMarketContent
|
displayStockMarketContent
|
||||||
} from "./StockMarket/StockMarket";
|
} from "./StockMarket/StockMarket";
|
||||||
|
import { displayMilestonesContent } from "./Milestones/MilestoneHelpers";
|
||||||
import { Terminal, postNetburnerText } from "./Terminal";
|
import { Terminal, postNetburnerText } from "./Terminal";
|
||||||
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
||||||
import {
|
import {
|
||||||
@@ -216,6 +217,7 @@ const Engine = {
|
|||||||
factionsContent: null,
|
factionsContent: null,
|
||||||
factionContent: null,
|
factionContent: null,
|
||||||
augmentationsContent: null,
|
augmentationsContent: null,
|
||||||
|
milestonesContent: null,
|
||||||
tutorialContent: null,
|
tutorialContent: null,
|
||||||
infiltrationContent: null,
|
infiltrationContent: null,
|
||||||
stockMarketContent: null,
|
stockMarketContent: null,
|
||||||
@@ -311,6 +313,14 @@ const Engine = {
|
|||||||
MainMenuLinks.Augmentations.classList.add("active");
|
MainMenuLinks.Augmentations.classList.add("active");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadMilestonesContent: function() {
|
||||||
|
Engine.hideAllContent();
|
||||||
|
Engine.Display.milestonesContent.style.display = "block";
|
||||||
|
routing.navigateTo(Page.Milestones);
|
||||||
|
displayMilestonesContent();
|
||||||
|
MainMenuLinks.Milestones.classList.add("active");
|
||||||
|
},
|
||||||
|
|
||||||
loadTutorialContent: function() {
|
loadTutorialContent: function() {
|
||||||
Engine.hideAllContent();
|
Engine.hideAllContent();
|
||||||
Engine.Display.tutorialContent.style.display = "block";
|
Engine.Display.tutorialContent.style.display = "block";
|
||||||
@@ -496,6 +506,7 @@ const Engine = {
|
|||||||
Engine.Display.augmentationsContent.style.display = "none";
|
Engine.Display.augmentationsContent.style.display = "none";
|
||||||
ReactDOM.unmountComponentAtNode(Engine.Display.augmentationsContent);
|
ReactDOM.unmountComponentAtNode(Engine.Display.augmentationsContent);
|
||||||
|
|
||||||
|
Engine.Display.milestonesContent.style.display = "none";
|
||||||
Engine.Display.tutorialContent.style.display = "none";
|
Engine.Display.tutorialContent.style.display = "none";
|
||||||
|
|
||||||
Engine.Display.locationContent.style.display = "none";
|
Engine.Display.locationContent.style.display = "none";
|
||||||
@@ -550,6 +561,7 @@ const Engine = {
|
|||||||
MainMenuLinks.Bladeburner.classList.remove("active");
|
MainMenuLinks.Bladeburner.classList.remove("active");
|
||||||
MainMenuLinks.Corporation.classList.remove("active");
|
MainMenuLinks.Corporation.classList.remove("active");
|
||||||
MainMenuLinks.Gang.classList.remove("active");
|
MainMenuLinks.Gang.classList.remove("active");
|
||||||
|
MainMenuLinks.Milestones.classList.remove("active");
|
||||||
MainMenuLinks.Tutorial.classList.remove("active");
|
MainMenuLinks.Tutorial.classList.remove("active");
|
||||||
MainMenuLinks.Options.classList.remove("active");
|
MainMenuLinks.Options.classList.remove("active");
|
||||||
MainMenuLinks.DevMenu.classList.remove("active");
|
MainMenuLinks.DevMenu.classList.remove("active");
|
||||||
@@ -777,7 +789,7 @@ const Engine = {
|
|||||||
createProgramNotifications: 10,
|
createProgramNotifications: 10,
|
||||||
augmentationsNotifications: 10,
|
augmentationsNotifications: 10,
|
||||||
checkFactionInvitations: 100,
|
checkFactionInvitations: 100,
|
||||||
passiveFactionGrowth: 600,
|
passiveFactionGrowth: 5,
|
||||||
messages: 150,
|
messages: 150,
|
||||||
mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
|
mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
|
||||||
contractGeneration: 3000, // Generate Coding Contracts
|
contractGeneration: 3000, // Generate Coding Contracts
|
||||||
@@ -911,9 +923,9 @@ const Engine = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Engine.Counters.passiveFactionGrowth <= 0) {
|
if (Engine.Counters.passiveFactionGrowth <= 0) {
|
||||||
var adjustedCycles = Math.floor((600 - Engine.Counters.passiveFactionGrowth));
|
var adjustedCycles = Math.floor((5 - Engine.Counters.passiveFactionGrowth));
|
||||||
processPassiveFactionRepGain(adjustedCycles);
|
processPassiveFactionRepGain(adjustedCycles);
|
||||||
Engine.Counters.passiveFactionGrowth = 600;
|
Engine.Counters.passiveFactionGrowth = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Engine.Counters.messages <= 0) {
|
if (Engine.Counters.messages <= 0) {
|
||||||
@@ -1055,6 +1067,7 @@ const Engine = {
|
|||||||
const bladeburner = document.getElementById("bladeburner-tab");
|
const bladeburner = document.getElementById("bladeburner-tab");
|
||||||
const corp = document.getElementById("corporation-tab");
|
const corp = document.getElementById("corporation-tab");
|
||||||
const gang = document.getElementById("gang-tab");
|
const gang = document.getElementById("gang-tab");
|
||||||
|
const milestones = document.getElementById("milestones-tab");
|
||||||
const tutorial = document.getElementById("tutorial-tab");
|
const tutorial = document.getElementById("tutorial-tab");
|
||||||
const options = document.getElementById("options-tab");
|
const options = document.getElementById("options-tab");
|
||||||
const dev = document.getElementById("dev-tab");
|
const dev = document.getElementById("dev-tab");
|
||||||
@@ -1097,7 +1110,7 @@ const Engine = {
|
|||||||
// Hacknet Nodes offline progress
|
// Hacknet Nodes offline progress
|
||||||
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
||||||
const hacknetProdInfo = hasHacknetServers() ?
|
const hacknetProdInfo = hasHacknetServers() ?
|
||||||
Hashes(offlineProductionFromHacknetNodes):
|
<>{Hashes(offlineProductionFromHacknetNodes)} hashes</>:
|
||||||
Money(offlineProductionFromHacknetNodes);
|
Money(offlineProductionFromHacknetNodes);
|
||||||
|
|
||||||
// Passive faction rep gain offline
|
// Passive faction rep gain offline
|
||||||
@@ -1151,11 +1164,12 @@ const Engine = {
|
|||||||
removeLoadingScreen();
|
removeLoadingScreen();
|
||||||
const timeOfflineString = convertTimeMsToTimeElapsedString(time);
|
const timeOfflineString = convertTimeMsToTimeElapsedString(time);
|
||||||
dialogBoxCreate(<>
|
dialogBoxCreate(<>
|
||||||
Offline for {timeOfflineString}. While you were offline, your scripts generated {Money(offlineProductionFromScripts)} and your Hacknet Nodes generated {hacknetProdInfo} hashes.
|
Offline for {timeOfflineString}. While you were offline, your scripts generated {Money(offlineProductionFromScripts)} and your Hacknet Nodes generated {hacknetProdInfo}.
|
||||||
</>);
|
</>);
|
||||||
// Close main menu accordions for loaded game
|
// Close main menu accordions for loaded game
|
||||||
var visibleMenuTabs = [terminal, createScript, activeScripts, stats,
|
var visibleMenuTabs = [terminal, createScript, activeScripts, stats,
|
||||||
hacknetnodes, city, tutorial, options, dev];
|
hacknetnodes, city, milestones, tutorial,
|
||||||
|
options, dev];
|
||||||
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
|
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
|
||||||
else {factions.style.display = "none";}
|
else {factions.style.display = "none";}
|
||||||
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
|
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
|
||||||
@@ -1214,7 +1228,7 @@ const Engine = {
|
|||||||
|
|
||||||
Engine.openMainMenuHeader(
|
Engine.openMainMenuHeader(
|
||||||
[terminal, createScript, activeScripts, stats,
|
[terminal, createScript, activeScripts, stats,
|
||||||
hacknetnodes, city,
|
hacknetnodes, city, milestones,
|
||||||
tutorial, options]
|
tutorial, options]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1257,6 +1271,8 @@ const Engine = {
|
|||||||
Engine.Display.augmentationsContent = document.getElementById("augmentations-container");
|
Engine.Display.augmentationsContent = document.getElementById("augmentations-container");
|
||||||
Engine.Display.augmentationsContent.style.display = "none";
|
Engine.Display.augmentationsContent.style.display = "none";
|
||||||
|
|
||||||
|
Engine.Display.milestonesContent = document.getElementById("milestones-container");
|
||||||
|
Engine.Display.milestonesContent.style.display = "none";
|
||||||
|
|
||||||
Engine.Display.tutorialContent = document.getElementById("tutorial-container");
|
Engine.Display.tutorialContent = document.getElementById("tutorial-container");
|
||||||
Engine.Display.tutorialContent.style.display = "none";
|
Engine.Display.tutorialContent.style.display = "none";
|
||||||
@@ -1398,6 +1414,11 @@ const Engine = {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MainMenuLinks.Milestones.addEventListener("click", function() {
|
||||||
|
Engine.loadMilestonesContent();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
MainMenuLinks.Tutorial.addEventListener("click", function() {
|
MainMenuLinks.Tutorial.addEventListener("click", function() {
|
||||||
Engine.loadTutorialContent();
|
Engine.loadTutorialContent();
|
||||||
return false;
|
return false;
|
||||||
@@ -1480,6 +1501,7 @@ const Engine = {
|
|||||||
document.getElementById("active-scripts-menu-link").removeAttribute("class");
|
document.getElementById("active-scripts-menu-link").removeAttribute("class");
|
||||||
document.getElementById("hacknet-nodes-menu-link").removeAttribute("class");
|
document.getElementById("hacknet-nodes-menu-link").removeAttribute("class");
|
||||||
document.getElementById("city-menu-link").removeAttribute("class");
|
document.getElementById("city-menu-link").removeAttribute("class");
|
||||||
|
document.getElementById("milestones-menu-link").removeAttribute("class");
|
||||||
document.getElementById("tutorial-menu-link").removeAttribute("class");
|
document.getElementById("tutorial-menu-link").removeAttribute("class");
|
||||||
|
|
||||||
// Copy Save Data to Clipboard
|
// Copy Save Data to Clipboard
|
||||||
|
|||||||
@@ -29,3 +29,5 @@ import "../css/resleeving.scss";
|
|||||||
import "../css/treant.css";
|
import "../css/treant.css";
|
||||||
import "../css/grid.min.css";
|
import "../css/grid.min.css";
|
||||||
import "../css/dev-menu.css";
|
import "../css/dev-menu.css";
|
||||||
|
import "../css/casino.scss";
|
||||||
|
import "../css/milestones.scss";
|
||||||
|
|||||||
@@ -102,9 +102,12 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<li id="help-menu-header-li">
|
<li id="help-menu-header-li">
|
||||||
<button id="help-menu-header" class="mainmenu-accordion-header"> Help </button>
|
<button id="help-menu-header" class="mainmenu-accordion-header"> Help </button>
|
||||||
</li>
|
</li>
|
||||||
<li id="tutorial-tab" class="mainmenu-accordion-panel">
|
<li id="milestones-tab" class="mainmenu-accordion-panel">
|
||||||
<button id="tutorial-menu-link"> Tutorial </button>
|
<button id="milestones-menu-link"> Milestones </button>
|
||||||
</li>
|
</li>
|
||||||
|
<li id="tutorial-tab" class="mainmenu-accordion-panel">
|
||||||
|
<button id="tutorial-menu-link"> Tutorial </button>
|
||||||
|
</li>
|
||||||
<li id="options-tab" class="mainmenu-accordion-panel">
|
<li id="options-tab" class="mainmenu-accordion-panel">
|
||||||
<button id="options-menu-link"> Options </button>
|
<button id="options-menu-link"> Options </button>
|
||||||
</li>
|
</li>
|
||||||
@@ -179,7 +182,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<table id="terminal">
|
<table id="terminal">
|
||||||
<tr id="terminal-input">
|
<tr id="terminal-input">
|
||||||
<td id="terminal-input-td" tabindex="2">$
|
<td id="terminal-input-td" tabindex="2">$
|
||||||
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" />
|
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -228,6 +231,10 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<!-- Augmentations -->
|
<!-- Augmentations -->
|
||||||
<div id="augmentations-container" class="generic-menupage-container"></div>
|
<div id="augmentations-container" class="generic-menupage-container"></div>
|
||||||
|
|
||||||
|
<!-- Milestones content -->
|
||||||
|
<div id="milestones-container" class="generic-menupage-container">
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Tutorial content -->
|
<!-- Tutorial content -->
|
||||||
<div id="tutorial-container" class="generic-menupage-container">
|
<div id="tutorial-container" class="generic-menupage-container">
|
||||||
<h1> Tutorial (AKA Links to Documentation) </h1>
|
<h1> Tutorial (AKA Links to Documentation) </h1>
|
||||||
@@ -394,7 +401,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
|
|
||||||
<!-- Status text -->
|
<!-- Status text -->
|
||||||
<div id="status-text-container">
|
<div id="status-text-container">
|
||||||
<p id="status-text"> </p>
|
<p id="status-text"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Game Options -->
|
<!-- Game Options -->
|
||||||
@@ -534,6 +541,16 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
|||||||
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableASCIIArt" id="settingsDisableASCIIArt">
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- Disable text effects such as corruption. -->
|
||||||
|
<fieldset>
|
||||||
|
<label for="settingsDisableTextEffects" class="tooltip">Disable Text Effects:
|
||||||
|
<span class="tooltiptexthigh">
|
||||||
|
If this is set, text effects will not be displayed. This can help if text is difficult to read in certain areas.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input class="optionCheckbox" type="checkbox" name="settingsDisableTextEffects" id="settingsDisableTextEffects">
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<!-- Locale for displaying numbers -->
|
<!-- Locale for displaying numbers -->
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="settingsLocale" class="tooltip">Locale:
|
<label for="settingsLocale" class="tooltip">Locale:
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
|
|||||||
const scriptRef = workerScript.scriptRef;
|
const scriptRef = workerScript.scriptRef;
|
||||||
|
|
||||||
const logClickHandler = logBoxCreate.bind(null, scriptRef);
|
const logClickHandler = logBoxCreate.bind(null, scriptRef);
|
||||||
const killScript = killWorkerScript.bind(null, scriptRef, scriptRef.server);
|
const killScript = killWorkerScript.bind(null, scriptRef as any, scriptRef.server);
|
||||||
|
|
||||||
function killScriptClickHandler() {
|
function killScriptClickHandler() {
|
||||||
killScript();
|
killScript();
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
function Hacknet(): React.ReactElement {
|
function Hacknet(): React.ReactElement {
|
||||||
// Can't import HacknetHelpers for some reason.
|
// Can't import HacknetHelpers for some reason.
|
||||||
if(!(p.bitNodeN === 9 || SourceFileFlags[9] > 0)) {
|
if(!(p.bitNodeN === 9 || SourceFileFlags[9] > 0)) {
|
||||||
return <><span>{`Hacknet Nodes owned: ${p.hacknetNodes.length}</span>`}</span><br /></>
|
return <><span>{`Hacknet Nodes owned: ${p.hacknetNodes.length}`}</span><br /></>
|
||||||
} else {
|
} else {
|
||||||
return <><span>{`Hacknet Servers owned: ${p.hacknetNodes.length} / ${HacknetServerConstants.MaxServers}`}</span><br /></>
|
return <><span>{`Hacknet Servers owned: ${p.hacknetNodes.length} / ${HacknetServerConstants.MaxServers}`}</span><br /></>
|
||||||
}
|
}
|
||||||
@@ -51,6 +51,7 @@ export function CharacterInfo(p: IPlayer): React.ReactElement {
|
|||||||
if (src.bladeburner) { parts.push([`Bladeburner:`, Money(src.bladeburner)]) };
|
if (src.bladeburner) { parts.push([`Bladeburner:`, Money(src.bladeburner)]) };
|
||||||
if (src.codingcontract) { parts.push([`Coding Contracts:`, Money(src.codingcontract)]) };
|
if (src.codingcontract) { parts.push([`Coding Contracts:`, Money(src.codingcontract)]) };
|
||||||
if (src.work) { parts.push([`Company Work:`, Money(src.work)]) };
|
if (src.work) { parts.push([`Company Work:`, Money(src.work)]) };
|
||||||
|
if (src.class) { parts.push([`Class:`, Money(src.class)]) };
|
||||||
if (src.corporation) { parts.push([`Corporation:`, Money(src.corporation)]) };
|
if (src.corporation) { parts.push([`Corporation:`, Money(src.corporation)]) };
|
||||||
if (src.crime) { parts.push([`Crimes:`, Money(src.crime)]) };
|
if (src.crime) { parts.push([`Crimes:`, Money(src.crime)]) };
|
||||||
if (src.gang) { parts.push([`Gang:`, Money(src.gang)]) };
|
if (src.gang) { parts.push([`Gang:`, Money(src.gang)]) };
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function toggleHeader(open: boolean, elems: HTMLElement[], links: HTMLElement[])
|
|||||||
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
|
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
|
||||||
} else {
|
} else {
|
||||||
elems[i].style.opacity = "0";
|
elems[i].style.opacity = "0";
|
||||||
elems[i].style.maxHeight = null;
|
elems[i].style.maxHeight = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,13 +35,13 @@ function toggleHeader(open: boolean, elems: HTMLElement[], links: HTMLElement[])
|
|||||||
links[i].style.pointerEvents = "auto";
|
links[i].style.pointerEvents = "auto";
|
||||||
} else {
|
} else {
|
||||||
links[i].style.opacity = "0";
|
links[i].style.opacity = "0";
|
||||||
links[i].style.maxHeight = null;
|
links[i].style.maxHeight = "";
|
||||||
links[i].style.pointerEvents = "none";
|
links[i].style.pointerEvents = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boolean {
|
export function initializeMainMenuHeaders(p: IPlayer, dev = false): boolean {
|
||||||
function safeGetElement(id: string): HTMLElement {
|
function safeGetElement(id: string): HTMLElement {
|
||||||
const elem: HTMLElement | null = document.getElementById(id);
|
const elem: HTMLElement | null = document.getElementById(id);
|
||||||
if (elem == null) {
|
if (elem == null) {
|
||||||
@@ -68,16 +68,16 @@ export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boole
|
|||||||
|
|
||||||
createProgram.style.display = p.firstProgramAvailable ? "list-item" : "none";
|
createProgram.style.display = p.firstProgramAvailable ? "list-item" : "none";
|
||||||
|
|
||||||
this.classList.toggle("opened");
|
(this as any).classList.toggle("opened");
|
||||||
|
|
||||||
const elems: HTMLElement[] = [terminal, createScript, activeScripts, createProgram];
|
const elems: HTMLElement[] = [terminal, createScript, activeScripts, createProgram];
|
||||||
const links: HTMLElement[] = [MainMenuLinks.Terminal!, MainMenuLinks.ScriptEditor!, MainMenuLinks.ActiveScripts!, MainMenuLinks.CreateProgram!];
|
const links: HTMLElement[] = [MainMenuLinks.Terminal!, MainMenuLinks.ScriptEditor!, MainMenuLinks.ActiveScripts!, MainMenuLinks.CreateProgram!];
|
||||||
if (terminal.style.maxHeight) {
|
if (terminal.style.maxHeight) {
|
||||||
toggleHeader(false, elems, links);
|
toggleHeader(false, elems, links);
|
||||||
createProgramNot!.style.display = "none";
|
createProgramNot.style.display = "none";
|
||||||
} else {
|
} else {
|
||||||
toggleHeader(true, elems, links);
|
toggleHeader(true, elems, links);
|
||||||
createProgramNot!.style.display = "block"
|
createProgramNot.style.display = "block"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boole
|
|||||||
|
|
||||||
sleeves.style.display = p.sleeves.length > 0 ? "list-item" : "none";
|
sleeves.style.display = p.sleeves.length > 0 ? "list-item" : "none";
|
||||||
|
|
||||||
this.classList.toggle("opened");
|
(this as any).classList.toggle("opened");
|
||||||
|
|
||||||
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes, sleeves];
|
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes, sleeves];
|
||||||
const links: HTMLElement[] = [MainMenuLinks.Stats!, MainMenuLinks.Factions!, MainMenuLinks.Augmentations!, MainMenuLinks.HacknetNodes!, MainMenuLinks.Sleeves!];
|
const links: HTMLElement[] = [MainMenuLinks.Stats!, MainMenuLinks.Factions!, MainMenuLinks.Augmentations!, MainMenuLinks.HacknetNodes!, MainMenuLinks.Sleeves!];
|
||||||
@@ -117,7 +117,7 @@ export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boole
|
|||||||
corporation.style.display = p.hasCorporation() ? "list-item" : "none";
|
corporation.style.display = p.hasCorporation() ? "list-item" : "none";
|
||||||
gang.style.display = p.inGang() ? "list-item" : "none";
|
gang.style.display = p.inGang() ? "list-item" : "none";
|
||||||
|
|
||||||
this.classList.toggle("opened");
|
(this as any).classList.toggle("opened");
|
||||||
|
|
||||||
const elems: HTMLElement[] = [city, travel, job, stockmarket, bladeburner, corporation, gang];
|
const elems: HTMLElement[] = [city, travel, job, stockmarket, bladeburner, corporation, gang];
|
||||||
const links: HTMLElement[] = [MainMenuLinks.City!, MainMenuLinks.Travel!, MainMenuLinks.Job!, MainMenuLinks.StockMarket!, MainMenuLinks.Bladeburner!, MainMenuLinks.Corporation!, MainMenuLinks.Gang!];
|
const links: HTMLElement[] = [MainMenuLinks.City!, MainMenuLinks.Travel!, MainMenuLinks.Job!, MainMenuLinks.StockMarket!, MainMenuLinks.Bladeburner!, MainMenuLinks.Corporation!, MainMenuLinks.Gang!];
|
||||||
@@ -129,13 +129,14 @@ export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
MainMenuHeaders.Help.onclick = function() {
|
MainMenuHeaders.Help.onclick = function() {
|
||||||
|
const milestones: HTMLElement = safeGetElement("milestones-tab");
|
||||||
const tutorial: HTMLElement = safeGetElement("tutorial-tab");
|
const tutorial: HTMLElement = safeGetElement("tutorial-tab");
|
||||||
const options: HTMLElement = safeGetElement("options-tab");
|
const options: HTMLElement = safeGetElement("options-tab");
|
||||||
|
|
||||||
this.classList.toggle("opened");
|
(this as any).classList.toggle("opened");
|
||||||
|
|
||||||
const elems: HTMLElement[] = [tutorial, options];
|
const elems: HTMLElement[] = [milestones, tutorial, options];
|
||||||
const links: HTMLElement[] = [MainMenuLinks.Tutorial!, MainMenuLinks.Options!];
|
const links: HTMLElement[] = [MainMenuLinks.Milestones!, MainMenuLinks.Tutorial!, MainMenuLinks.Options!];
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
elems.push(safeGetElement("dev-tab"));
|
elems.push(safeGetElement("dev-tab"));
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ interface IMainMenuLinks {
|
|||||||
Bladeburner: HTMLElement | null;
|
Bladeburner: HTMLElement | null;
|
||||||
Corporation: HTMLElement | null;
|
Corporation: HTMLElement | null;
|
||||||
Gang: HTMLElement | null;
|
Gang: HTMLElement | null;
|
||||||
|
Milestones: HTMLElement | null;
|
||||||
Tutorial: HTMLElement | null;
|
Tutorial: HTMLElement | null;
|
||||||
Options: HTMLElement | null;
|
Options: HTMLElement | null;
|
||||||
DevMenu: HTMLElement | null;
|
DevMenu: HTMLElement | null;
|
||||||
@@ -41,6 +42,7 @@ export const MainMenuLinks: IMainMenuLinks = {
|
|||||||
Bladeburner: null,
|
Bladeburner: null,
|
||||||
Corporation: null,
|
Corporation: null,
|
||||||
Gang: null,
|
Gang: null,
|
||||||
|
Milestones: null,
|
||||||
Tutorial: null,
|
Tutorial: null,
|
||||||
Options: null,
|
Options: null,
|
||||||
DevMenu: null,
|
DevMenu: null,
|
||||||
@@ -54,7 +56,7 @@ export function initializeMainMenuLinks(): boolean {
|
|||||||
throw new Error(`clearEventListeners() failed for element with id: ${id}`);
|
throw new Error(`clearEventListeners() failed for element with id: ${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return elem!;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
MainMenuLinks.Terminal = safeGetLink("terminal-menu-link");
|
MainMenuLinks.Terminal = safeGetLink("terminal-menu-link");
|
||||||
@@ -73,6 +75,7 @@ export function initializeMainMenuLinks(): boolean {
|
|||||||
MainMenuLinks.Bladeburner = safeGetLink("bladeburner-menu-link");
|
MainMenuLinks.Bladeburner = safeGetLink("bladeburner-menu-link");
|
||||||
MainMenuLinks.Corporation = safeGetLink("corporation-menu-link");
|
MainMenuLinks.Corporation = safeGetLink("corporation-menu-link");
|
||||||
MainMenuLinks.Gang = safeGetLink("gang-menu-link");
|
MainMenuLinks.Gang = safeGetLink("gang-menu-link");
|
||||||
|
MainMenuLinks.Milestones = safeGetLink("milestones-menu-link");
|
||||||
MainMenuLinks.Tutorial = safeGetLink("tutorial-menu-link");
|
MainMenuLinks.Tutorial = safeGetLink("tutorial-menu-link");
|
||||||
MainMenuLinks.Options = document.getElementById("options-menu-link"); // This click listener is already set, so don't clear it
|
MainMenuLinks.Options = document.getElementById("options-menu-link"); // This click listener is already set, so don't clear it
|
||||||
MainMenuLinks.DevMenu = safeGetLink("dev-menu-link");
|
MainMenuLinks.DevMenu = safeGetLink("dev-menu-link");
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class CharacterOverviewComponent extends Component {
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr id="character-hp-wrapper">
|
<tr id="character-hp-wrapper">
|
||||||
<td className="character-hp-cell">Hp:</td><td id="character-hp-text" className="character-hp-cell character-stat-cell">{Player.hp + " / " + Player.max_hp}</td>
|
<td className="character-hp-cell">Hp:</td><td id="character-hp-text" className="character-hp-cell character-stat-cell">{numeralWrapper.formatHp(Player.hp) + " / " + numeralWrapper.formatHp(Player.max_hp)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="character-money-wrapper">
|
<tr id="character-money-wrapper">
|
||||||
<td className="character-money-cell">Money: </td><td id="character-money-text" className="character-money-cell character-stat-cell">{numeralWrapper.formatMoney(Player.money.toNumber())}</td>
|
<td className="character-money-cell">Money: </td><td id="character-money-text" className="character-money-cell character-stat-cell">{numeralWrapper.formatMoney(Player.money.toNumber())}</td>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user