mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 14:28:36 +02:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c96c7e3d2e | ||
|
|
84a1d27b9a | ||
|
|
99c75baea0 | ||
|
|
371d41b7c3 | ||
|
|
02b085cc75 | ||
|
|
e38bfc70cf | ||
|
|
52a96b94f9 | ||
|
|
73b9cae203 | ||
|
|
30588a885b | ||
|
|
45c46ce2a0 | ||
|
|
58650c5895 | ||
|
|
09f621e342 | ||
|
|
762e7f127c | ||
|
|
d6ea9c55b1 | ||
|
|
34fa906013 | ||
|
|
80d197652d | ||
|
|
b5a8ed1d9d | ||
|
|
e047653ed7 | ||
|
|
f645d08a50 | ||
|
|
515f9e5d4b | ||
|
|
5e9143371a | ||
|
|
536b8360cf | ||
|
|
8b59260bd3 | ||
|
|
3bd05ea398 | ||
|
|
79a6c7eb7b | ||
|
|
1d302a0320 | ||
|
|
d35bac1ace | ||
|
|
e99ffcfe2b | ||
|
|
c1d4ced331 | ||
|
|
6b0e5416c4 | ||
|
|
745fb4fdf6 | ||
|
|
af816dbc7e | ||
|
|
89fa79c4de | ||
|
|
8819042c0f | ||
|
|
7417ff8a10 | ||
|
|
e6a4456d81 | ||
|
|
4603216aa0 | ||
|
|
3fddb3c9f2 | ||
|
|
fe6473f426 | ||
|
|
89a6bf175d | ||
|
|
6b114fab7d | ||
|
|
542b2d6b8a | ||
|
|
139ccd11ff | ||
|
|
38d915372f | ||
|
|
dda6235591 | ||
|
|
3d97f2d770 | ||
|
|
f60af97e74 | ||
|
|
db9c3193f7 | ||
|
|
c556408208 | ||
|
|
f6ffe5b5be | ||
|
|
cc056ceef4 | ||
|
|
cee716bbb0 | ||
|
|
737d9e027f | ||
|
|
63e467986e | ||
|
|
d3fc6a9d48 | ||
|
|
e245c2d3a7 | ||
|
|
3f1d4875e7 | ||
|
|
921a1517df | ||
|
|
c4e17c3fb3 | ||
|
|
2f673b0767 | ||
|
|
b7823f46e4 | ||
|
|
e2c8fed307 | ||
|
|
e436d7f3a0 | ||
|
|
a5a28db47f | ||
|
|
c66a8b5974 | ||
|
|
3c2a237140 | ||
|
|
0dbeac52ac | ||
|
|
6543e73f6f | ||
|
|
85aa67ac26 | ||
|
|
bf75cf80b8 | ||
|
|
a90575aea9 | ||
|
|
a0baab6f6c |
78
dist/vendor.bundle.js
vendored
78
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
18
doc/source/netscript/advancedfunctions/atExit.rst
Normal file
18
doc/source/netscript/advancedfunctions/atExit.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
atExit() Netscript Function
|
||||
============================
|
||||
|
||||
.. js:function:: atExit(f)
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:param function f: function to call when the script dies.
|
||||
|
||||
Runs when the script dies.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function onDeath() {
|
||||
console.log('I died!!!')
|
||||
}
|
||||
atExit(onDeath);
|
||||
36
doc/source/netscript/advancedfunctions/autocomplete.rst
Normal file
36
doc/source/netscript/advancedfunctions/autocomplete.rst
Normal file
@@ -0,0 +1,36 @@
|
||||
autocomplete() Netscript Function
|
||||
============================
|
||||
|
||||
.. warning:: This feature is not officially supported yet and the API might change.
|
||||
|
||||
.. js:function:: autocomplete(data, args)
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:param Object data: general data about the game you might want to autocomplete.
|
||||
:param string[] args: current arguments.
|
||||
|
||||
data is an object with the following properties::
|
||||
|
||||
{
|
||||
servers: list of all servers in the game.
|
||||
txts: list of all text files on the current server.
|
||||
scripts: list of all scripts on the current server.
|
||||
}
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
export function autocomplete(data, args) {
|
||||
return [...data.servers]; // This script autocompletes the list of servers.
|
||||
return [...data.servers, ...data.scripts]; // Autocomplete servers and scripts
|
||||
return ["low", "medium", "high"]; // Autocomplete 3 specific strings.
|
||||
}
|
||||
|
||||
Terminal:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
$ run demo.ns mega\t
|
||||
// results in
|
||||
$ run demo.ns megacorp
|
||||
15
doc/source/netscript/basicfunctions/alert.rst
Normal file
15
doc/source/netscript/basicfunctions/alert.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
alert() Netscript Function
|
||||
============================
|
||||
|
||||
.. js:function:: alert(message)
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:param string message: message to display
|
||||
|
||||
Spawns an alert box.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
alert("Reached $1b");
|
||||
17
doc/source/netscript/basicfunctions/toast.rst
Normal file
17
doc/source/netscript/basicfunctions/toast.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
toast() Netscript Function
|
||||
============================
|
||||
|
||||
.. js:function:: toast(message[, variant])
|
||||
|
||||
:RAM cost: 0 GB
|
||||
:param string message: message to display
|
||||
:param success|info|warning|error variant: color of the toast
|
||||
|
||||
Spawns a toast (those bottom left notifications).
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
toast("Reached $1b");
|
||||
toast("Failed to hack home", "error");
|
||||
@@ -10,3 +10,4 @@ they contain spoilers for the game.
|
||||
|
||||
getBitNodeMultipliers() <advancedfunctions/getBitNodeMultipliers>
|
||||
getServer() <advancedfunctions/getServer>
|
||||
autocomplete() <advancedfunctions/autocomplete>
|
||||
|
||||
@@ -43,6 +43,7 @@ The player has access to all of these functions while in BitNode-4. Completing B
|
||||
getFactionRep() <singularityfunctions/getFactionRep>
|
||||
getFactionFavor() <singularityfunctions/getFactionFavor>
|
||||
getFactionFavorGain() <singularityfunctions/getFactionFavorGain>
|
||||
upgradeHomeCores() <singularityfunctions/upgradeHomeCores>
|
||||
|
||||
.. toctree::
|
||||
:caption: Level 3 Functions
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
upgradeHomeRam() Netscript Function
|
||||
===================================
|
||||
|
||||
.. js:function:: upgradeHomeCores()
|
||||
|
||||
:RAM cost: 3 GB
|
||||
|
||||
If you are not in BitNode-4, then you must have Level 2 of Source-File 4 in order to use this function.
|
||||
|
||||
This function will upgrade amount of CORES on the player's home computer. The cost is the same as if you were to do it manually.
|
||||
|
||||
This function will return true if the player's home computer core count is successfully upgraded, and false otherwise.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
34801
package-lock.json
generated
34801
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
73
package.json
73
package.json
@@ -13,10 +13,9 @@
|
||||
"@emotion/react": "^11.4.1",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@monaco-editor/react": "^4.2.2",
|
||||
"@mui/icons-material": "^5.0.0-rc.1",
|
||||
"@mui/lab": "^5.0.0-alpha.46",
|
||||
"@mui/material": "^5.0.0-rc.1",
|
||||
"@mui/styles": "^5.0.0-rc.1",
|
||||
"@mui/icons-material": "^5.0.3",
|
||||
"@mui/material": "^5.0.3",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@types/escodegen": "^0.0.7",
|
||||
"@types/js-beautify": "^1.13.2",
|
||||
"@types/numeral": "0.0.25",
|
||||
@@ -25,46 +24,23 @@
|
||||
"@types/react-resizable": "^1.7.3",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"ajv": "^5.1.5",
|
||||
"ajv-keywords": "^2.0.0",
|
||||
"arg": "^5.0.0",
|
||||
"async": "^2.6.1",
|
||||
"autosize": "^4.0.2",
|
||||
"brace": "^0.11.1",
|
||||
"codemirror": "^5.58.2",
|
||||
"better-react-mathjax": "^1.0.3",
|
||||
"clsx": "^1.1.1",
|
||||
"decimal.js": "7.2.3",
|
||||
"enhanced-resolve": "^4.0.0",
|
||||
"escodegen": "^1.11.0",
|
||||
"escope": "^3.6.0",
|
||||
"file-saver": "^1.3.8",
|
||||
"interpret": "^1.0.0",
|
||||
"jquery": "^3.5.0",
|
||||
"jshint": "^2.10.2",
|
||||
"json-loader": "^0.5.4",
|
||||
"jsplumb": "^2.6.8",
|
||||
"jszip": "^3.7.0",
|
||||
"loader-runner": "^2.3.0",
|
||||
"loader-utils": "^1.1.0",
|
||||
"material-ui-color": "^1.2.0",
|
||||
"mathjax-full": "^3.2.0",
|
||||
"mathjax-react": "^1.0.6",
|
||||
"memory-fs": "~0.4.1",
|
||||
"monaco-editor": "^0.27.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"normalize.css": "^8.0.0",
|
||||
"notistack": "^2.0.2",
|
||||
"numeral": "2.0.6",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-draggable": "^4.4.4",
|
||||
"react-modal": "^3.12.1",
|
||||
"react-resizable": "^3.0.4",
|
||||
"sprintf-js": "^1.1.1",
|
||||
"tapable": "^1.0.0",
|
||||
"treant-js": "^1.0.1",
|
||||
"unused-webpack-plugin": "^2.4.0",
|
||||
"uuid": "^3.2.1",
|
||||
"w3c-blob": "0.0.1",
|
||||
"webpack-deadcode-plugin": "^0.1.15"
|
||||
"sprintf-js": "^1.1.1"
|
||||
},
|
||||
"description": "A cyberpunk-themed incremental game",
|
||||
"devDependencies": {
|
||||
@@ -75,65 +51,33 @@
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
|
||||
"@testing-library/cypress": "^8.0.1",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/node": "^16.9.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"babel-jest": "^27.0.6",
|
||||
"babel-loader": "^8.0.5",
|
||||
"beautify-lint": "^1.0.3",
|
||||
"benchmark": "^2.1.1",
|
||||
"bundle-loader": "~0.5.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"cypress": "^8.3.1",
|
||||
"electron": "^14.0.1",
|
||||
"electron-packager": "^15.4.0",
|
||||
"es6-promise-polyfill": "^1.1.1",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"file-loader": "^1.1.11",
|
||||
"fork-ts-checker-webpack-plugin": "^6.3.3",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"http-server": "^13.0.1",
|
||||
"i18n-webpack-plugin": "^1.0.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"jest": "^27.1.0",
|
||||
"js-beautify": "^1.5.10",
|
||||
"jsdom": "^15.0.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"json5": "^1.0.1",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"null-loader": "^1.0.0",
|
||||
"prettier": "^2.3.2",
|
||||
"raw-loader": "~0.5.0",
|
||||
"react-refresh": "^0.10.0",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"sass-loader": "^7.0.3",
|
||||
"script-loader": "~0.7.0",
|
||||
"should": "^11.1.1",
|
||||
"simple-git": "^1.96.0",
|
||||
"sinon": "^2.3.2",
|
||||
"source-map": "^0.7.3",
|
||||
"start-server-and-test": "^1.14.0",
|
||||
"style-loader": "^0.21.0",
|
||||
"stylelint": "^9.2.1",
|
||||
"stylelint-declaration-use-variable": "^1.6.1",
|
||||
"stylelint-order": "^0.8.1",
|
||||
"typescript": "^4.2.4",
|
||||
"uglify-es": "^3.3.9",
|
||||
"uglifyjs-webpack-plugin": "^1.3.0",
|
||||
"url-loader": "^1.0.1",
|
||||
"watchpack": "^1.6.0",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-middleware": "^3.7.3",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"worker-loader": "^2.0.0"
|
||||
"webpack-dev-server": "^3.11.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8 || <=9"
|
||||
@@ -157,7 +101,6 @@
|
||||
"build:dev": "webpack --mode development",
|
||||
"lint": "npm run lint:jsts & npm run lint:style",
|
||||
"lint:jsts": "eslint --fix . --ext js,jsx,ts,tsx",
|
||||
"lint:style": "stylelint --fix ./css/*",
|
||||
"preinstall": "node ./scripts/engines-check.js",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
|
||||
@@ -2,366 +2,433 @@ const numSpaces = 4;
|
||||
const maxLineLength = 160;
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
extends: "eslint:recommended",
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
ecmaVersion: 8,
|
||||
sourceType: "module",
|
||||
},
|
||||
rules: {
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{
|
||||
getWithoutSet: false,
|
||||
setWithoutGet: true,
|
||||
},
|
||||
],
|
||||
"array-bracket-newline": ["error"],
|
||||
"array-bracket-spacing": ["error"],
|
||||
"array-callback-return": ["error"],
|
||||
"array-element-newline": ["error"],
|
||||
"arrow-body-style": ["error"],
|
||||
"arrow-parens": ["error"],
|
||||
"arrow-spacing": ["error"],
|
||||
"block-scoped-var": ["error"],
|
||||
"block-spacing": ["error"],
|
||||
"brace-style": ["error"],
|
||||
"callback-return": ["error"],
|
||||
camelcase: ["error"],
|
||||
"capitalized-comments": ["error"],
|
||||
"class-methods-use-this": ["error"],
|
||||
"comma-dangle": ["error"],
|
||||
"comma-spacing": ["error"],
|
||||
"comma-style": ["error", "last"],
|
||||
complexity: ["error"],
|
||||
"computed-property-spacing": ["error", "never"],
|
||||
"consistent-return": ["error"],
|
||||
"consistent-this": ["error"],
|
||||
"constructor-super": ["error"],
|
||||
curly: ["error"],
|
||||
"default-case": ["error"],
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": ["error"],
|
||||
"eol-last": ["error"],
|
||||
eqeqeq: ["error"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["error"],
|
||||
"func-name-matching": ["error"],
|
||||
"func-names": ["error", "never"],
|
||||
"func-style": ["error"],
|
||||
"function-paren-newline": ["error"],
|
||||
"generator-star-spacing": ["error", "before"],
|
||||
"getter-return": [
|
||||
"error",
|
||||
{
|
||||
allowImplicit: false,
|
||||
},
|
||||
],
|
||||
"global-require": ["error"],
|
||||
"guard-for-in": ["error"],
|
||||
"handle-callback-err": ["error"],
|
||||
"id-blacklist": ["error"],
|
||||
"id-length": ["error"],
|
||||
"id-match": ["error"],
|
||||
"implicit-arrow-linebreak": ["error", "beside"],
|
||||
indent: [
|
||||
"error",
|
||||
numSpaces,
|
||||
{
|
||||
SwitchCase: 1,
|
||||
},
|
||||
],
|
||||
"init-declarations": ["error"],
|
||||
"jsx-quotes": ["error"],
|
||||
"key-spacing": ["error"],
|
||||
"keyword-spacing": ["error"],
|
||||
"line-comment-position": ["error"],
|
||||
"linebreak-style": ["error", "windows"],
|
||||
"lines-around-comment": ["error"],
|
||||
"lines-between-class-members": ["error"],
|
||||
"max-depth": ["error"],
|
||||
"max-len": ["error", maxLineLength],
|
||||
"max-lines": [
|
||||
"error",
|
||||
{
|
||||
skipBlankLines: true,
|
||||
skipComments: true,
|
||||
},
|
||||
],
|
||||
"max-nested-callbacks": ["error"],
|
||||
"max-params": ["error"],
|
||||
"max-statements": ["error"],
|
||||
"max-statements-per-line": ["error"],
|
||||
"multiline-comment-style": ["off", "starred-block"],
|
||||
"multiline-ternary": ["error", "never"],
|
||||
"new-cap": ["error"],
|
||||
"new-parens": ["error"],
|
||||
// TODO: configure this...
|
||||
"newline-before-return": ["error"],
|
||||
"newline-per-chained-call": ["error"],
|
||||
"no-alert": ["error"],
|
||||
"no-array-constructor": ["error"],
|
||||
"no-await-in-loop": ["error"],
|
||||
"no-bitwise": ["error"],
|
||||
"no-buffer-constructor": ["error"],
|
||||
"no-caller": ["error"],
|
||||
"no-case-declarations": ["error"],
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-cond-assign": ["error", "except-parens"],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["error"],
|
||||
"no-const-assign": ["error"],
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
checkLoops: false,
|
||||
},
|
||||
],
|
||||
"no-continue": ["off"],
|
||||
"no-control-regex": ["error"],
|
||||
"no-debugger": ["error"],
|
||||
"no-delete-var": ["error"],
|
||||
"no-div-regex": ["error"],
|
||||
"no-dupe-args": ["error"],
|
||||
"no-dupe-class-members": ["error"],
|
||||
"no-dupe-keys": ["error"],
|
||||
"no-duplicate-case": ["error"],
|
||||
"no-duplicate-imports": [
|
||||
"error",
|
||||
{
|
||||
includeExports: true,
|
||||
},
|
||||
],
|
||||
"no-else-return": ["error"],
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
allowEmptyCatch: false,
|
||||
},
|
||||
],
|
||||
"no-empty-character-class": ["error"],
|
||||
"no-empty-function": ["error"],
|
||||
"no-empty-pattern": ["error"],
|
||||
"no-eq-null": ["error"],
|
||||
"no-eval": ["error"],
|
||||
"no-ex-assign": ["error"],
|
||||
"no-extend-native": ["error"],
|
||||
"no-extra-bind": ["error"],
|
||||
"no-extra-boolean-cast": ["error"],
|
||||
"no-extra-label": ["error"],
|
||||
"no-extra-parens": [
|
||||
"error",
|
||||
"all",
|
||||
{
|
||||
conditionalAssign: false,
|
||||
},
|
||||
],
|
||||
"no-extra-semi": ["error"],
|
||||
"no-fallthrough": ["error"],
|
||||
"no-floating-decimal": ["error"],
|
||||
"no-func-assign": ["error"],
|
||||
"no-global-assign": ["error"],
|
||||
"no-implicit-coercion": ["error"],
|
||||
"no-implicit-globals": ["error"],
|
||||
"no-implied-eval": ["error"],
|
||||
"no-inline-comments": ["error"],
|
||||
"no-inner-declarations": ["error", "both"],
|
||||
"no-invalid-regexp": ["error"],
|
||||
"no-invalid-this": ["error"],
|
||||
"no-irregular-whitespace": [
|
||||
"error",
|
||||
{
|
||||
skipComments: false,
|
||||
skipRegExps: false,
|
||||
skipStrings: false,
|
||||
skipTemplates: false,
|
||||
},
|
||||
],
|
||||
"no-iterator": ["error"],
|
||||
"no-label-var": ["error"],
|
||||
"no-labels": ["error"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-lonely-if": ["error"],
|
||||
"no-loop-func": ["error"],
|
||||
"no-magic-numbers": [
|
||||
"error",
|
||||
{
|
||||
ignore: [-1, 0, 1],
|
||||
ignoreArrayIndexes: true,
|
||||
},
|
||||
],
|
||||
"no-mixed-operators": ["error"],
|
||||
"no-mixed-requires": ["error"],
|
||||
"no-mixed-spaces-and-tabs": ["error"],
|
||||
"no-multi-assign": ["error"],
|
||||
"no-multi-spaces": ["error"],
|
||||
"no-multi-str": ["error"],
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{
|
||||
max: 1,
|
||||
},
|
||||
],
|
||||
"no-native-reassign": ["error"],
|
||||
"no-negated-condition": ["error"],
|
||||
"no-negated-in-lhs": ["error"],
|
||||
"no-nested-ternary": ["error"],
|
||||
"no-new": ["error"],
|
||||
"no-new-func": ["error"],
|
||||
"no-new-object": ["error"],
|
||||
"no-new-require": ["error"],
|
||||
"no-new-symbol": ["error"],
|
||||
"no-new-wrappers": ["error"],
|
||||
"no-obj-calls": ["error"],
|
||||
"no-octal": ["error"],
|
||||
"no-octal-escape": ["error"],
|
||||
"no-param-reassign": ["error"],
|
||||
"no-path-concat": ["error"],
|
||||
"no-plusplus": [
|
||||
"error",
|
||||
{
|
||||
allowForLoopAfterthoughts: true,
|
||||
},
|
||||
],
|
||||
"no-process-env": ["error"],
|
||||
"no-process-exit": ["error"],
|
||||
"no-proto": ["error"],
|
||||
"no-prototype-builtins": ["error"],
|
||||
"no-redeclare": ["error"],
|
||||
"no-regex-spaces": ["error"],
|
||||
"no-restricted-globals": ["error"],
|
||||
"no-restricted-imports": ["error"],
|
||||
"no-restricted-modules": ["error"],
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
message: "'log' is too general, use an appropriate level when logging.",
|
||||
object: "console",
|
||||
property: "log",
|
||||
},
|
||||
],
|
||||
"no-restricted-syntax": ["error"],
|
||||
"no-return-assign": ["error"],
|
||||
"no-return-await": ["error"],
|
||||
"no-script-url": ["error"],
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
props: false,
|
||||
},
|
||||
],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
"no-shadow": ["error"],
|
||||
"no-shadow-restricted-names": ["error"],
|
||||
"no-spaced-func": ["error"],
|
||||
"no-sparse-arrays": ["error"],
|
||||
"no-sync": ["error"],
|
||||
"no-tabs": ["error"],
|
||||
"no-template-curly-in-string": ["error"],
|
||||
"no-ternary": ["off"],
|
||||
"no-this-before-super": ["error"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-undef": ["error"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-undefined": ["error"],
|
||||
"no-underscore-dangle": ["error"],
|
||||
"no-unexpected-multiline": ["error"],
|
||||
"no-unmodified-loop-condition": ["error"],
|
||||
"no-unneeded-ternary": ["error"],
|
||||
"no-unreachable": ["error"],
|
||||
"no-unsafe-finally": ["error"],
|
||||
"no-unsafe-negation": ["error"],
|
||||
"no-unused-expressions": ["error"],
|
||||
"no-unused-labels": ["error"],
|
||||
"no-unused-vars": ["error"],
|
||||
"no-use-before-define": ["error"],
|
||||
"no-useless-call": ["error"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-concat": ["error"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-escape": ["error"],
|
||||
"no-useless-rename": [
|
||||
"error",
|
||||
{
|
||||
ignoreDestructuring: false,
|
||||
ignoreExport: false,
|
||||
ignoreImport: false,
|
||||
},
|
||||
],
|
||||
"no-useless-return": ["error"],
|
||||
"no-var": ["error"],
|
||||
"no-void": ["error"],
|
||||
"no-warning-comments": ["error"],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"no-with": ["error"],
|
||||
"nonblock-statement-body-position": ["error", "below"],
|
||||
"object-curly-newline": ["error"],
|
||||
"object-curly-spacing": ["error"],
|
||||
"object-property-newline": ["error"],
|
||||
"object-shorthand": ["error"],
|
||||
"one-var": ["off"],
|
||||
"one-var-declaration-per-line": ["error"],
|
||||
"operator-assignment": ["error"],
|
||||
"operator-linebreak": ["error", "none"],
|
||||
"padded-blocks": ["off"],
|
||||
"padding-line-between-statements": ["error"],
|
||||
"prefer-arrow-callback": ["error"],
|
||||
"prefer-const": ["error"],
|
||||
"prefer-destructuring": ["off"],
|
||||
"prefer-numeric-literals": ["error"],
|
||||
"prefer-promise-reject-errors": ["off"],
|
||||
"prefer-reflect": ["error"],
|
||||
"prefer-rest-params": ["error"],
|
||||
"prefer-spread": ["error"],
|
||||
"prefer-template": ["error"],
|
||||
"quote-props": ["error"],
|
||||
quotes: ["error"],
|
||||
radix: ["error", "as-needed"],
|
||||
"require-await": ["error"],
|
||||
"require-jsdoc": ["off"],
|
||||
"require-yield": ["error"],
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
semi: ["error"],
|
||||
"semi-spacing": ["error"],
|
||||
"semi-style": ["error", "last"],
|
||||
"sort-imports": ["error"],
|
||||
"sort-keys": ["error"],
|
||||
"sort-vars": ["error"],
|
||||
"space-before-blocks": ["error"],
|
||||
"space-before-function-paren": ["off"],
|
||||
"space-in-parens": ["error"],
|
||||
"space-infix-ops": ["error"],
|
||||
"space-unary-ops": ["error"],
|
||||
"spaced-comment": ["error"],
|
||||
strict: ["error"],
|
||||
"switch-colon-spacing": [
|
||||
"error",
|
||||
{
|
||||
after: true,
|
||||
before: false,
|
||||
},
|
||||
],
|
||||
"symbol-description": ["error"],
|
||||
"template-curly-spacing": ["error"],
|
||||
"template-tag-spacing": ["error"],
|
||||
"unicode-bom": ["error", "never"],
|
||||
"use-isnan": ["error"],
|
||||
"valid-jsdoc": ["error"],
|
||||
"valid-typeof": ["error"],
|
||||
"vars-on-top": ["error"],
|
||||
"wrap-iife": ["error", "any"],
|
||||
"wrap-regex": ["error"],
|
||||
"yield-star-spacing": ["error", "before"],
|
||||
yoda: ["error", "never"],
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
"ecmaVersion": 8,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{
|
||||
"getWithoutSet": false,
|
||||
"setWithoutGet": true
|
||||
}
|
||||
],
|
||||
"array-bracket-newline": ["error"],
|
||||
"array-bracket-spacing": ["error"],
|
||||
"array-callback-return": ["error"],
|
||||
"array-element-newline": ["error"],
|
||||
"arrow-body-style": ["error"],
|
||||
"arrow-parens": ["error"],
|
||||
"arrow-spacing": ["error"],
|
||||
"block-scoped-var": ["error"],
|
||||
"block-spacing": ["error"],
|
||||
"brace-style": ["error"],
|
||||
"callback-return": ["error"],
|
||||
"camelcase": ["error"],
|
||||
"capitalized-comments": ["error"],
|
||||
"class-methods-use-this": ["error"],
|
||||
"comma-dangle": ["error"],
|
||||
"comma-spacing": ["error"],
|
||||
"comma-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"complexity": ["error"],
|
||||
"computed-property-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"consistent-return": ["error"],
|
||||
"consistent-this": ["error"],
|
||||
"constructor-super": ["error"],
|
||||
"curly": ["error"],
|
||||
"default-case": ["error"],
|
||||
"dot-location": [
|
||||
"error",
|
||||
"property"
|
||||
],
|
||||
"dot-notation": ["error"],
|
||||
"eol-last": ["error"],
|
||||
"eqeqeq": ["error"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["error"],
|
||||
"func-name-matching": ["error"],
|
||||
"func-names": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"func-style": ["error"],
|
||||
"function-paren-newline": ["error"],
|
||||
"generator-star-spacing": [
|
||||
"error",
|
||||
"before"
|
||||
],
|
||||
"getter-return": [
|
||||
"error",
|
||||
{
|
||||
"allowImplicit": false
|
||||
}
|
||||
],
|
||||
"global-require": ["error"],
|
||||
"guard-for-in": ["error"],
|
||||
"handle-callback-err": ["error"],
|
||||
"id-blacklist": ["error"],
|
||||
"id-length": ["error"],
|
||||
"id-match": ["error"],
|
||||
"implicit-arrow-linebreak": [
|
||||
"error",
|
||||
"beside"
|
||||
],
|
||||
"indent": [
|
||||
"error",
|
||||
numSpaces,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"init-declarations": ["error"],
|
||||
"jsx-quotes": ["error"],
|
||||
"key-spacing": ["error"],
|
||||
"keyword-spacing": ["error"],
|
||||
"line-comment-position": ["error"],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"windows"
|
||||
],
|
||||
"lines-around-comment": ["error"],
|
||||
"lines-between-class-members": ["error"],
|
||||
"max-depth": ["error"],
|
||||
"max-len": [
|
||||
"error",
|
||||
maxLineLength
|
||||
],
|
||||
"max-lines": [
|
||||
"error",
|
||||
{
|
||||
"skipBlankLines": true,
|
||||
"skipComments": true
|
||||
}
|
||||
],
|
||||
"max-nested-callbacks": ["error"],
|
||||
"max-params": ["error"],
|
||||
"max-statements": ["error"],
|
||||
"max-statements-per-line": ["error"],
|
||||
"multiline-comment-style": [
|
||||
"off",
|
||||
"starred-block"
|
||||
],
|
||||
"multiline-ternary": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"new-cap": ["error"],
|
||||
"new-parens": ["error"],
|
||||
// TODO: configure this...
|
||||
"newline-before-return": ["error"],
|
||||
"newline-per-chained-call": ["error"],
|
||||
"no-alert": ["error"],
|
||||
"no-array-constructor": ["error"],
|
||||
"no-await-in-loop": ["error"],
|
||||
"no-bitwise": ["error"],
|
||||
"no-buffer-constructor": ["error"],
|
||||
"no-caller": ["error"],
|
||||
"no-case-declarations": ["error"],
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-cond-assign": [
|
||||
"error",
|
||||
"except-parens"
|
||||
],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["error"],
|
||||
"no-const-assign": ["error"],
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-continue": ["off"],
|
||||
"no-control-regex": ["error"],
|
||||
"no-debugger": ["error"],
|
||||
"no-delete-var": ["error"],
|
||||
"no-div-regex": ["error"],
|
||||
"no-dupe-args": ["error"],
|
||||
"no-dupe-class-members": ["error"],
|
||||
"no-dupe-keys": ["error"],
|
||||
"no-duplicate-case": ["error"],
|
||||
"no-duplicate-imports": [
|
||||
"error",
|
||||
{
|
||||
"includeExports": true
|
||||
}
|
||||
],
|
||||
"no-else-return": ["error"],
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
"allowEmptyCatch": false
|
||||
}
|
||||
],
|
||||
"no-empty-character-class": ["error"],
|
||||
"no-empty-function": ["error"],
|
||||
"no-empty-pattern": ["error"],
|
||||
"no-eq-null": ["error"],
|
||||
"no-eval": ["error"],
|
||||
"no-ex-assign": ["error"],
|
||||
"no-extend-native": ["error"],
|
||||
"no-extra-bind": ["error"],
|
||||
"no-extra-boolean-cast": ["error"],
|
||||
"no-extra-label": ["error"],
|
||||
"no-extra-parens": [
|
||||
"error",
|
||||
"all",
|
||||
{
|
||||
"conditionalAssign": false
|
||||
}
|
||||
],
|
||||
"no-extra-semi": ["error"],
|
||||
"no-fallthrough": ["error"],
|
||||
"no-floating-decimal": ["error"],
|
||||
"no-func-assign": ["error"],
|
||||
"no-global-assign": ["error"],
|
||||
"no-implicit-coercion": ["error"],
|
||||
"no-implicit-globals": ["error"],
|
||||
"no-implied-eval": ["error"],
|
||||
"no-inline-comments": ["error"],
|
||||
"no-inner-declarations": [
|
||||
"error",
|
||||
"both"
|
||||
],
|
||||
"no-invalid-regexp": ["error"],
|
||||
"no-invalid-this": ["error"],
|
||||
"no-irregular-whitespace": [
|
||||
"error",
|
||||
{
|
||||
"skipComments": false,
|
||||
"skipRegExps": false,
|
||||
"skipStrings": false,
|
||||
"skipTemplates": false
|
||||
}
|
||||
],
|
||||
"no-iterator": ["error"],
|
||||
"no-label-var": ["error"],
|
||||
"no-labels": ["error"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-lonely-if": ["error"],
|
||||
"no-loop-func": ["error"],
|
||||
"no-magic-numbers": [
|
||||
"error",
|
||||
{
|
||||
"ignore": [
|
||||
-1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"ignoreArrayIndexes": true
|
||||
}
|
||||
],
|
||||
"no-mixed-operators": ["error"],
|
||||
"no-mixed-requires": ["error"],
|
||||
"no-mixed-spaces-and-tabs": ["error"],
|
||||
"no-multi-assign": ["error"],
|
||||
"no-multi-spaces": ["error"],
|
||||
"no-multi-str": ["error"],
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{
|
||||
"max": 1
|
||||
}
|
||||
],
|
||||
"no-native-reassign": ["error"],
|
||||
"no-negated-condition": ["error"],
|
||||
"no-negated-in-lhs": ["error"],
|
||||
"no-nested-ternary": ["error"],
|
||||
"no-new": ["error"],
|
||||
"no-new-func": ["error"],
|
||||
"no-new-object": ["error"],
|
||||
"no-new-require": ["error"],
|
||||
"no-new-symbol": ["error"],
|
||||
"no-new-wrappers": ["error"],
|
||||
"no-obj-calls": ["error"],
|
||||
"no-octal": ["error"],
|
||||
"no-octal-escape": ["error"],
|
||||
"no-param-reassign": ["error"],
|
||||
"no-path-concat": ["error"],
|
||||
"no-plusplus": [
|
||||
"error",
|
||||
{
|
||||
"allowForLoopAfterthoughts": true
|
||||
}
|
||||
],
|
||||
"no-process-env": ["error"],
|
||||
"no-process-exit": ["error"],
|
||||
"no-proto": ["error"],
|
||||
"no-prototype-builtins": ["error"],
|
||||
"no-redeclare": ["error"],
|
||||
"no-regex-spaces": ["error"],
|
||||
"no-restricted-globals": ["error"],
|
||||
"no-restricted-imports": ["error"],
|
||||
"no-restricted-modules": ["error"],
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
"message": "'log' is too general, use an appropriate level when logging.",
|
||||
"object": "console",
|
||||
"property": "log"
|
||||
}
|
||||
],
|
||||
"no-restricted-syntax": ["error"],
|
||||
"no-return-assign": ["error"],
|
||||
"no-return-await": ["error"],
|
||||
"no-script-url": ["error"],
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
"props": false
|
||||
}
|
||||
],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
"no-shadow": ["error"],
|
||||
"no-shadow-restricted-names": ["error"],
|
||||
"no-spaced-func": ["error"],
|
||||
"no-sparse-arrays": ["error"],
|
||||
"no-sync": ["error"],
|
||||
"no-tabs": ["error"],
|
||||
"no-template-curly-in-string": ["error"],
|
||||
"no-ternary": ["off"],
|
||||
"no-this-before-super": ["error"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-undef": ["error"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-undefined": ["error"],
|
||||
"no-underscore-dangle": ["error"],
|
||||
"no-unexpected-multiline": ["error"],
|
||||
"no-unmodified-loop-condition": ["error"],
|
||||
"no-unneeded-ternary": ["error"],
|
||||
"no-unreachable": ["error"],
|
||||
"no-unsafe-finally": ["error"],
|
||||
"no-unsafe-negation": ["error"],
|
||||
"no-unused-expressions": ["error"],
|
||||
"no-unused-labels": ["error"],
|
||||
"no-unused-vars": ["error"],
|
||||
"no-use-before-define": ["error"],
|
||||
"no-useless-call": ["error"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-concat": ["error"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-escape": ["error"],
|
||||
"no-useless-rename": [
|
||||
"error",
|
||||
{
|
||||
"ignoreDestructuring": false,
|
||||
"ignoreExport": false,
|
||||
"ignoreImport": false
|
||||
}
|
||||
],
|
||||
"no-useless-return": ["error"],
|
||||
"no-var": ["error"],
|
||||
"no-void": ["error"],
|
||||
"no-warning-comments": ["error"],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"no-with": ["error"],
|
||||
"nonblock-statement-body-position": [
|
||||
"error",
|
||||
"below"
|
||||
],
|
||||
"object-curly-newline": ["error"],
|
||||
"object-curly-spacing": ["error"],
|
||||
"object-property-newline": ["error"],
|
||||
"object-shorthand": ["error"],
|
||||
"one-var": ["off"],
|
||||
"one-var-declaration-per-line": ["error"],
|
||||
"operator-assignment": ["error"],
|
||||
"operator-linebreak": [
|
||||
"error",
|
||||
"none"
|
||||
],
|
||||
"padded-blocks": ["off"],
|
||||
"padding-line-between-statements": ["error"],
|
||||
"prefer-arrow-callback": ["error"],
|
||||
"prefer-const": ["error"],
|
||||
"prefer-destructuring": ["off"],
|
||||
"prefer-numeric-literals": ["error"],
|
||||
"prefer-promise-reject-errors": ["off"],
|
||||
"prefer-reflect": ["error"],
|
||||
"prefer-rest-params": ["error"],
|
||||
"prefer-spread": ["error"],
|
||||
"prefer-template": ["error"],
|
||||
"quote-props": ["error"],
|
||||
"quotes": ["error"],
|
||||
"radix": [
|
||||
"error",
|
||||
"as-needed"
|
||||
],
|
||||
"require-await": ["error"],
|
||||
"require-jsdoc": ["off"],
|
||||
"require-yield": ["error"],
|
||||
"rest-spread-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"semi": ["error"],
|
||||
"semi-spacing": ["error"],
|
||||
"semi-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"sort-imports": ["error"],
|
||||
"sort-keys": ["error"],
|
||||
"sort-vars": ["error"],
|
||||
"space-before-blocks": ["error"],
|
||||
"space-before-function-paren": ["off"],
|
||||
"space-in-parens": ["error"],
|
||||
"space-infix-ops": ["error"],
|
||||
"space-unary-ops": ["error"],
|
||||
"spaced-comment": ["error"],
|
||||
"strict": ["error"],
|
||||
"switch-colon-spacing": [
|
||||
"error",
|
||||
{
|
||||
"after": true,
|
||||
"before": false
|
||||
}
|
||||
],
|
||||
"symbol-description": ["error"],
|
||||
"template-curly-spacing": ["error"],
|
||||
"template-tag-spacing": ["error"],
|
||||
"unicode-bom": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"use-isnan": ["error"],
|
||||
"valid-jsdoc": ["error"],
|
||||
"valid-typeof": ["error"],
|
||||
"vars-on-top": ["error"],
|
||||
"wrap-iife": [
|
||||
"error",
|
||||
"any"
|
||||
],
|
||||
"wrap-regex": ["error"],
|
||||
"yield-star-spacing": [
|
||||
"error",
|
||||
"before"
|
||||
],
|
||||
"yoda": [
|
||||
"error",
|
||||
"never"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,74 +8,66 @@ const path = require("path");
|
||||
const exec = require("child_process").exec;
|
||||
const semver = require("./semver");
|
||||
|
||||
const getPackageJson = () =>
|
||||
new Promise((resolve, reject) => {
|
||||
const getPackageJson = () => new Promise((resolve, reject) => {
|
||||
try {
|
||||
/* eslint-disable-next-line global-require */
|
||||
resolve(require(path.resolve(process.cwd(), "package.json")));
|
||||
/* eslint-disable-next-line global-require */
|
||||
resolve(require(path.resolve(process.cwd(), "package.json")));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const getEngines = (data) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const getEngines = (data) => new Promise((resolve, reject) => {
|
||||
let versions = null;
|
||||
|
||||
if (data.engines) {
|
||||
versions = data.engines;
|
||||
versions = data.engines;
|
||||
}
|
||||
|
||||
if (versions) {
|
||||
resolve(versions);
|
||||
resolve(versions);
|
||||
} else {
|
||||
reject("Missing or improper 'engines' property in 'package.json'");
|
||||
reject("Missing or improper 'engines' property in 'package.json'");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const checkNpmVersion = (engines) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
|
||||
exec("npm -v", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(`Unable to find NPM version\n${stderr}`);
|
||||
}
|
||||
if (error) {
|
||||
reject(`Unable to find NPM version\n${stderr}`);
|
||||
}
|
||||
|
||||
const npmVersion = stdout.trim();
|
||||
const engineVersion = engines.npm || ">=0";
|
||||
const npmVersion = stdout.trim();
|
||||
const engineVersion = engines.npm || ">=0";
|
||||
|
||||
if (semver.satisfies(npmVersion, engineVersion)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(
|
||||
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
|
||||
);
|
||||
}
|
||||
if (semver.satisfies(npmVersion, engineVersion)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const checkNodeVersion = (engines) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
|
||||
const nodeVersion = process.version.substring(1);
|
||||
|
||||
if (semver.satisfies(nodeVersion, engines.node)) {
|
||||
resolve(engines);
|
||||
resolve(engines);
|
||||
} else {
|
||||
reject(
|
||||
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
|
||||
);
|
||||
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
getPackageJson()
|
||||
.then(getEngines)
|
||||
.then(checkNodeVersion)
|
||||
.then(checkNpmVersion)
|
||||
.then(
|
||||
() => true,
|
||||
(error) => {
|
||||
// Specifically disable these as the error message gets lost in the normal unhandled output.
|
||||
/* eslint-disable no-console, no-process-exit */
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
},
|
||||
);
|
||||
.then(getEngines)
|
||||
.then(checkNodeVersion)
|
||||
.then(checkNpmVersion)
|
||||
.then(
|
||||
() => true,
|
||||
(error) => {
|
||||
// Specifically disable these as the error message gets lost in the normal unhandled output.
|
||||
/* eslint-disable no-console, no-process-exit */
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -735,7 +735,7 @@ function initAugmentations(): void {
|
||||
|
||||
const ENMCore = new Augmentation({
|
||||
name: AugmentationNames.ENMCore,
|
||||
repCost: 2.5e5,
|
||||
repCost: 175e3,
|
||||
moneyCost: 2.5e9,
|
||||
info:
|
||||
"The Core library is an implant that upgrades the firmware of the Embedded Netburner Module. " +
|
||||
|
||||
@@ -567,6 +567,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.FactionWorkRepGain = 0.5;
|
||||
BitNodeMultipliers.FactionPassiveRepGain = 0;
|
||||
BitNodeMultipliers.GangKarmaRequirement = 0;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 1.4;
|
||||
break;
|
||||
case 3: // Corporatocracy
|
||||
BitNodeMultipliers.HackingLevelMultiplier = 0.8;
|
||||
@@ -583,6 +584,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.HomeComputerRamCost = 1.5;
|
||||
BitNodeMultipliers.PurchasedServerCost = 2;
|
||||
BitNodeMultipliers.GangKarmaRequirement = 3;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 1.4;
|
||||
break;
|
||||
case 4: // The Singularity
|
||||
BitNodeMultipliers.ServerMaxMoney = 0.15;
|
||||
@@ -597,6 +599,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.HackExpGain = 0.4;
|
||||
BitNodeMultipliers.CrimeExpGain = 0.5;
|
||||
BitNodeMultipliers.FactionWorkRepGain = 0.75;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 1.3;
|
||||
break;
|
||||
case 5: // Artificial intelligence
|
||||
BitNodeMultipliers.ServerMaxMoney = 2;
|
||||
@@ -610,6 +613,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.AugmentationMoneyCost = 2;
|
||||
BitNodeMultipliers.HackExpGain = 0.5;
|
||||
BitNodeMultipliers.CorporationValuation = 0.5;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 1.3;
|
||||
break;
|
||||
case 6: // Bladeburner
|
||||
BitNodeMultipliers.HackingLevelMultiplier = 0.35;
|
||||
@@ -626,6 +630,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.HackExpGain = 0.25;
|
||||
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
|
||||
BitNodeMultipliers.GangKarmaRequirement = 5;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 2;
|
||||
break;
|
||||
case 7: // Bladeburner 2079
|
||||
BitNodeMultipliers.BladeburnerRank = 0.6;
|
||||
@@ -647,6 +652,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.FourSigmaMarketDataApiCost = 2;
|
||||
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
|
||||
BitNodeMultipliers.GangKarmaRequirement = 5;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 2;
|
||||
break;
|
||||
case 8: // Ghost of Wall Street
|
||||
BitNodeMultipliers.ScriptHackMoney = 0.3;
|
||||
@@ -660,6 +666,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.CorporationValuation = 0;
|
||||
BitNodeMultipliers.CodingContractMoney = 0;
|
||||
BitNodeMultipliers.GangKarmaRequirement = 10;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 5;
|
||||
break;
|
||||
case 9: // Hacktocracy
|
||||
BitNodeMultipliers.HackingLevelMultiplier = 0.4;
|
||||
@@ -706,6 +713,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.PurchasedServerMaxRam = 0.5;
|
||||
BitNodeMultipliers.BladeburnerRank = 0.8;
|
||||
BitNodeMultipliers.GangKarmaRequirement = 3;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 1.2;
|
||||
break;
|
||||
case 11: //The Big Crash
|
||||
BitNodeMultipliers.HackingLevelMultiplier = 0.5;
|
||||
@@ -724,6 +732,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.CodingContractMoney = 0.25;
|
||||
BitNodeMultipliers.FourSigmaMarketDataCost = 4;
|
||||
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 2.2;
|
||||
break;
|
||||
case 12: {
|
||||
//The Recursion
|
||||
@@ -760,6 +769,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.PurchasedServerCost = inc;
|
||||
BitNodeMultipliers.PurchasedServerLimit = dec;
|
||||
BitNodeMultipliers.PurchasedServerMaxRam = dec;
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = inc;
|
||||
|
||||
BitNodeMultipliers.ManualHackMoney = dec;
|
||||
BitNodeMultipliers.ScriptHackMoney = dec;
|
||||
|
||||
@@ -156,6 +156,11 @@ interface IBitNodeMultipliers {
|
||||
*/
|
||||
PurchasedServerCost: number;
|
||||
|
||||
/**
|
||||
* Influence how much it costs to purchase a server
|
||||
*/
|
||||
PurchasedServerSoftcap: number;
|
||||
|
||||
/**
|
||||
* Influences the maximum number of purchased servers you can have
|
||||
*/
|
||||
@@ -237,6 +242,7 @@ export const BitNodeMultipliers: IBitNodeMultipliers = {
|
||||
HomeComputerRamCost: 1,
|
||||
|
||||
PurchasedServerCost: 1,
|
||||
PurchasedServerSoftcap: 1,
|
||||
PurchasedServerLimit: 1,
|
||||
PurchasedServerMaxRam: 1,
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Skill } from "./Skill";
|
||||
import { City } from "./City";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { IRouter, Page } from "../ui/Router";
|
||||
import { ConsoleHelpText } from "./data/Help";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
@@ -26,7 +26,6 @@ import { addOffset } from "../utils/helpers/addOffset";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { calculateHospitalizationCost } from "../Hospital/Hospital";
|
||||
import { redPillFlag } from "../RedPill";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
@@ -132,7 +131,7 @@ export class Bladeburner implements IBladeburner {
|
||||
return this.resetAction();
|
||||
}
|
||||
this.actionTimeToComplete = action.getActionTime(this);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
break;
|
||||
@@ -145,11 +144,11 @@ export class Bladeburner implements IBladeburner {
|
||||
if (action.count < 1) {
|
||||
return this.resetAction();
|
||||
}
|
||||
if (actionId.name === "Raid" && this.getCurrentCity().commsEst === 0) {
|
||||
if (actionId.name === "Raid" && this.getCurrentCity().comms === 0) {
|
||||
return this.resetAction();
|
||||
}
|
||||
this.actionTimeToComplete = action.getActionTime(this);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
break;
|
||||
@@ -169,7 +168,7 @@ export class Bladeburner implements IBladeburner {
|
||||
throw new Error("Failed to get BlackOperation object for: " + actionId.name);
|
||||
}
|
||||
this.actionTimeToComplete = action.getActionTime(this);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
break;
|
||||
@@ -184,6 +183,7 @@ export class Bladeburner implements IBladeburner {
|
||||
break;
|
||||
case ActionTypes["Diplomacy"]:
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
case ActionTypes["Incite Violence"]:
|
||||
this.actionTimeToComplete = 60;
|
||||
break;
|
||||
default:
|
||||
@@ -220,7 +220,7 @@ export class Bladeburner implements IBladeburner {
|
||||
for (let i = 0; i < arrayOfCommands.length; ++i) {
|
||||
this.executeConsoleCommand(player, arrayOfCommands[i]);
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
}
|
||||
@@ -339,6 +339,10 @@ export class Bladeburner implements IBladeburner {
|
||||
action.type = ActionTypes["Hyperbolic Regeneration Chamber"];
|
||||
action.name = "Hyperbolic Regeneration Chamber";
|
||||
break;
|
||||
case "incite violence":
|
||||
action.type = ActionTypes["Incite Violence"];
|
||||
action.name = "Incite Violence";
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -1088,9 +1092,6 @@ export class Bladeburner implements IBladeburner {
|
||||
case "Investigation":
|
||||
if (success) {
|
||||
city.improvePopulationEstimateByPercentage(0.4 * this.skillMultipliers.successChanceEstimate);
|
||||
if (Math.random() < 0.02 * this.skillMultipliers.successChanceEstimate) {
|
||||
city.improveCommunityEstimate(1);
|
||||
}
|
||||
} else {
|
||||
this.triggerPotentialMigration(this.city, 0.1);
|
||||
}
|
||||
@@ -1098,9 +1099,6 @@ export class Bladeburner implements IBladeburner {
|
||||
case "Undercover Operation":
|
||||
if (success) {
|
||||
city.improvePopulationEstimateByPercentage(0.8 * this.skillMultipliers.successChanceEstimate);
|
||||
if (Math.random() < 0.02 * this.skillMultipliers.successChanceEstimate) {
|
||||
city.improveCommunityEstimate(1);
|
||||
}
|
||||
} else {
|
||||
this.triggerPotentialMigration(this.city, 0.15);
|
||||
}
|
||||
@@ -1121,7 +1119,6 @@ export class Bladeburner implements IBladeburner {
|
||||
nonZero: true,
|
||||
});
|
||||
--city.comms;
|
||||
--city.commsEst;
|
||||
} else {
|
||||
const change = getRandomInt(-10, -5) / 10;
|
||||
city.changePopulationByPercentage(change, {
|
||||
@@ -1174,6 +1171,8 @@ export class Bladeburner implements IBladeburner {
|
||||
return GeneralActions["Diplomacy"];
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
return GeneralActions["Hyperbolic Regeneration Chamber"];
|
||||
case ActionTypes["Incite Violence"]:
|
||||
return GeneralActions["Incite Violence"];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -1298,7 +1297,7 @@ export class Bladeburner implements IBladeburner {
|
||||
action.level = action.maxLevel;
|
||||
} // Autolevel
|
||||
this.startAction(player, this.action); // Repeat action
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
break;
|
||||
@@ -1387,7 +1386,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.log("You lost " + formatNumber(losses, 0) + " team members during " + action.name);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
break;
|
||||
@@ -1500,6 +1499,25 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ActionTypes["Incite Violence"]: {
|
||||
for (const contract of Object.keys(this.contracts)) {
|
||||
const growthF = Growths[contract];
|
||||
if (!growthF) throw new Error("trying to generate count for action that doesn't exist? " + contract);
|
||||
this.contracts[contract].count += (60 * 6 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
||||
}
|
||||
for (const operation of Object.keys(this.operations)) {
|
||||
const growthF = Growths[operation];
|
||||
if (!growthF) throw new Error("trying to generate count for action that doesn't exist? " + operation);
|
||||
this.operations[operation].count += (60 * 6 * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
||||
}
|
||||
if (this.logging.general) {
|
||||
this.log(`Incited violence in the synthoid communities.`);
|
||||
}
|
||||
const city = this.cities[this.city];
|
||||
city.chaos *= (city.chaos + 100) * 2;
|
||||
this.startAction(player, this.action);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error(`Bladeburner.completeAction() called for invalid action: ${this.action.type}`);
|
||||
break;
|
||||
@@ -1854,7 +1872,7 @@ export class Bladeburner implements IBladeburner {
|
||||
|
||||
process(router: IRouter, player: IPlayer): void {
|
||||
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
|
||||
if (redPillFlag === false && this.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
if (router.page() !== Page.BitVerse && this.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
return router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
@@ -1967,6 +1985,7 @@ export class Bladeburner implements IBladeburner {
|
||||
"Field Analysis",
|
||||
"Diplomacy",
|
||||
"Hyperbolic Regeneration Chamber",
|
||||
"Incite Violence",
|
||||
];
|
||||
if (gen.includes(res.type)) {
|
||||
res.type = "General";
|
||||
@@ -2056,7 +2075,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.startAction(player, actionId);
|
||||
workerScript.log("bladeburner.startAction", `Starting bladeburner action with type '${type}' and name ${name}"`);
|
||||
return true;
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
this.resetAction();
|
||||
workerScript.log("bladeburner.startAction", errorLogText);
|
||||
return false;
|
||||
@@ -2091,6 +2110,7 @@ export class Bladeburner implements IBladeburner {
|
||||
return this.getRecruitmentTime(player);
|
||||
case ActionTypes["Diplomacy"]:
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
case ActionTypes["Incite Violence"]:
|
||||
return 60;
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionTime", errorLogText);
|
||||
@@ -2128,6 +2148,7 @@ export class Bladeburner implements IBladeburner {
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
case ActionTypes["Diplomacy"]:
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
case ActionTypes["Incite Violence"]:
|
||||
return [1, 1];
|
||||
case ActionTypes["Recruitment"]: {
|
||||
const recChance = this.getRecruitmentSuccessChance(player);
|
||||
@@ -2170,6 +2191,7 @@ export class Bladeburner implements IBladeburner {
|
||||
case ActionTypes["FieldAnalysis"]:
|
||||
case ActionTypes["Diplomacy"]:
|
||||
case ActionTypes["Hyperbolic Regeneration Chamber"]:
|
||||
case ActionTypes["Incite Violence"]:
|
||||
return Infinity;
|
||||
default:
|
||||
workerScript.log("bladeburner.getActionCountRemaining", errorLogText);
|
||||
|
||||
@@ -34,11 +34,6 @@ export class City {
|
||||
*/
|
||||
comms = 0;
|
||||
|
||||
/**
|
||||
* Estimated number of communities in the city.
|
||||
*/
|
||||
commsEst = 0;
|
||||
|
||||
/**
|
||||
* Chaos level of the city.
|
||||
*/
|
||||
@@ -53,8 +48,6 @@ export class City {
|
||||
|
||||
// Number of Synthoid communities population and estimate
|
||||
this.comms = getRandomInt(5, 150);
|
||||
this.commsEst = this.comms + getRandomInt(-5, 5);
|
||||
if (this.commsEst < 0) this.commsEst = 0;
|
||||
this.chaos = 0;
|
||||
}
|
||||
|
||||
@@ -113,23 +106,6 @@ export class City {
|
||||
}
|
||||
}
|
||||
|
||||
improveCommunityEstimate(n = 1): void {
|
||||
if (isNaN(n)) {
|
||||
throw new Error("NaN passed into City.improveCommunityEstimate()");
|
||||
}
|
||||
if (this.commsEst < this.comms) {
|
||||
this.commsEst += n;
|
||||
if (this.commsEst > this.comms) {
|
||||
this.commsEst = this.comms;
|
||||
}
|
||||
} else if (this.commsEst > this.comms) {
|
||||
this.commsEst -= n;
|
||||
if (this.commsEst < this.comms) {
|
||||
this.commsEst = this.comms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @params options:
|
||||
* estChange(int): How much the estimate should change by
|
||||
|
||||
@@ -30,4 +30,8 @@ export const GeneralActions: IMap<Action> = {};
|
||||
GeneralActions[actionName] = new Action({
|
||||
name: actionName,
|
||||
});
|
||||
actionName = "Incite Violence";
|
||||
GeneralActions[actionName] = new Action({
|
||||
name: actionName,
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IBladeburner } from "./IBladeburner";
|
||||
|
||||
export interface IStatsMultiplier {
|
||||
interface IStatsMultiplier {
|
||||
[key: string]: number;
|
||||
|
||||
hack: number;
|
||||
|
||||
@@ -12,6 +12,7 @@ export const ActionTypes: {
|
||||
"Field Analysis": number;
|
||||
Diplomacy: number;
|
||||
"Hyperbolic Regeneration Chamber": number;
|
||||
"Incite Violence": number;
|
||||
} = {
|
||||
Idle: 1,
|
||||
Contract: 2,
|
||||
@@ -24,4 +25,5 @@ export const ActionTypes: {
|
||||
"Field Analysis": 7,
|
||||
Diplomacy: 8,
|
||||
"Hyperbolic Regeneration Chamber": 9,
|
||||
"Incite Violence": 10,
|
||||
};
|
||||
|
||||
@@ -62,4 +62,7 @@ export const GeneralActions: {
|
||||
</>
|
||||
),
|
||||
},
|
||||
"Incite Violence": {
|
||||
desc: <>Purposefully stir trouble in the synthoid community in order to gain a political edge.</>,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -12,13 +12,13 @@ export const Growths: {
|
||||
["Stealth Retirement Operation"]: () => number;
|
||||
["Assassination"]: () => number;
|
||||
} = {
|
||||
Tracking: () => getRandomInt(5, 75) / 10,
|
||||
"Bounty Hunter": () => getRandomInt(5, 75) / 10,
|
||||
Retirement: () => getRandomInt(5, 75) / 10,
|
||||
Investigation: () => getRandomInt(10, 40) / 10,
|
||||
"Undercover Operation": () => getRandomInt(10, 40) / 10,
|
||||
"Sting Operation": () => getRandomInt(3, 40) / 10,
|
||||
Raid: () => getRandomInt(2, 40) / 10,
|
||||
"Stealth Retirement Operation": () => getRandomInt(1, 20) / 10,
|
||||
Assassination: () => getRandomInt(1, 20) / 10,
|
||||
Tracking: () => getRandomInt(5, 75) / 20,
|
||||
"Bounty Hunter": () => getRandomInt(5, 75) / 20,
|
||||
Retirement: () => getRandomInt(5, 75) / 20,
|
||||
Investigation: () => getRandomInt(10, 40) / 20,
|
||||
"Undercover Operation": () => getRandomInt(10, 40) / 20,
|
||||
"Sting Operation": () => getRandomInt(3, 40) / 20,
|
||||
Raid: () => getRandomInt(2, 40) / 20,
|
||||
"Stealth Retirement Operation": () => getRandomInt(1, 20) / 20,
|
||||
Assassination: () => getRandomInt(1, 20) / 20,
|
||||
};
|
||||
|
||||
@@ -55,14 +55,18 @@ export function ActionLevel({ action, isActive, bladeburner, rerender }: IProps)
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Tooltip title={isActive ? <Typography>WARNING: changing the level will restart the Operation</Typography> : ""}>
|
||||
<IconButton disabled={!canIncrease} onClick={increaseLevel}>
|
||||
<ArrowDropUpIcon />
|
||||
</IconButton>
|
||||
<span>
|
||||
<IconButton disabled={!canIncrease} onClick={increaseLevel}>
|
||||
<ArrowDropUpIcon />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip title={isActive ? <Typography>WARNING: changing the level will restart the Operation</Typography> : ""}>
|
||||
<IconButton disabled={!canDecrease} onClick={decreaseLevel}>
|
||||
<ArrowDropDownIcon />
|
||||
</IconButton>
|
||||
<span>
|
||||
<IconButton disabled={!canDecrease} onClick={decreaseLevel}>
|
||||
<ArrowDropDownIcon />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -27,7 +27,11 @@ export function BlackOpElem(props: IProps): React.ReactElement {
|
||||
}
|
||||
const isCompleted = props.bladeburner.blackops[props.action.name] != null;
|
||||
if (isCompleted) {
|
||||
return <h2 style={{ display: "block" }}>{props.action.name} (COMPLETED)</h2>;
|
||||
return (
|
||||
<Paper sx={{ my: 1, p: 1 }}>
|
||||
<Typography>{props.action.name} (COMPLETED)</Typography>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
const isActive =
|
||||
@@ -47,33 +51,35 @@ export function BlackOpElem(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Paper sx={{ my: 1, p: 1 }}>
|
||||
<Typography>
|
||||
{isActive ? (
|
||||
<>
|
||||
<>
|
||||
<CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
|
||||
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
|
||||
<p style={{ display: "block" }}>
|
||||
{createProgressBarText({
|
||||
progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete,
|
||||
})}
|
||||
</p>
|
||||
</>
|
||||
</>
|
||||
) : (
|
||||
{isActive ? (
|
||||
<>
|
||||
<>
|
||||
<CopyableText value={props.action.name} />
|
||||
|
||||
<StartButton
|
||||
bladeburner={props.bladeburner}
|
||||
type={ActionTypes.BlackOperation}
|
||||
name={props.action.name}
|
||||
rerender={rerender}
|
||||
/>
|
||||
<TeamSizeButton action={props.action} bladeburner={props.bladeburner} />
|
||||
<Typography>
|
||||
(IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
|
||||
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
|
||||
</Typography>
|
||||
<Typography>
|
||||
{createProgressBarText({
|
||||
progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete,
|
||||
})}
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<CopyableText value={props.action.name} />
|
||||
|
||||
<StartButton
|
||||
bladeburner={props.bladeburner}
|
||||
type={ActionTypes.BlackOperation}
|
||||
name={props.action.name}
|
||||
rerender={rerender}
|
||||
/>
|
||||
<TeamSizeButton action={props.action} bladeburner={props.bladeburner} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<Typography>{actionData.desc}</Typography>
|
||||
|
||||
@@ -37,6 +37,7 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
|
||||
return 30;
|
||||
case "Diplomacy":
|
||||
case "Hyperbolic Regeneration Chamber":
|
||||
case "Incite Violence":
|
||||
return 60;
|
||||
case "Recruitment":
|
||||
return props.bladeburner.getRecruitmentTime(props.player);
|
||||
@@ -57,8 +58,9 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
|
||||
<Paper sx={{ my: 1, p: 1 }}>
|
||||
{isActive ? (
|
||||
<>
|
||||
<CopyableText value={props.action.name} />
|
||||
<Typography>
|
||||
<CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
|
||||
(IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} /{" "}
|
||||
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
|
||||
</Typography>
|
||||
<Typography>
|
||||
@@ -69,9 +71,7 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
|
||||
</>
|
||||
) : (
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
<Typography>
|
||||
<CopyableText value={props.action.name} />
|
||||
</Typography>
|
||||
<CopyableText value={props.action.name} />
|
||||
<StartButton
|
||||
bladeburner={props.bladeburner}
|
||||
type={ActionTypes[props.action.name as string]}
|
||||
|
||||
@@ -117,9 +117,7 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>
|
||||
Est. Synthoid Communities: {formatNumber(props.bladeburner.getCurrentCity().comms, 0)}
|
||||
</Typography>
|
||||
<Typography>Synthoid Communities: {formatNumber(props.bladeburner.getCurrentCity().comms, 0)}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<br />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface RNG {
|
||||
interface RNG {
|
||||
random(): number;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ export function generateRandomContractOnHome(): void {
|
||||
serv.addContract(contract);
|
||||
}
|
||||
|
||||
export interface IGenerateContractParams {
|
||||
interface IGenerateContractParams {
|
||||
problemType?: string;
|
||||
server?: string;
|
||||
fn?: string;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { CodingContractEvent } from "./ui/React/CodingContractModal";
|
||||
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
||||
|
||||
/* Represents different types of problems that a Coding Contract can have */
|
||||
export class CodingContractType {
|
||||
class CodingContractType {
|
||||
/**
|
||||
* Function that generates a description of the problem
|
||||
*/
|
||||
|
||||
@@ -45,8 +45,3 @@ export function initCompanies(): void {
|
||||
export function loadCompanies(saveString: string): void {
|
||||
Companies = JSON.parse(saveString, Reviver);
|
||||
}
|
||||
|
||||
// Utility function to check if a string is valid company name
|
||||
export function companyExists(name: string): boolean {
|
||||
return Companies.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
122
src/Constants.ts
122
src/Constants.ts
@@ -114,7 +114,7 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: number;
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
Version: "0.56.0",
|
||||
Version: "0.57.0",
|
||||
|
||||
// Speed (in ms) at which the main loop is updated
|
||||
_idleSpeed: 200,
|
||||
@@ -281,107 +281,55 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
LatestUpdate: `
|
||||
v0.56.0 - 2021-10-11 Trimming the backlog (hydroflame & community)
|
||||
v0.57.0 - 2021-10-16 It was too cheap! (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
** BREAKING **
|
||||
** BREAKING (kindof) **
|
||||
|
||||
* The 'write' function is now async. This helps when making scripts that write scripts.
|
||||
* purchased server cost now scales exponentially past 2^10.
|
||||
I'm going to actually explain this one: Currently the cost of a 2^20GB server is 57b
|
||||
Most players can get that before their first install. In an effort to nerf good players
|
||||
a softcap was added. This softcap is different for every BN.
|
||||
|
||||
** Terminal **
|
||||
** Script Editor **
|
||||
|
||||
* 'grow' and 'weaken' have been added as terminal command. This should help player transition
|
||||
from commands to scripts. The tutorial also talks about it.
|
||||
* 'cp' command added
|
||||
* Improved performance by rate limiting refresh.
|
||||
|
||||
** IP vs Hostname **
|
||||
|
||||
* The game now uses hostname as primary key for it's servers (yeah believe it or not IPs were
|
||||
used until then). This has caused some issues with purchased servers (they couldn't be sold).
|
||||
You might need to soft reset for the game to fully convert itself.
|
||||
|
||||
** Sleeve **
|
||||
|
||||
* Fixed bug where they couldn't train at Volhaven.
|
||||
* No longer consume all bonus time at once, making it look buggy.
|
||||
|
||||
** SF9 **
|
||||
|
||||
* Now boosts hacknet production by 8/12/14%
|
||||
|
||||
** Hacknet Servers **
|
||||
|
||||
* production nerfed by 10%
|
||||
* Max money increase gets weaker above 10t max money
|
||||
|
||||
** Corporation **
|
||||
|
||||
* Warehouse tooltip now also displays the amount of space taken by products.
|
||||
* Changed research box completely to avoid dependency on Treant (Treant is a pita)
|
||||
* All textbox should accept MAX/MP case insensitive.
|
||||
* Fixed export popup not refreshing dropdowns correctly.
|
||||
* Fixed product mku becoming zero
|
||||
* Increased scaling of Wilson to avoid feedback loop.
|
||||
* Can no longer get in debt by buying real estate
|
||||
* Bonus time is consumed faster.
|
||||
* Added a theme that is close to monokai. Unfortunately a full monokai is impossible because
|
||||
Monaco doesn't have a very good tokenizer.
|
||||
* Opening a file and connecting to a new server will still save the file on the server that the file
|
||||
was opened.
|
||||
|
||||
** Netscript **
|
||||
|
||||
* isBusy takes bitverse and infiltration into account
|
||||
* hospitalize can't be called when in infiltration.
|
||||
* setToCommitCrime now accepts crime rough name instead of perfect name.
|
||||
* disableLog All now works for bladeburner functions.
|
||||
* Fixed netscript port for ns1.
|
||||
|
||||
* New function: alert, which creates a textbox.
|
||||
* New function: toast, creates a notification in the bottom right.
|
||||
* New function: upgradeHomeCores (@Saynt_Garmo)
|
||||
* New function: atExit, allows you to set a callback for when the script closes.
|
||||
* New kindof function: autocomplete, this allows you to tell the game what it should
|
||||
autocomplete on the terminal.
|
||||
|
||||
** Augmentation **
|
||||
|
||||
* Added augmentation to Ti Di Hui that removes penalty for being unfocused.
|
||||
* Neuroflux no longer appears in special factions.
|
||||
* ENM Core (the Augmentation from The Black Hand with the highest rep cost) rep cost
|
||||
reduced from 250 to 175. This will help new players transition from TBH to BitRunners more easily.
|
||||
|
||||
** Script Editor **
|
||||
** Bladeburner **
|
||||
|
||||
* Ram check is debounced instead of refreshed every second.
|
||||
* Added the vscode extension documentation to the game (it doesn't work well, thought)
|
||||
* Fixed issue where autocomplete list would grow forever
|
||||
* Added semi-monokai as theme.
|
||||
* Fixed issue where modifying filename would mess it up.
|
||||
* Font size can be changed now.
|
||||
|
||||
** Infiltration **
|
||||
|
||||
* Fixed issue where game controls would become unfocused.
|
||||
* New general action: Incite Violence. This action adds other action counts but increases chaos.
|
||||
|
||||
** Misc. **
|
||||
|
||||
* Fixed loader incorrectly assuming some null values are incorrect.
|
||||
* installBackdoor trigger Bitverse sequence
|
||||
* Some improvements to the theme editor
|
||||
* Improved documentation about where to learn javascript.
|
||||
* Added some instructions for contributors.
|
||||
* Fixed typo in corporation sell shares modal (@Saynt_Garmo)
|
||||
* Fixed pagination being black on black in Active Scripts
|
||||
* Create Script tab renamed to Script Editor
|
||||
* Fixed an issue where corp some textbox wouldn't update when changing city.
|
||||
* Fixed an issue where hacknet online time was always 0.
|
||||
* Netscript function prompt fixed.
|
||||
* Fixed miscalculation in growth.
|
||||
* Script with syntax errors will try to be a tad more helpful.
|
||||
* Corporations can no longer bribe bladeburners.
|
||||
* Augmentation Graphene Branchiblade renamed to Brachi, like the rest of them.
|
||||
* All ram is displayed in GB/TB/PB now.
|
||||
* Game now saves when saving a file, this can be turned off.
|
||||
* Several improvement to log window.
|
||||
* Bladeburner current action returns General type instead of the name of the action.
|
||||
* Bladeburner travel and Sleeve travel respect disable ASCII.
|
||||
* Tutorial fits on small screens.
|
||||
* Import is much slower but more consistent now.
|
||||
* Fix intelligence not updating properly.
|
||||
* Added SF -1: Time Compression
|
||||
* ReadTheDoc theme now matches the game.
|
||||
* Logbox should wrap text better
|
||||
* Logbox behavior should feel better.
|
||||
* Fix font for AutoLink.exe
|
||||
* Current bladeburner action is shown on the character overview.
|
||||
* Fix blackop being #000 on #000.
|
||||
* The last clicked Tail Box goes in front of the others.
|
||||
* Fixed an issue where some values were loaded as 0 when they should be null.
|
||||
* Implemented toasts.
|
||||
* .msg are no longer saved in the text file.
|
||||
* Tail boxes no longer display all the args, they use "..." after 30 characters.
|
||||
* Fixed cancelation penalty bonus not being properly applied after the IP <-> hostname switch.
|
||||
* Fixed an exploit where you could send non-strings or numbers to other scripts.
|
||||
* Fixed issue when trying to work for a faction with a work type that doesn't exist while
|
||||
already working for that faction.
|
||||
* Fixed not being able to work for the CIA. (Don't ask)
|
||||
* nerf noodle bar
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -99,7 +99,7 @@ export class Warehouse {
|
||||
updateSize(corporation: ICorporation, industry: IIndustry): void {
|
||||
try {
|
||||
this.size = this.level * 100 * corporation.getStorageMultiplier() * industry.getStorageMultiplier();
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { MathComponent } from "mathjax-react";
|
||||
import { MathJax, MathJaxContext } from "better-react-mathjax";
|
||||
|
||||
interface IProps {
|
||||
division: IIndustry;
|
||||
@@ -19,9 +19,8 @@ export function IndustryProductEquation(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<MathComponent
|
||||
display={false}
|
||||
tex={reqs.join("+") + String.raw`\Rightarrow` + prod.map((p) => String.raw`1\text{ }${p}`).join("+")}
|
||||
/>
|
||||
<MathJaxContext>
|
||||
<MathJax>{"\\(" + reqs.join("+") + `\\Rightarrow` + prod.map((p) => `1 \\text{${p}}`).join("+") + "\\)"}</MathJax>
|
||||
</MathJaxContext>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,11 +76,6 @@ function MarketTA2(props: IMarketTA2Props): React.ReactElement {
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
|
||||
<Typography>
|
||||
Note that Market-TA.II overrides Market-TA.I. This means that if both are enabled, then Market-TA.II will take
|
||||
effect, not Market-TA.I
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -93,6 +88,7 @@ interface IProps {
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Materials
|
||||
export function MaterialMarketTaModal(props: IProps): React.ReactElement {
|
||||
const division = useDivision();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
@@ -106,28 +102,32 @@ export function MaterialMarketTaModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is {numeralWrapper.formatMoney(props.mat.bCost + markupLimit)}.
|
||||
This means that if you set the sale price higher than this, you will begin to experience a loss in number of
|
||||
sales
|
||||
</Typography>
|
||||
{!division.hasResearch("Market-TA.II") && (
|
||||
<>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is{" "}
|
||||
{numeralWrapper.formatMoney(props.mat.bCost + markupLimit)}. This means that if you set the sale price
|
||||
higher than this, you will begin to experience a loss in number of sales
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.mat.marketTa1} onChange={onMarketTA1} />}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I
|
||||
(i.e. the price shown above)
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.mat.marketTa1} onChange={onMarketTA1} />}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the price identified by
|
||||
Market-TA.I (i.e. the price shown above)
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Use Market-TA.I for Auto-Sale Price</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Typography>Use Market-TA.I for Auto-Sale Price</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<MarketTA2 mat={props.mat} />
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -66,11 +66,6 @@ function MarketTA2(props: ITa2Props): React.ReactElement {
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
|
||||
<Typography>
|
||||
Note that Market-TA.II overrides Market-TA.I. This means that if both are enabled, then Market-TA.II will take
|
||||
effect, not Market-TA.I
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -83,6 +78,7 @@ interface IProps {
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Products
|
||||
export function ProductMarketTaModal(props: IProps): React.ReactElement {
|
||||
const division = useDivision();
|
||||
const markupLimit = props.product.rat / props.product.mku;
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
@@ -96,29 +92,32 @@ export function ProductMarketTaModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is{" "}
|
||||
{numeralWrapper.formatMoney(props.product.pCost + markupLimit)}. This means that if you set the sale price
|
||||
higher than this, you will begin to experience a loss in number of sales
|
||||
</Typography>
|
||||
{!division.hasResearch("Market-TA.II") && (
|
||||
<>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is{" "}
|
||||
{numeralWrapper.formatMoney(props.product.pCost + markupLimit)}. This means that if you set the sale price
|
||||
higher than this, you will begin to experience a loss in number of sales
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.product.marketTa1} onChange={onChange} />}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I
|
||||
(i.e. the price shown above)
|
||||
</Typography>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.product.marketTa1} onChange={onChange} />}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the price identified by
|
||||
Market-TA.I (i.e. the price shown above)
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Use Market-TA.I for Auto-Sale Price</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Typography>Use Market-TA.I for Auto-Sale Price</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<MarketTA2 product={props.product} />
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
|
||||
export interface IConstructorParams {
|
||||
interface IConstructorParams {
|
||||
hacking_success_weight?: number;
|
||||
strength_success_weight?: number;
|
||||
defense_success_weight?: number;
|
||||
|
||||
@@ -24,7 +24,7 @@ export function loadFactions(saveString: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function AddToFactions(faction: Faction): void {
|
||||
function AddToFactions(faction: Faction): void {
|
||||
const name: string = faction.name;
|
||||
Factions[name] = faction;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ export function initFactions(): void {
|
||||
//Resets a faction during (re-)initialization. Saves the favor in the new
|
||||
//Faction object and deletes the old Faction Object from "Factions". Then
|
||||
//reinserts the new Faction object
|
||||
export function resetFaction(newFactionObject: Faction): void {
|
||||
function resetFaction(newFactionObject: Faction): void {
|
||||
if (!(newFactionObject instanceof Faction)) {
|
||||
throw new Error("Invalid argument 'newFactionObject' passed into resetFaction()");
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Reputation } from "../../ui/React/Reputation";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { MathComponent } from "mathjax-react";
|
||||
import { MathJax, MathJaxContext } from "better-react-mathjax";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
@@ -98,9 +98,9 @@ export function DonateOption(props: IProps): React.ReactElement {
|
||||
}}
|
||||
/>
|
||||
<Typography>
|
||||
<MathComponent
|
||||
tex={String.raw`reputation = \frac{\text{donation amount} \times \text{reputation multiplier}}{10^{${digits}}}`}
|
||||
/>
|
||||
<MathJaxContext>
|
||||
<MathJax>{`\\(reputation = \\frac{\\text{donation amount} \\cdot \\text{reputation multiplier}}{10^{${digits}}}\\)`}</MathJax>
|
||||
</MathJaxContext>
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { FactionInfo } from "../../Faction/FactionInfo";
|
||||
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
import { MathComponent } from "mathjax-react";
|
||||
import { MathJax, MathJaxContext } from "better-react-mathjax";
|
||||
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
@@ -57,10 +57,14 @@ export function Info(props: IProps): React.ReactElement {
|
||||
You will have <Favor favor={props.faction.favor + favorGain} /> faction favor after installing an
|
||||
Augmentation.
|
||||
</Typography>
|
||||
<MathComponent tex={String.raw`\large{r = \text{total faction reputation}}`} />
|
||||
<MathComponent
|
||||
tex={String.raw`\large{favor=\left\lfloor\log_{1.02}\left(\frac{r+25000}{25500}\right)\right\rfloor}`}
|
||||
/>
|
||||
<MathJaxContext>
|
||||
<MathJax>{"\\(\\huge{r = \\text{total faction reputation}}\\)"}</MathJax>
|
||||
</MathJaxContext>
|
||||
<MathJaxContext>
|
||||
<MathJax>
|
||||
{"\\(\\huge{favor=\\left\\lfloor\\log_{1.02}\\left(\\frac{r+25000}{25500}\\right)\\right\\rfloor}\\)"}
|
||||
</MathJax>
|
||||
</MathJaxContext>
|
||||
</>
|
||||
}
|
||||
>
|
||||
@@ -81,8 +85,13 @@ export function Info(props: IProps): React.ReactElement {
|
||||
favor is gained whenever you install an Augmentation. The amount of favor you gain depends on the total
|
||||
amount of reputation you earned with this faction. Across all resets.
|
||||
</Typography>
|
||||
<MathComponent tex={String.raw`\large{r = reputation}`} />
|
||||
<MathComponent tex={String.raw`\large{\Delta r = \Delta r \times \frac{100+favor}{100}}`} />
|
||||
|
||||
<MathJaxContext>
|
||||
<MathJax>{"\\(\\huge{r = reputation}\\)"}</MathJax>
|
||||
</MathJaxContext>
|
||||
<MathJaxContext>
|
||||
<MathJax>{"\\(\\huge{\\Delta r = \\Delta r \\times \\frac{100+favor}{100}}\\)"}</MathJax>
|
||||
</MathJaxContext>
|
||||
</>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -97,7 +97,7 @@ export class Gang {
|
||||
this.processExperienceGains(cycles);
|
||||
this.processTerritoryAndPowerGains(cycles);
|
||||
this.storedCycles -= cycles;
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
console.error(`Exception caught when processing Gang: ${e}`);
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,7 @@ export class Gang {
|
||||
workerScript.log("ascend", `Ascended Gang member ${member.name}`);
|
||||
}
|
||||
return res;
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (workerScript == null) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ITaskParams } from "../ITaskParams";
|
||||
* Defines the parameters that can be used to initialize and describe a GangMemberTask
|
||||
* (defined in Gang.js)
|
||||
*/
|
||||
export interface IGangMemberTaskMetadata {
|
||||
interface IGangMemberTaskMetadata {
|
||||
/**
|
||||
* Description of the task
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ export enum UpgradeType {
|
||||
* Defines the parameters that can be used to initialize and describe a GangMemberUpgrade
|
||||
* (defined in Gang.js)
|
||||
*/
|
||||
export interface IGangMemberUpgradeMetadata {
|
||||
interface IGangMemberUpgradeMetadata {
|
||||
cost: number;
|
||||
mults: IMults;
|
||||
name: string;
|
||||
|
||||
@@ -512,7 +512,6 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
|
||||
|
||||
const old = target.moneyMax;
|
||||
target.changeMaximumMoney(upg.value);
|
||||
console.log(target.moneyMax / old);
|
||||
} catch (e) {
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
|
||||
@@ -5,7 +5,7 @@ import Tooltip from "@mui/material/Tooltip";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MathComponent } from "mathjax-react";
|
||||
import { MathJax, MathJaxContext } from "better-react-mathjax";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
@@ -19,7 +19,7 @@ export function CoresButton(props: IProps): React.ReactElement {
|
||||
return <Button>Upgrade 'home' cores - MAX</Button>;
|
||||
}
|
||||
|
||||
const cost = 1e9 * Math.pow(7.5, homeComputer.cpuCores);
|
||||
const cost = props.p.getUpgradeHomeCoresCost();
|
||||
|
||||
function buy(): void {
|
||||
if (maxCores) return;
|
||||
@@ -30,7 +30,13 @@ export function CoresButton(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={<MathComponent tex={String.raw`\large{cost = 10^9 \times 7.5 ^{\text{cores}}}`} />}>
|
||||
<Tooltip
|
||||
title={
|
||||
<MathJaxContext>
|
||||
<MathJax>{`\\(\\large{cost = 10^9 \\cdot 7.5 ^{\\text{cores}}}\\)`}</MathJax>
|
||||
</MathJaxContext>
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
|
||||
Upgrade 'home' cores ({homeComputer.cpuCores} -> {homeComputer.cpuCores + 1}) -
|
||||
|
||||
@@ -7,8 +7,8 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { purchaseRamForHomeComputer } from "../../Server/ServerPurchases";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MathComponent } from "mathjax-react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { MathJax, MathJaxContext } from "better-react-mathjax";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
@@ -29,7 +29,13 @@ export function RamButton(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={<MathComponent tex={String.raw`\large{cost = 3.2 \times 10^3 \times 1.58^{log_2{(ram)}}}`} />}>
|
||||
<Tooltip
|
||||
title={
|
||||
<MathJaxContext>
|
||||
<MathJax>{`\\(\\large{cost = 3.2 \\cdot 10^3 \\cdot 1.58^{log_2{(ram)}}}\\)`}</MathJax>
|
||||
</MathJaxContext>
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
|
||||
Upgrade 'home' RAM ({numeralWrapper.formatRAM(homeComputer.maxRam)} ->
|
||||
|
||||
@@ -69,6 +69,7 @@ export function TechVendorLocation(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
{purchaseServerButtons}
|
||||
<br />
|
||||
<Typography>
|
||||
|
||||
@@ -13,12 +13,14 @@ import { Reviver } from "../utils/JSONReviver";
|
||||
function sendMessage(msg: Message, forced = false): void {
|
||||
msg.recvd = true;
|
||||
if (forced || !Settings.SuppressMessages) {
|
||||
showMessage(msg);
|
||||
showMessage(msg.filename);
|
||||
}
|
||||
addMessageToServer(msg, "home");
|
||||
}
|
||||
|
||||
function showMessage(msg: Message): void {
|
||||
function showMessage(name: string): void {
|
||||
const msg = Messages[name];
|
||||
if (!msg) throw new Error("trying to display unexistent message");
|
||||
const txt =
|
||||
"Message received from unknown sender: <br><br>" +
|
||||
"<i>" +
|
||||
@@ -39,12 +41,11 @@ function addMessageToServer(msg: Message, serverHostname: string): void {
|
||||
}
|
||||
for (let i = 0; i < server.messages.length; ++i) {
|
||||
const other = server.messages[i];
|
||||
if (typeof other === "string") continue;
|
||||
if (msg.filename === other.filename) {
|
||||
if (msg.filename === other) {
|
||||
return; //Already exists
|
||||
}
|
||||
}
|
||||
server.messages.push(msg);
|
||||
server.messages.push(msg.filename);
|
||||
}
|
||||
|
||||
//Checks if any of the 'timed' messages should be sent
|
||||
@@ -216,4 +217,4 @@ function initMessages(): void {
|
||||
);
|
||||
}
|
||||
|
||||
export { Messages, checkForMessagesToSend, sendMessage, showMessage, loadMessages, initMessages, Message };
|
||||
export { Messages, checkForMessagesToSend, showMessage, loadMessages, initMessages };
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { Milestone } from "./Milestone";
|
||||
|
||||
export class Quest {
|
||||
title: string;
|
||||
milestones: Milestone[];
|
||||
|
||||
constructor(title: string, milestones: Milestone[]) {
|
||||
this.title = title;
|
||||
this.milestones = milestones;
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,11 @@ export class WorkerScript {
|
||||
*/
|
||||
hostname: string;
|
||||
|
||||
/**
|
||||
* Function called when the script ends.
|
||||
*/
|
||||
atExit: any;
|
||||
|
||||
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => any) {
|
||||
this.name = runningScriptObj.filename;
|
||||
this.hostname = runningScriptObj.server;
|
||||
@@ -132,15 +137,13 @@ export class WorkerScript {
|
||||
if (!found) {
|
||||
throw new Error(`WorkerScript constructed with invalid script filename: ${this.name}`);
|
||||
}
|
||||
|
||||
this.scriptRef = runningScriptObj;
|
||||
this.args = runningScriptObj.args.slice();
|
||||
this.env = new Environment(null);
|
||||
if (typeof nsFuncsGenerator === "function") {
|
||||
this.env.vars = nsFuncsGenerator(this);
|
||||
}
|
||||
this.env.set("args", runningScriptObj.args.slice());
|
||||
|
||||
this.scriptRef = runningScriptObj;
|
||||
this.args = runningScriptObj.args.slice();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ import { RunningScript } from "../Script/RunningScript";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
|
||||
import { compareArrays } from "../utils/helpers/compareArrays";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
|
||||
export function killWorkerScript(runningScriptObj: RunningScript, hostname: string, rerenderUi?: boolean): boolean;
|
||||
export function killWorkerScript(workerScript: WorkerScript): boolean;
|
||||
@@ -67,6 +68,16 @@ function killWorkerScriptByPid(pid: number, rerenderUi = true): boolean {
|
||||
function stopAndCleanUpWorkerScript(workerScript: WorkerScript, rerenderUi = true): void {
|
||||
workerScript.env.stopFlag = true;
|
||||
killNetscriptDelay(workerScript);
|
||||
if (typeof workerScript.atExit === "function") {
|
||||
try {
|
||||
workerScript.atExit();
|
||||
} catch (e: any) {
|
||||
dialogBoxCreate(
|
||||
`Error trying to call atExit for script ${workerScript.name} on ${workerScript.hostname} ${workerScript.scriptRef.args} ${e}`,
|
||||
);
|
||||
}
|
||||
workerScript.atExit = undefined;
|
||||
}
|
||||
removeWorkerScript(workerScript, rerenderUi);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
224
src/NetscriptFunctions/Augmentations.ts
Normal file
224
src/NetscriptFunctions/Augmentations.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { purchaseAugmentation } from "../Faction/FactionHelpers";
|
||||
import { startWorkerScript } from "../NetscriptWorker";
|
||||
import { Augmentation } from "../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { augmentationExists, installAugmentations } from "../Augmentation/AugmentationHelpers";
|
||||
import { prestigeAugmentation } from "../Prestige";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { killWorkerScript } from "../Netscript/killWorkerScript";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { RunningScript } from "../Script/RunningScript";
|
||||
|
||||
export interface INetscriptAugmentations {
|
||||
getOwnedAugmentations(purchased?: any): any;
|
||||
getOwnedSourceFiles(): any;
|
||||
getAugmentationsFromFaction(facname: any): any;
|
||||
getAugmentationCost(name: any): any;
|
||||
getAugmentationPrereq(name: any): any;
|
||||
getAugmentationPrice(name: any): any;
|
||||
getAugmentationRepReq(name: any): any;
|
||||
getAugmentationStats(name: any): any;
|
||||
purchaseAugmentation(faction: any, name: any): any;
|
||||
softReset(cbScript: any): any;
|
||||
installAugmentations(cbScript: any): any;
|
||||
}
|
||||
|
||||
export function NetscriptAugmentations(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptAugmentations {
|
||||
const getAugmentation = function (func: any, name: any): Augmentation {
|
||||
if (!augmentationExists(name)) {
|
||||
throw helper.makeRuntimeErrorMsg(func, `Invalid augmentation: '${name}'`);
|
||||
}
|
||||
|
||||
return Augmentations[name];
|
||||
};
|
||||
const runAfterReset = function (cbScript = null): void {
|
||||
//Run a script after reset
|
||||
if (cbScript && isString(cbScript)) {
|
||||
const home = player.getHomeComputer();
|
||||
for (const script of home.scripts) {
|
||||
if (script.filename === cbScript) {
|
||||
const ramUsage = script.ramUsage;
|
||||
const ramAvailable = home.maxRam - home.ramUsed;
|
||||
if (ramUsage > ramAvailable) {
|
||||
return; // Not enough RAM
|
||||
}
|
||||
const runningScriptObj = new RunningScript(script, []); // No args
|
||||
runningScriptObj.threads = 1; // Only 1 thread
|
||||
startWorkerScript(runningScriptObj, home);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
getOwnedAugmentations: function (purchased: any = false): any {
|
||||
helper.updateDynamicRam("getOwnedAugmentations", getRamCost("getOwnedAugmentations"));
|
||||
helper.checkSingularityAccess("getOwnedAugmentations", 3);
|
||||
const res = [];
|
||||
for (let i = 0; i < player.augmentations.length; ++i) {
|
||||
res.push(player.augmentations[i].name);
|
||||
}
|
||||
if (purchased) {
|
||||
for (let i = 0; i < player.queuedAugmentations.length; ++i) {
|
||||
res.push(player.queuedAugmentations[i].name);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getOwnedSourceFiles: function (): any {
|
||||
helper.updateDynamicRam("getOwnedSourceFiles", getRamCost("getOwnedSourceFiles"));
|
||||
helper.checkSingularityAccess("getOwnedSourceFiles", 3);
|
||||
const res = [];
|
||||
for (let i = 0; i < player.sourceFiles.length; ++i) {
|
||||
res.push({
|
||||
n: player.sourceFiles[i].n,
|
||||
lvl: player.sourceFiles[i].lvl,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getAugmentationsFromFaction: function (facname: any): any {
|
||||
helper.updateDynamicRam("getAugmentationsFromFaction", getRamCost("getAugmentationsFromFaction"));
|
||||
helper.checkSingularityAccess("getAugmentationsFromFaction", 3);
|
||||
const faction = helper.getFaction("getAugmentationsFromFaction", facname);
|
||||
|
||||
// If player has a gang with this faction, return all augmentations.
|
||||
if (player.hasGangWith(facname)) {
|
||||
const res = [];
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
if (!aug.isSpecial) {
|
||||
res.push(augName);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return faction.augmentations.slice();
|
||||
},
|
||||
getAugmentationCost: function (name: any): any {
|
||||
helper.updateDynamicRam("getAugmentationCost", getRamCost("getAugmentationCost"));
|
||||
helper.checkSingularityAccess("getAugmentationCost", 3);
|
||||
const aug = getAugmentation("getAugmentationCost", name);
|
||||
return [aug.baseRepRequirement, aug.baseCost];
|
||||
},
|
||||
getAugmentationPrereq: function (name: any): any {
|
||||
helper.updateDynamicRam("getAugmentationPrereq", getRamCost("getAugmentationPrereq"));
|
||||
helper.checkSingularityAccess("getAugmentationPrereq", 3);
|
||||
const aug = getAugmentation("getAugmentationPrereq", name);
|
||||
return aug.prereqs.slice();
|
||||
},
|
||||
getAugmentationPrice: function (name: any): any {
|
||||
helper.updateDynamicRam("getAugmentationPrice", getRamCost("getAugmentationPrice"));
|
||||
helper.checkSingularityAccess("getAugmentationPrice", 3);
|
||||
const aug = getAugmentation("getAugmentationPrice", name);
|
||||
return aug.baseCost;
|
||||
},
|
||||
getAugmentationRepReq: function (name: any): any {
|
||||
helper.updateDynamicRam("getAugmentationRepReq", getRamCost("getAugmentationRepReq"));
|
||||
helper.checkSingularityAccess("getAugmentationRepReq", 3);
|
||||
const aug = getAugmentation("getAugmentationRepReq", name);
|
||||
return aug.baseRepRequirement;
|
||||
},
|
||||
getAugmentationStats: function (name: any): any {
|
||||
helper.updateDynamicRam("getAugmentationStats", getRamCost("getAugmentationStats"));
|
||||
helper.checkSingularityAccess("getAugmentationStats", 3);
|
||||
const aug = getAugmentation("getAugmentationStats", name);
|
||||
return Object.assign({}, aug.mults);
|
||||
},
|
||||
purchaseAugmentation: function (faction: any, name: any): any {
|
||||
helper.updateDynamicRam("purchaseAugmentation", getRamCost("purchaseAugmentation"));
|
||||
helper.checkSingularityAccess("purchaseAugmentation", 3);
|
||||
const fac = helper.getFaction("purchaseAugmentation", faction);
|
||||
const aug = getAugmentation("purchaseAugmentation", name);
|
||||
|
||||
let augs = [];
|
||||
if (player.hasGangWith(faction)) {
|
||||
for (const augName in Augmentations) {
|
||||
const tempAug = Augmentations[augName];
|
||||
if (!tempAug.isSpecial) {
|
||||
augs.push(augName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
augs = fac.augmentations;
|
||||
}
|
||||
|
||||
if (!augs.includes(name)) {
|
||||
workerScript.log("purchaseAugmentation", `Faction '${faction}' does not have the '${name}' augmentation.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const isNeuroflux = aug.name === AugmentationNames.NeuroFluxGovernor;
|
||||
if (!isNeuroflux) {
|
||||
for (let j = 0; j < player.queuedAugmentations.length; ++j) {
|
||||
if (player.queuedAugmentations[j].name === aug.name) {
|
||||
workerScript.log("purchaseAugmentation", `You already have the '${name}' augmentation.`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < player.augmentations.length; ++j) {
|
||||
if (player.augmentations[j].name === aug.name) {
|
||||
workerScript.log("purchaseAugmentation", `You already have the '${name}' augmentation.`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fac.playerReputation < aug.baseRepRequirement) {
|
||||
workerScript.log("purchaseAugmentation", `You do not have enough reputation with '${fac.name}'.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const res = purchaseAugmentation(aug, fac, true);
|
||||
workerScript.log("purchaseAugmentation", res);
|
||||
if (isString(res) && res.startsWith("You purchased")) {
|
||||
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
softReset: function (cbScript: any): any {
|
||||
helper.updateDynamicRam("softReset", getRamCost("softReset"));
|
||||
helper.checkSingularityAccess("softReset", 3);
|
||||
|
||||
workerScript.log("softReset", "Soft resetting. This will cause this script to be killed");
|
||||
setTimeout(() => {
|
||||
prestigeAugmentation();
|
||||
runAfterReset(cbScript);
|
||||
}, 0);
|
||||
|
||||
// Prevent workerScript from "finishing execution naturally"
|
||||
workerScript.running = false;
|
||||
killWorkerScript(workerScript);
|
||||
},
|
||||
installAugmentations: function (cbScript: any): any {
|
||||
helper.updateDynamicRam("installAugmentations", getRamCost("installAugmentations"));
|
||||
helper.checkSingularityAccess("installAugmentations", 3);
|
||||
|
||||
if (player.queuedAugmentations.length === 0) {
|
||||
workerScript.log("installAugmentations", "You do not have any Augmentations to be installed.");
|
||||
return false;
|
||||
}
|
||||
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
|
||||
workerScript.log("installAugmentations", "Installing Augmentations. This will cause this script to be killed");
|
||||
setTimeout(() => {
|
||||
installAugmentations();
|
||||
runAfterReset(cbScript);
|
||||
}, 0);
|
||||
|
||||
workerScript.running = false; // Prevent workerScript from "finishing execution naturally"
|
||||
killWorkerScript(workerScript);
|
||||
},
|
||||
};
|
||||
}
|
||||
403
src/NetscriptFunctions/Bladeburner.ts
Normal file
403
src/NetscriptFunctions/Bladeburner.ts
Normal file
@@ -0,0 +1,403 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner/Bladeburner";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
|
||||
export interface INetscriptBladeburner {
|
||||
getContractNames(): any;
|
||||
getOperationNames(): any;
|
||||
getBlackOpNames(): any;
|
||||
getBlackOpRank(name?: any): any;
|
||||
getGeneralActionNames(): any;
|
||||
getSkillNames(): any;
|
||||
startAction(type?: any, name?: any): any;
|
||||
stopBladeburnerAction(): any;
|
||||
getCurrentAction(): any;
|
||||
getActionTime(type?: any, name?: any): any;
|
||||
getActionEstimatedSuccessChance(type?: any, name?: any): any;
|
||||
getActionRepGain(type?: any, name?: any, level?: any): any;
|
||||
getActionCountRemaining(type?: any, name?: any): any;
|
||||
getActionMaxLevel(type?: any, name?: any): any;
|
||||
getActionCurrentLevel(type?: any, name?: any): any;
|
||||
getActionAutolevel(type?: any, name?: any): any;
|
||||
setActionAutolevel(type?: any, name?: any, autoLevel?: any): any;
|
||||
setActionLevel(type?: any, name?: any, level?: any): any;
|
||||
getRank(): any;
|
||||
getSkillPoints(): any;
|
||||
getSkillLevel(skillName?: any): any;
|
||||
getSkillUpgradeCost(skillName?: any): any;
|
||||
upgradeSkill(skillName: any): any;
|
||||
getTeamSize(type?: any, name?: any): any;
|
||||
setTeamSize(type?: any, name?: any, size?: any): any;
|
||||
getCityEstimatedPopulation(cityName: any): any;
|
||||
getCityEstimatedCommunities(cityName: any): any;
|
||||
getCityChaos(cityName: any): any;
|
||||
getCity(): any;
|
||||
switchCity(cityName: any): any;
|
||||
getStamina(): any;
|
||||
joinBladeburnerFaction(): any;
|
||||
joinBladeburnerDivision(): any;
|
||||
getBonusTime(): any;
|
||||
}
|
||||
|
||||
export function NetscriptBladeburner(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptBladeburner {
|
||||
const checkBladeburnerAccess = function (func: any, skipjoined: any = false): void {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
const apiAccess =
|
||||
player.bitNodeN === 7 ||
|
||||
player.sourceFiles.some((a) => {
|
||||
return a.n === 7;
|
||||
});
|
||||
if (!apiAccess) {
|
||||
const apiDenied = `You do not currently have access to the Bladeburner API. You must either be in BitNode-7 or have Source-File 7.`;
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, apiDenied);
|
||||
}
|
||||
if (!skipjoined) {
|
||||
const bladeburnerAccess = bladeburner instanceof Bladeburner;
|
||||
if (!bladeburnerAccess) {
|
||||
const bladeburnerDenied = `You must be a member of the Bladeburner division to use this API.`;
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, bladeburnerDenied);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const checkBladeburnerCity = function (func: any, city: any): void {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
if (!bladeburner.cities.hasOwnProperty(city)) {
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid city: ${city}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getBladeburnerActionObject = function (func: any, type: any, name: any): any {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
const actionId = bladeburner.getActionIdFromTypeAndName(type, name);
|
||||
if (!actionId) {
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid action type='${type}', name='${name}'`);
|
||||
}
|
||||
const actionObj = bladeburner.getActionObject(actionId);
|
||||
if (!actionObj) {
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid action type='${type}', name='${name}'`);
|
||||
}
|
||||
|
||||
return actionObj;
|
||||
};
|
||||
|
||||
return {
|
||||
getContractNames: function (): any {
|
||||
helper.updateDynamicRam("getContractNames", getRamCost("bladeburner", "getContractNames"));
|
||||
checkBladeburnerAccess("getContractNames");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getContractNamesNetscriptFn();
|
||||
},
|
||||
getOperationNames: function (): any {
|
||||
helper.updateDynamicRam("getOperationNames", getRamCost("bladeburner", "getOperationNames"));
|
||||
checkBladeburnerAccess("getOperationNames");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getOperationNamesNetscriptFn();
|
||||
},
|
||||
getBlackOpNames: function (): any {
|
||||
helper.updateDynamicRam("getBlackOpNames", getRamCost("bladeburner", "getBlackOpNames"));
|
||||
checkBladeburnerAccess("getBlackOpNames");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getBlackOpNamesNetscriptFn();
|
||||
},
|
||||
getBlackOpRank: function (name: any = ""): any {
|
||||
helper.updateDynamicRam("getBlackOpRank", getRamCost("bladeburner", "getBlackOpRank"));
|
||||
checkBladeburnerAccess("getBlackOpRank");
|
||||
const action: any = getBladeburnerActionObject("getBlackOpRank", "blackops", name);
|
||||
return action.reqdRank;
|
||||
},
|
||||
getGeneralActionNames: function (): any {
|
||||
helper.updateDynamicRam("getGeneralActionNames", getRamCost("bladeburner", "getGeneralActionNames"));
|
||||
checkBladeburnerAccess("getGeneralActionNames");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getGeneralActionNamesNetscriptFn();
|
||||
},
|
||||
getSkillNames: function (): any {
|
||||
helper.updateDynamicRam("getSkillNames", getRamCost("bladeburner", "getSkillNames"));
|
||||
checkBladeburnerAccess("getSkillNames");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getSkillNamesNetscriptFn();
|
||||
},
|
||||
startAction: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("startAction", getRamCost("bladeburner", "startAction"));
|
||||
checkBladeburnerAccess("startAction");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.startActionNetscriptFn(player, type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.startAction", e);
|
||||
}
|
||||
},
|
||||
stopBladeburnerAction: function (): any {
|
||||
helper.updateDynamicRam("stopBladeburnerAction", getRamCost("bladeburner", "stopBladeburnerAction"));
|
||||
checkBladeburnerAccess("stopBladeburnerAction");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.resetAction();
|
||||
},
|
||||
getCurrentAction: function (): any {
|
||||
helper.updateDynamicRam("getCurrentAction", getRamCost("bladeburner", "getCurrentAction"));
|
||||
checkBladeburnerAccess("getCurrentAction");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getTypeAndNameFromActionId(bladeburner.action);
|
||||
},
|
||||
getActionTime: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("getActionTime", getRamCost("bladeburner", "getActionTime"));
|
||||
checkBladeburnerAccess("getActionTime");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getActionTimeNetscriptFn(player, type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getActionTime", e);
|
||||
}
|
||||
},
|
||||
getActionEstimatedSuccessChance: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam(
|
||||
"getActionEstimatedSuccessChance",
|
||||
getRamCost("bladeburner", "getActionEstimatedSuccessChance"),
|
||||
);
|
||||
checkBladeburnerAccess("getActionEstimatedSuccessChance");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getActionEstimatedSuccessChance", e);
|
||||
}
|
||||
},
|
||||
getActionRepGain: function (type: any = "", name: any = "", level: any): any {
|
||||
helper.updateDynamicRam("getActionRepGain", getRamCost("bladeburner", "getActionRepGain"));
|
||||
checkBladeburnerAccess("getActionRepGain");
|
||||
const action = getBladeburnerActionObject("getActionRepGain", type, name);
|
||||
let rewardMultiplier;
|
||||
if (level == null || isNaN(level)) {
|
||||
rewardMultiplier = Math.pow(action.rewardFac, action.level - 1);
|
||||
} else {
|
||||
rewardMultiplier = Math.pow(action.rewardFac, level - 1);
|
||||
}
|
||||
|
||||
return action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank;
|
||||
},
|
||||
getActionCountRemaining: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("getActionCountRemaining", getRamCost("bladeburner", "getActionCountRemaining"));
|
||||
checkBladeburnerAccess("getActionCountRemaining");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getActionCountRemainingNetscriptFn(type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getActionCountRemaining", e);
|
||||
}
|
||||
},
|
||||
getActionMaxLevel: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("getActionMaxLevel", getRamCost("bladeburner", "getActionMaxLevel"));
|
||||
checkBladeburnerAccess("getActionMaxLevel");
|
||||
const action = getBladeburnerActionObject("getActionMaxLevel", type, name);
|
||||
return action.maxLevel;
|
||||
},
|
||||
getActionCurrentLevel: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("getActionCurrentLevel", getRamCost("bladeburner", "getActionCurrentLevel"));
|
||||
checkBladeburnerAccess("getActionCurrentLevel");
|
||||
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
|
||||
return action.level;
|
||||
},
|
||||
getActionAutolevel: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("getActionAutolevel", getRamCost("bladeburner", "getActionAutolevel"));
|
||||
checkBladeburnerAccess("getActionAutolevel");
|
||||
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
|
||||
return action.autoLevel;
|
||||
},
|
||||
setActionAutolevel: function (type: any = "", name: any = "", autoLevel: any = true): any {
|
||||
helper.updateDynamicRam("setActionAutolevel", getRamCost("bladeburner", "setActionAutolevel"));
|
||||
checkBladeburnerAccess("setActionAutolevel");
|
||||
const action = getBladeburnerActionObject("setActionAutolevel", type, name);
|
||||
action.autoLevel = autoLevel;
|
||||
},
|
||||
setActionLevel: function (type: any = "", name: any = "", level: any = 1): any {
|
||||
helper.updateDynamicRam("setActionLevel", getRamCost("bladeburner", "setActionLevel"));
|
||||
checkBladeburnerAccess("setActionLevel");
|
||||
const action = getBladeburnerActionObject("setActionLevel", type, name);
|
||||
if (level < 1 || level > action.maxLevel) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"bladeburner.setActionLevel",
|
||||
`Level must be between 1 and ${action.maxLevel}, is ${level}`,
|
||||
);
|
||||
}
|
||||
action.level = level;
|
||||
},
|
||||
getRank: function (): any {
|
||||
helper.updateDynamicRam("getRank", getRamCost("bladeburner", "getRank"));
|
||||
checkBladeburnerAccess("getRank");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.rank;
|
||||
},
|
||||
getSkillPoints: function (): any {
|
||||
helper.updateDynamicRam("getSkillPoints", getRamCost("bladeburner", "getSkillPoints"));
|
||||
checkBladeburnerAccess("getSkillPoints");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.skillPoints;
|
||||
},
|
||||
getSkillLevel: function (skillName: any = ""): any {
|
||||
helper.updateDynamicRam("getSkillLevel", getRamCost("bladeburner", "getSkillLevel"));
|
||||
checkBladeburnerAccess("getSkillLevel");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getSkillLevelNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getSkillLevel", e);
|
||||
}
|
||||
},
|
||||
getSkillUpgradeCost: function (skillName: any = ""): any {
|
||||
helper.updateDynamicRam("getSkillUpgradeCost", getRamCost("bladeburner", "getSkillUpgradeCost"));
|
||||
checkBladeburnerAccess("getSkillUpgradeCost");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getSkillUpgradeCost", e);
|
||||
}
|
||||
},
|
||||
upgradeSkill: function (skillName: any): any {
|
||||
helper.updateDynamicRam("upgradeSkill", getRamCost("bladeburner", "upgradeSkill"));
|
||||
checkBladeburnerAccess("upgradeSkill");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.upgradeSkillNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.upgradeSkill", e);
|
||||
}
|
||||
},
|
||||
getTeamSize: function (type: any = "", name: any = ""): any {
|
||||
helper.updateDynamicRam("getTeamSize", getRamCost("bladeburner", "getTeamSize"));
|
||||
checkBladeburnerAccess("getTeamSize");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getTeamSizeNetscriptFn(type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getTeamSize", e);
|
||||
}
|
||||
},
|
||||
setTeamSize: function (type: any = "", name: any = "", size: any): any {
|
||||
helper.updateDynamicRam("setTeamSize", getRamCost("bladeburner", "setTeamSize"));
|
||||
checkBladeburnerAccess("setTeamSize");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.setTeamSizeNetscriptFn(type, name, size, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.setTeamSize", e);
|
||||
}
|
||||
},
|
||||
getCityEstimatedPopulation: function (cityName: any): any {
|
||||
helper.updateDynamicRam("getCityEstimatedPopulation", getRamCost("bladeburner", "getCityEstimatedPopulation"));
|
||||
checkBladeburnerAccess("getCityEstimatedPopulation");
|
||||
checkBladeburnerCity("getCityEstimatedPopulation", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].popEst;
|
||||
},
|
||||
getCityEstimatedCommunities: function (cityName: any): any {
|
||||
helper.updateDynamicRam("getCityEstimatedCommunities", getRamCost("bladeburner", "getCityEstimatedCommunities"));
|
||||
checkBladeburnerAccess("getCityEstimatedCommunities");
|
||||
checkBladeburnerCity("getCityEstimatedCommunities", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].commsEst;
|
||||
},
|
||||
getCityChaos: function (cityName: any): any {
|
||||
helper.updateDynamicRam("getCityChaos", getRamCost("bladeburner", "getCityChaos"));
|
||||
checkBladeburnerAccess("getCityChaos");
|
||||
checkBladeburnerCity("getCityChaos", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].chaos;
|
||||
},
|
||||
getCity: function (): any {
|
||||
helper.updateDynamicRam("getCity", getRamCost("bladeburner", "getCity"));
|
||||
checkBladeburnerAccess("getCityChaos");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.city;
|
||||
},
|
||||
switchCity: function (cityName: any): any {
|
||||
helper.updateDynamicRam("switchCity", getRamCost("bladeburner", "switchCity"));
|
||||
checkBladeburnerAccess("switchCity");
|
||||
checkBladeburnerCity("switchCity", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return (bladeburner.city = cityName);
|
||||
},
|
||||
getStamina: function (): any {
|
||||
helper.updateDynamicRam("getStamina", getRamCost("bladeburner", "getStamina"));
|
||||
checkBladeburnerAccess("getStamina");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return [bladeburner.stamina, bladeburner.maxStamina];
|
||||
},
|
||||
joinBladeburnerFaction: function (): any {
|
||||
helper.updateDynamicRam("joinBladeburnerFaction", getRamCost("bladeburner", "joinBladeburnerFaction"));
|
||||
checkBladeburnerAccess("joinBladeburnerFaction", true);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.joinBladeburnerFactionNetscriptFn(workerScript);
|
||||
},
|
||||
joinBladeburnerDivision: function (): any {
|
||||
helper.updateDynamicRam("joinBladeburnerDivision", getRamCost("bladeburner", "joinBladeburnerDivision"));
|
||||
if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) {
|
||||
if (player.bitNodeN === 8) {
|
||||
return false;
|
||||
}
|
||||
if (player.bladeburner instanceof Bladeburner) {
|
||||
return true; // Already member
|
||||
} else if (
|
||||
player.strength >= 100 &&
|
||||
player.defense >= 100 &&
|
||||
player.dexterity >= 100 &&
|
||||
player.agility >= 100
|
||||
) {
|
||||
player.bladeburner = new Bladeburner(player);
|
||||
workerScript.log("joinBladeburnerDivision", "You have been accepted into the Bladeburner division");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
workerScript.log(
|
||||
"joinBladeburnerDivision",
|
||||
"You do not meet the requirements for joining the Bladeburner division",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
getBonusTime: function (): any {
|
||||
helper.updateDynamicRam("getBonusTime", getRamCost("bladeburner", "getBonusTime"));
|
||||
checkBladeburnerAccess("getBonusTime");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return Math.round(bladeburner.storedCycles / 5);
|
||||
},
|
||||
};
|
||||
}
|
||||
109
src/NetscriptFunctions/CodingContract.ts
Normal file
109
src/NetscriptFunctions/CodingContract.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { is2DArray } from "../utils/helpers/is2DArray";
|
||||
import { CodingContract } from "../CodingContracts";
|
||||
|
||||
export interface INetscriptCodingContract {
|
||||
attempt(answer: any, fn: any, ip?: any, options?: { returnReward: any }): any;
|
||||
getContractType(fn: any, ip?: any): any;
|
||||
getData(fn: any, ip?: any): any;
|
||||
getDescription(fn: any, ip?: any): any;
|
||||
getNumTriesRemaining(fn: any, ip?: any): any;
|
||||
}
|
||||
|
||||
export function NetscriptCodingContract(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptCodingContract {
|
||||
const getCodingContract = function (func: any, ip: any, fn: any): CodingContract {
|
||||
const server = helper.getServer(ip, func);
|
||||
const contract = server.getContract(fn);
|
||||
if (contract == null) {
|
||||
throw helper.makeRuntimeErrorMsg(`codingcontract.${func}`, `Cannot find contract '${fn}' on server '${ip}'`);
|
||||
}
|
||||
|
||||
return contract;
|
||||
};
|
||||
|
||||
return {
|
||||
attempt: function (answer: any, fn: any, ip: any = workerScript.hostname, { returnReward }: any = {}): any {
|
||||
helper.updateDynamicRam("attempt", getRamCost("codingcontract", "attempt"));
|
||||
const contract = getCodingContract("attempt", ip, fn);
|
||||
|
||||
// Convert answer to string. If the answer is a 2D array, then we have to
|
||||
// manually add brackets for the inner arrays
|
||||
if (is2DArray(answer)) {
|
||||
const answerComponents = [];
|
||||
for (let i = 0; i < answer.length; ++i) {
|
||||
answerComponents.push(["[", answer[i].toString(), "]"].join(""));
|
||||
}
|
||||
|
||||
answer = answerComponents.join(",");
|
||||
} else {
|
||||
answer = String(answer);
|
||||
}
|
||||
|
||||
const creward = contract.reward;
|
||||
if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward");
|
||||
|
||||
const serv = helper.getServer(ip, "codingcontract.attempt");
|
||||
if (contract.isSolution(answer)) {
|
||||
const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
|
||||
workerScript.log("attempt", `Successfully completed Coding Contract '${fn}'. Reward: ${reward}`);
|
||||
serv.removeContract(fn);
|
||||
return returnReward ? reward : true;
|
||||
} else {
|
||||
++contract.tries;
|
||||
if (contract.tries >= contract.getMaxNumTries()) {
|
||||
workerScript.log("attempt", `Coding Contract attempt '${fn}' failed. Contract is now self-destructing`);
|
||||
serv.removeContract(fn);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"attempt",
|
||||
`Coding Contract attempt '${fn}' failed. ${contract.getMaxNumTries() - contract.tries} attempts remaining.`,
|
||||
);
|
||||
}
|
||||
|
||||
return returnReward ? "" : false;
|
||||
}
|
||||
},
|
||||
getContractType: function (fn: any, ip: any = workerScript.hostname): any {
|
||||
helper.updateDynamicRam("getContractType", getRamCost("codingcontract", "getContractType"));
|
||||
const contract = getCodingContract("getContractType", ip, fn);
|
||||
return contract.getType();
|
||||
},
|
||||
getData: function (fn: any, ip: any = workerScript.hostname): any {
|
||||
helper.updateDynamicRam("getData", getRamCost("codingcontract", "getData"));
|
||||
const contract = getCodingContract("getData", ip, fn);
|
||||
const data = contract.getData();
|
||||
if (data.constructor === Array) {
|
||||
// For two dimensional arrays, we have to copy the internal arrays using
|
||||
// slice() as well. As of right now, no contract has arrays that have
|
||||
// more than two dimensions
|
||||
const copy = data.slice();
|
||||
for (let i = 0; i < copy.length; ++i) {
|
||||
if (data[i].constructor === Array) {
|
||||
copy[i] = data[i].slice();
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
getDescription: function (fn: any, ip: any = workerScript.hostname): any {
|
||||
helper.updateDynamicRam("getDescription", getRamCost("codingcontract", "getDescription"));
|
||||
const contract = getCodingContract("getDescription", ip, fn);
|
||||
return contract.getDescription();
|
||||
},
|
||||
getNumTriesRemaining: function (fn: any, ip: any = workerScript.hostname): any {
|
||||
helper.updateDynamicRam("getNumTriesRemaining", getRamCost("codingcontract", "getNumTriesRemaining"));
|
||||
const contract = getCodingContract("getNumTriesRemaining", ip, fn);
|
||||
return contract.getMaxNumTries() - contract.tries;
|
||||
},
|
||||
};
|
||||
}
|
||||
305
src/NetscriptFunctions/Corporation.ts
Normal file
305
src/NetscriptFunctions/Corporation.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
|
||||
import { OfficeSpace } from "../Corporation/OfficeSpace";
|
||||
import { Employee } from "../Corporation/Employee";
|
||||
import { Product } from "../Corporation/Product";
|
||||
import { Material } from "../Corporation/Material";
|
||||
import { Warehouse } from "../Corporation/Warehouse";
|
||||
import { IIndustry } from "../Corporation/IIndustry";
|
||||
|
||||
import {
|
||||
NewIndustry,
|
||||
NewCity,
|
||||
UnlockUpgrade,
|
||||
LevelUpgrade,
|
||||
IssueDividends,
|
||||
SellMaterial,
|
||||
SellProduct,
|
||||
SetSmartSupply,
|
||||
BuyMaterial,
|
||||
AssignJob,
|
||||
UpgradeOfficeSize,
|
||||
ThrowParty,
|
||||
PurchaseWarehouse,
|
||||
UpgradeWarehouse,
|
||||
BuyCoffee,
|
||||
HireAdVert,
|
||||
MakeProduct,
|
||||
Research,
|
||||
ExportMaterial,
|
||||
CancelExportMaterial,
|
||||
SetMaterialMarketTA1,
|
||||
SetMaterialMarketTA2,
|
||||
SetProductMarketTA1,
|
||||
SetProductMarketTA2,
|
||||
} from "../Corporation/Actions";
|
||||
import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades";
|
||||
import { CorporationUpgrades } from "../Corporation/data/CorporationUpgrades";
|
||||
|
||||
export interface INetscriptCorporation {
|
||||
expandIndustry(industryName: any, divisionName: any): any;
|
||||
expandCity(divisionName: any, cityName: any): any;
|
||||
unlockUpgrade(upgradeName: any): any;
|
||||
levelUpgrade(upgradeName: any): any;
|
||||
issueDividends(percent: any): any;
|
||||
sellMaterial(divisionName: any, cityName: any, materialName: any, amt: any, price: any): any;
|
||||
sellProduct(divisionName: any, cityName: any, productName: any, amt: any, price: any, all: any): any;
|
||||
discontinueProduct(divisionName: any, productName: any): any;
|
||||
setSmartSupply(divisionName: any, cityName: any, enabled: any): any;
|
||||
buyMaterial(divisionName: any, cityName: any, materialName: any, amt: any): any;
|
||||
employees(divisionName: any, cityName: any): any;
|
||||
assignJob(divisionName: any, cityName: any, employeeName: any, job: any): any;
|
||||
hireEmployee(divisionName: any, cityName: any): any;
|
||||
upgradeOfficeSize(divisionName: any, cityName: any, size: any): any;
|
||||
throwParty(divisionName: any, cityName: any, costPerEmployee: any): any;
|
||||
purchaseWarehouse(divisionName: any, cityName: any): any;
|
||||
upgradeWarehouse(divisionName: any, cityName: any): any;
|
||||
buyCoffee(divisionName: any, cityName: any): any;
|
||||
hireAdVert(divisionName: any): any;
|
||||
makeProduct(divisionName: any, cityName: any, productName: any, designInvest: any, marketingInvest: any): any;
|
||||
research(divisionName: any, researchName: any): any;
|
||||
exportMaterial(
|
||||
sourceDivision: any,
|
||||
sourceCity: any,
|
||||
targetDivision: any,
|
||||
targetCity: any,
|
||||
materialName: any,
|
||||
amt: any,
|
||||
): any;
|
||||
cancelExportMaterial(
|
||||
sourceDivision: any,
|
||||
sourceCity: any,
|
||||
targetDivision: any,
|
||||
targetCity: any,
|
||||
materialName: any,
|
||||
amt: any,
|
||||
): any;
|
||||
setMaterialMarketTA1(divisionName: any, cityName: any, materialName: any, on: any): any;
|
||||
setMaterialMarketTA2(divisionName: any, cityName: any, materialName: any, on: any): any;
|
||||
setProductMarketTA1(divisionName: any, productName: any, on: any): any;
|
||||
setProductMarketTA2(divisionName: any, productName: any, on: any): any;
|
||||
getDivision(divisionName: any): any;
|
||||
getOffice(divisionName: any, cityName: any): any;
|
||||
getWarehouse(divisionName: any, cityName: any): any;
|
||||
getMaterial(divisionName: any, cityName: any, materialName: any): any;
|
||||
getProduct(divisionName: any, productName: any): any;
|
||||
getEmployee(divisionName: any, cityName: any, employeeName: any): any;
|
||||
}
|
||||
|
||||
export function NetscriptCorporation(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptCorporation {
|
||||
function getDivision(divisionName: any): IIndustry {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("cannot be called without a corporation");
|
||||
const division = corporation.divisions.find((div) => div.name === divisionName);
|
||||
if (division === undefined) throw new Error(`No division named '${divisionName}'`);
|
||||
return division;
|
||||
}
|
||||
|
||||
function getOffice(divisionName: any, cityName: any): OfficeSpace {
|
||||
const division = getDivision(divisionName);
|
||||
if (!(cityName in division.offices)) throw new Error(`Invalid city name '${cityName}'`);
|
||||
const office = division.offices[cityName];
|
||||
if (office === 0) throw new Error(`${division.name} has not expanded to '${cityName}'`);
|
||||
return office;
|
||||
}
|
||||
|
||||
function getWarehouse(divisionName: any, cityName: any): Warehouse {
|
||||
const division = getDivision(divisionName);
|
||||
if (!(cityName in division.warehouses)) throw new Error(`Invalid city name '${cityName}'`);
|
||||
const warehouse = division.warehouses[cityName];
|
||||
if (warehouse === 0) throw new Error(`${division.name} has not expanded to '${cityName}'`);
|
||||
return warehouse;
|
||||
}
|
||||
|
||||
function getMaterial(divisionName: any, cityName: any, materialName: any): Material {
|
||||
const warehouse = getWarehouse(divisionName, cityName);
|
||||
const material = warehouse.materials[materialName];
|
||||
if (material === undefined) throw new Error(`Invalid material name: '${materialName}'`);
|
||||
return material;
|
||||
}
|
||||
|
||||
function getProduct(divisionName: any, productName: any): Product {
|
||||
const division = getDivision(divisionName);
|
||||
const product = division.products[productName];
|
||||
if (product === undefined) throw new Error(`Invalid product name: '${productName}'`);
|
||||
return product;
|
||||
}
|
||||
|
||||
function getEmployee(divisionName: any, cityName: any, employeeName: any): Employee {
|
||||
const office = getOffice(divisionName, cityName);
|
||||
const employee = office.employees.find((e) => e.name === employeeName);
|
||||
if (employee === undefined) throw new Error(`Invalid employee name: '${employeeName}'`);
|
||||
return employee;
|
||||
}
|
||||
// Hi, if you're reading this you're a bit nosy.
|
||||
// There's a corporation API but it's very imbalanced right now.
|
||||
// It's here so players can test with if they want.
|
||||
return {
|
||||
expandIndustry: function (industryName: any, divisionName: any): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
NewIndustry(corporation, industryName, divisionName);
|
||||
},
|
||||
expandCity: function (divisionName: any, cityName: any): any {
|
||||
const division = getDivision(divisionName);
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
NewCity(corporation, division, cityName);
|
||||
},
|
||||
unlockUpgrade: function (upgradeName: any): any {
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade[2] === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
UnlockUpgrade(corporation, upgrade);
|
||||
},
|
||||
levelUpgrade: function (upgradeName: any): any {
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade[4] === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
LevelUpgrade(corporation, upgrade);
|
||||
},
|
||||
issueDividends: function (percent: any): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
IssueDividends(corporation, percent);
|
||||
},
|
||||
sellMaterial: function (divisionName: any, cityName: any, materialName: any, amt: any, price: any): any {
|
||||
const material = getMaterial(divisionName, cityName, materialName);
|
||||
SellMaterial(material, amt, price);
|
||||
},
|
||||
sellProduct: function (divisionName: any, cityName: any, productName: any, amt: any, price: any, all: any): any {
|
||||
const product = getProduct(divisionName, productName);
|
||||
SellProduct(product, cityName, amt, price, all);
|
||||
},
|
||||
discontinueProduct: function (divisionName: any, productName: any): any {
|
||||
getDivision(divisionName).discontinueProduct(getProduct(divisionName, productName));
|
||||
},
|
||||
setSmartSupply: function (divisionName: any, cityName: any, enabled: any): any {
|
||||
const warehouse = getWarehouse(divisionName, cityName);
|
||||
SetSmartSupply(warehouse, enabled);
|
||||
},
|
||||
// setSmartSupplyUseLeftovers: function (): any {},
|
||||
buyMaterial: function (divisionName: any, cityName: any, materialName: any, amt: any): any {
|
||||
const material = getMaterial(divisionName, cityName, materialName);
|
||||
BuyMaterial(material, amt);
|
||||
},
|
||||
employees: function (divisionName: any, cityName: any): any {
|
||||
const office = getOffice(divisionName, cityName);
|
||||
return office.employees.map((e) => Object.assign({}, e));
|
||||
},
|
||||
assignJob: function (divisionName: any, cityName: any, employeeName: any, job: any): any {
|
||||
const employee = getEmployee(divisionName, cityName, employeeName);
|
||||
AssignJob(employee, job);
|
||||
},
|
||||
hireEmployee: function (divisionName: any, cityName: any): any {
|
||||
const office = getOffice(divisionName, cityName);
|
||||
office.hireRandomEmployee();
|
||||
},
|
||||
upgradeOfficeSize: function (divisionName: any, cityName: any, size: any): any {
|
||||
const office = getOffice(divisionName, cityName);
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
UpgradeOfficeSize(corporation, office, size);
|
||||
},
|
||||
throwParty: function (divisionName: any, cityName: any, costPerEmployee: any): any {
|
||||
const office = getOffice(divisionName, cityName);
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
ThrowParty(corporation, office, costPerEmployee);
|
||||
},
|
||||
purchaseWarehouse: function (divisionName: any, cityName: any): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
PurchaseWarehouse(corporation, getDivision(divisionName), cityName);
|
||||
},
|
||||
upgradeWarehouse: function (divisionName: any, cityName: any): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName));
|
||||
},
|
||||
buyCoffee: function (divisionName: any, cityName: any): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
BuyCoffee(corporation, getDivision(divisionName), getOffice(divisionName, cityName));
|
||||
},
|
||||
hireAdVert: function (divisionName: any): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
HireAdVert(corporation, getDivision(divisionName), getOffice(divisionName, "Sector-12"));
|
||||
},
|
||||
makeProduct: function (
|
||||
divisionName: any,
|
||||
cityName: any,
|
||||
productName: any,
|
||||
designInvest: any,
|
||||
marketingInvest: any,
|
||||
): any {
|
||||
const corporation = player.corporation;
|
||||
if (corporation === null) throw new Error("Should not be called without a corporation");
|
||||
MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest);
|
||||
},
|
||||
research: function (divisionName: any, researchName: any): any {
|
||||
Research(getDivision(divisionName), researchName);
|
||||
},
|
||||
exportMaterial: function (
|
||||
sourceDivision: any,
|
||||
sourceCity: any,
|
||||
targetDivision: any,
|
||||
targetCity: any,
|
||||
materialName: any,
|
||||
amt: any,
|
||||
): any {
|
||||
ExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "");
|
||||
},
|
||||
cancelExportMaterial: function (
|
||||
sourceDivision: any,
|
||||
sourceCity: any,
|
||||
targetDivision: any,
|
||||
targetCity: any,
|
||||
materialName: any,
|
||||
amt: any,
|
||||
): any {
|
||||
CancelExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "");
|
||||
},
|
||||
setMaterialMarketTA1: function (divisionName: any, cityName: any, materialName: any, on: any): any {
|
||||
SetMaterialMarketTA1(getMaterial(divisionName, cityName, materialName), on);
|
||||
},
|
||||
setMaterialMarketTA2: function (divisionName: any, cityName: any, materialName: any, on: any) {
|
||||
SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on);
|
||||
},
|
||||
setProductMarketTA1: function (divisionName: any, productName: any, on: any): any {
|
||||
SetProductMarketTA1(getProduct(divisionName, productName), on);
|
||||
},
|
||||
setProductMarketTA2: function (divisionName: any, productName: any, on: any) {
|
||||
SetProductMarketTA2(getProduct(divisionName, productName), on);
|
||||
},
|
||||
// If you modify these objects you will affect them for real, it's not
|
||||
// copies.
|
||||
getDivision: function (divisionName: any): any {
|
||||
return getDivision(divisionName);
|
||||
},
|
||||
getOffice: function (divisionName: any, cityName: any): any {
|
||||
return getOffice(divisionName, cityName);
|
||||
},
|
||||
getWarehouse: function (divisionName: any, cityName: any): any {
|
||||
return getWarehouse(divisionName, cityName);
|
||||
},
|
||||
getMaterial: function (divisionName: any, cityName: any, materialName: any): any {
|
||||
return getMaterial(divisionName, cityName, materialName);
|
||||
},
|
||||
getProduct: function (divisionName: any, productName: any): any {
|
||||
return getProduct(divisionName, productName);
|
||||
},
|
||||
getEmployee: function (divisionName: any, cityName: any, employeeName: any): any {
|
||||
return getEmployee(divisionName, cityName, employeeName);
|
||||
},
|
||||
};
|
||||
}
|
||||
37
src/NetscriptFunctions/Flags.ts
Normal file
37
src/NetscriptFunctions/Flags.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { toNative } from "./toNative";
|
||||
import * as libarg from "arg";
|
||||
|
||||
export function Flags(vargs: string[]): any {
|
||||
return function (data: any): any {
|
||||
data = toNative(data);
|
||||
// We always want the help flag.
|
||||
const args: {
|
||||
[key: string]: any;
|
||||
} = {};
|
||||
|
||||
for (const d of data) {
|
||||
let t: any = String;
|
||||
if (typeof d[1] === "number") {
|
||||
t = Number;
|
||||
} else if (typeof d[1] === "boolean") {
|
||||
t = Boolean;
|
||||
} else if (Array.isArray(d[1])) {
|
||||
t = [String];
|
||||
}
|
||||
const numDashes = d[0].length > 1 ? 2 : 1;
|
||||
args["-".repeat(numDashes) + d[0]] = t;
|
||||
}
|
||||
const ret = libarg(args, { argv: vargs });
|
||||
for (const d of data) {
|
||||
if (!ret.hasOwnProperty("--" + d[0]) || !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];
|
||||
const numDashes = key.length === 2 ? 1 : 2;
|
||||
ret[key.slice(numDashes)] = value;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
187
src/NetscriptFunctions/Formulas.ts
Normal file
187
src/NetscriptFunctions/Formulas.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { calculateServerGrowth } from "../Server/formulas/grow";
|
||||
import {
|
||||
calculateMoneyGainRate,
|
||||
calculateLevelUpgradeCost,
|
||||
calculateRamUpgradeCost,
|
||||
calculateCoreUpgradeCost,
|
||||
calculateNodeCost,
|
||||
} from "../Hacknet/formulas/HacknetNodes";
|
||||
import {
|
||||
calculateHashGainRate as HScalculateHashGainRate,
|
||||
calculateLevelUpgradeCost as HScalculateLevelUpgradeCost,
|
||||
calculateRamUpgradeCost as HScalculateRamUpgradeCost,
|
||||
calculateCoreUpgradeCost as HScalculateCoreUpgradeCost,
|
||||
calculateCacheUpgradeCost as HScalculateCacheUpgradeCost,
|
||||
calculateServerCost as HScalculateServerCost,
|
||||
} from "../Hacknet/formulas/HacknetServers";
|
||||
import { HacknetNodeConstants, HacknetServerConstants } from "../Hacknet/data/Constants";
|
||||
import { calculateSkill, calculateExp } from "../PersonObjects/formulas/skill";
|
||||
import {
|
||||
calculateHackingChance,
|
||||
calculateHackingExpGain,
|
||||
calculatePercentMoneyHacked,
|
||||
calculateHackingTime,
|
||||
calculateGrowTime,
|
||||
calculateWeakenTime,
|
||||
} from "../Hacking";
|
||||
|
||||
export interface INetscriptFormulas {
|
||||
basic: {
|
||||
calculateSkill(exp: any, mult?: any): any;
|
||||
calculateExp(skill: any, mult?: any): any;
|
||||
hackChance(server: any, player: any): any;
|
||||
hackExp(server: any, player: any): any;
|
||||
hackPercent(server: any, player: any): any;
|
||||
growPercent(server: any, threads: any, player: any, cores?: any): any;
|
||||
hackTime(server: any, player: any): any;
|
||||
growTime(server: any, player: any): any;
|
||||
weakenTime(server: any, player: any): any;
|
||||
};
|
||||
hacknetNodes: {
|
||||
moneyGainRate(level: any, ram: any, cores: any, mult?: any): any;
|
||||
levelUpgradeCost(startingLevel: any, extraLevels?: any, costMult?: any): any;
|
||||
ramUpgradeCost(startingRam: any, extraLevels?: any, costMult?: any): any;
|
||||
coreUpgradeCost(startingCore: any, extraCores?: any, costMult?: any): any;
|
||||
hacknetNodeCost(n: any, mult: any): any;
|
||||
constants(): any;
|
||||
};
|
||||
hacknetServers: {
|
||||
hashGainRate(level: any, ramUsed: any, maxRam: any, cores: any, mult?: any): any;
|
||||
levelUpgradeCost(startingLevel: any, extraLevels?: any, costMult?: any): any;
|
||||
ramUpgradeCost(startingRam: any, extraLevels?: any, costMult?: any): any;
|
||||
coreUpgradeCost(startingCore: any, extraCores?: any, costMult?: any): any;
|
||||
cacheUpgradeCost(startingCache: any, extraCache?: any): any;
|
||||
hashUpgradeCost(upgName: any, level: any): any;
|
||||
hacknetServerCost(n: any, mult: any): any;
|
||||
constants(): any;
|
||||
};
|
||||
}
|
||||
|
||||
export function NetscriptFormulas(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptFormulas {
|
||||
const checkFormulasAccess = function (func: any, n: any): void {
|
||||
if (
|
||||
(player.sourceFileLvl(5) < 1 && player.bitNodeN !== 5) ||
|
||||
(player.sourceFileLvl(n) < 1 && player.bitNodeN !== n)
|
||||
) {
|
||||
let extra = "";
|
||||
if (n !== 5) {
|
||||
extra = ` and Source-File ${n}-1`;
|
||||
}
|
||||
throw helper.makeRuntimeErrorMsg(`formulas.${func}`, `Requires Source-File 5-1${extra} to run.`);
|
||||
}
|
||||
};
|
||||
return {
|
||||
basic: {
|
||||
calculateSkill: function (exp: any, mult: any = 1): any {
|
||||
checkFormulasAccess("basic.calculateSkill", 5);
|
||||
return calculateSkill(exp, mult);
|
||||
},
|
||||
calculateExp: function (skill: any, mult: any = 1): any {
|
||||
checkFormulasAccess("basic.calculateExp", 5);
|
||||
return calculateExp(skill, mult);
|
||||
},
|
||||
hackChance: function (server: any, player: any): any {
|
||||
checkFormulasAccess("basic.hackChance", 5);
|
||||
return calculateHackingChance(server, player);
|
||||
},
|
||||
hackExp: function (server: any, player: any): any {
|
||||
checkFormulasAccess("basic.hackExp", 5);
|
||||
return calculateHackingExpGain(server, player);
|
||||
},
|
||||
hackPercent: function (server: any, player: any): any {
|
||||
checkFormulasAccess("basic.hackPercent", 5);
|
||||
return calculatePercentMoneyHacked(server, player);
|
||||
},
|
||||
growPercent: function (server: any, threads: any, player: any, cores: any = 1): any {
|
||||
checkFormulasAccess("basic.growPercent", 5);
|
||||
return calculateServerGrowth(server, threads, player, cores);
|
||||
},
|
||||
hackTime: function (server: any, player: any): any {
|
||||
checkFormulasAccess("basic.hackTime", 5);
|
||||
return calculateHackingTime(server, player);
|
||||
},
|
||||
growTime: function (server: any, player: any): any {
|
||||
checkFormulasAccess("basic.growTime", 5);
|
||||
return calculateGrowTime(server, player);
|
||||
},
|
||||
weakenTime: function (server: any, player: any): any {
|
||||
checkFormulasAccess("basic.weakenTime", 5);
|
||||
return calculateWeakenTime(server, player);
|
||||
},
|
||||
},
|
||||
hacknetNodes: {
|
||||
moneyGainRate: function (level: any, ram: any, cores: any, mult: any = 1): any {
|
||||
checkFormulasAccess("hacknetNodes.moneyGainRate", 5);
|
||||
return calculateMoneyGainRate(level, ram, cores, mult);
|
||||
},
|
||||
levelUpgradeCost: function (startingLevel: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
checkFormulasAccess("hacknetNodes.levelUpgradeCost", 5);
|
||||
return calculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
|
||||
},
|
||||
ramUpgradeCost: function (startingRam: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
checkFormulasAccess("hacknetNodes.ramUpgradeCost", 5);
|
||||
return calculateRamUpgradeCost(startingRam, extraLevels, costMult);
|
||||
},
|
||||
coreUpgradeCost: function (startingCore: any, extraCores: any = 1, costMult: any = 1): any {
|
||||
checkFormulasAccess("hacknetNodes.coreUpgradeCost", 5);
|
||||
return calculateCoreUpgradeCost(startingCore, extraCores, costMult);
|
||||
},
|
||||
hacknetNodeCost: function (n: any, mult: any): any {
|
||||
checkFormulasAccess("hacknetNodes.hacknetNodeCost", 5);
|
||||
return calculateNodeCost(n, mult);
|
||||
},
|
||||
constants: function (): any {
|
||||
checkFormulasAccess("hacknetNodes.constants", 5);
|
||||
return Object.assign({}, HacknetNodeConstants);
|
||||
},
|
||||
},
|
||||
hacknetServers: {
|
||||
hashGainRate: function (level: any, ramUsed: any, maxRam: any, cores: any, mult: any = 1): any {
|
||||
checkFormulasAccess("hacknetServers.hashGainRate", 9);
|
||||
return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult);
|
||||
},
|
||||
levelUpgradeCost: function (startingLevel: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
checkFormulasAccess("hacknetServers.levelUpgradeCost", 9);
|
||||
return HScalculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
|
||||
},
|
||||
ramUpgradeCost: function (startingRam: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
checkFormulasAccess("hacknetServers.ramUpgradeCost", 9);
|
||||
return HScalculateRamUpgradeCost(startingRam, extraLevels, costMult);
|
||||
},
|
||||
coreUpgradeCost: function (startingCore: any, extraCores: any = 1, costMult: any = 1): any {
|
||||
checkFormulasAccess("hacknetServers.coreUpgradeCost", 9);
|
||||
return HScalculateCoreUpgradeCost(startingCore, extraCores, costMult);
|
||||
},
|
||||
cacheUpgradeCost: function (startingCache: any, extraCache: any = 1): any {
|
||||
checkFormulasAccess("hacknetServers.cacheUpgradeCost", 9);
|
||||
return HScalculateCacheUpgradeCost(startingCache, extraCache);
|
||||
},
|
||||
hashUpgradeCost: function (upgName: any, level: any): any {
|
||||
checkFormulasAccess("hacknetServers.hashUpgradeCost", 9);
|
||||
const upg = player.hashManager.getUpgrade(upgName);
|
||||
if (!upg) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"formulas.hacknetServers.calculateHashUpgradeCost",
|
||||
`Invalid Hash Upgrade: ${upgName}`,
|
||||
);
|
||||
}
|
||||
return upg.getCost(level);
|
||||
},
|
||||
hacknetServerCost: function (n: any, mult: any): any {
|
||||
checkFormulasAccess("hacknetServers.hacknetServerCost", 9);
|
||||
return HScalculateServerCost(n, mult);
|
||||
},
|
||||
constants: function (): any {
|
||||
checkFormulasAccess("hacknetServers.constants", 9);
|
||||
return Object.assign({}, HacknetServerConstants);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
|
||||
export interface INetscriptHelper {
|
||||
updateDynamicRam(functionName: string, ram: number): void;
|
||||
makeRuntimeErrorMsg(functionName: string, message: string): void;
|
||||
string(funcName: string, argName: string, v: any): string;
|
||||
number(funcName: string, argName: string, v: any): number;
|
||||
boolean(v: any): boolean;
|
||||
getServer(ip: any, fn: any): BaseServer;
|
||||
checkSingularityAccess(func: string, n: number): void;
|
||||
getFaction(func: string, name: string): Faction;
|
||||
}
|
||||
|
||||
377
src/NetscriptFunctions/StockMarket.ts
Normal file
377
src/NetscriptFunctions/StockMarket.ts
Normal file
@@ -0,0 +1,377 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling";
|
||||
import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder } from "../StockMarket/StockMarket";
|
||||
import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers";
|
||||
import { OrderTypes } from "../StockMarket/data/OrderTypes";
|
||||
import { PositionTypes } from "../StockMarket/data/PositionTypes";
|
||||
import { StockSymbols } from "../StockMarket/data/StockSymbols";
|
||||
import { getStockMarket4SDataCost, getStockMarket4STixApiCost } from "../StockMarket/StockMarketCosts";
|
||||
import { Stock } from "../StockMarket/Stock";
|
||||
|
||||
export interface INetscriptStockMarket {
|
||||
getStockSymbols(): any;
|
||||
getStockPrice(symbol: any): any;
|
||||
getStockAskPrice(symbol: any): any;
|
||||
getStockBidPrice(symbol: any): any;
|
||||
getStockPosition(symbol: any): any;
|
||||
getStockMaxShares(symbol: any): any;
|
||||
getStockPurchaseCost(symbol: any, shares: any, posType: any): any;
|
||||
getStockSaleGain(symbol: any, shares: any, posType: any): any;
|
||||
buyStock(symbol: any, shares: any): any;
|
||||
sellStock(symbol: any, shares: any): any;
|
||||
shortStock(symbol: any, shares: any): any;
|
||||
sellShort(symbol: any, shares: any): any;
|
||||
placeOrder(symbol: any, shares: any, price: any, type: any, pos: any): any;
|
||||
cancelOrder(symbol: any, shares: any, price: any, type: any, pos: any): any;
|
||||
getOrders(): any;
|
||||
getStockVolatility(symbol: any): any;
|
||||
getStockForecast(symbol: any): any;
|
||||
purchase4SMarketData(): void;
|
||||
purchase4SMarketDataTixApi(): void;
|
||||
}
|
||||
|
||||
export function NetscriptStockMarket(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptStockMarket {
|
||||
/**
|
||||
* Checks if the player has TIX API access. Throws an error if the player does not
|
||||
*/
|
||||
const checkTixApiAccess = function (callingFn: string): void {
|
||||
if (!player.hasWseAccount) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, `You don't have WSE Access! Cannot use ${callingFn}()`);
|
||||
}
|
||||
if (!player.hasTixApiAccess) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, `You don't have TIX API Access! Cannot use ${callingFn}()`);
|
||||
}
|
||||
};
|
||||
|
||||
const getStockFromSymbol = function (symbol: string, callingFn: string): Stock {
|
||||
const stock = SymbolToStockMap[symbol];
|
||||
if (stock == null) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, `Invalid stock symbol: '${symbol}'`);
|
||||
}
|
||||
|
||||
return stock;
|
||||
};
|
||||
return {
|
||||
getStockSymbols: function (): any {
|
||||
helper.updateDynamicRam("getStockSymbols", getRamCost("getStockSymbols"));
|
||||
checkTixApiAccess("getStockSymbols");
|
||||
return Object.values(StockSymbols);
|
||||
},
|
||||
getStockPrice: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockPrice", getRamCost("getStockPrice"));
|
||||
checkTixApiAccess("getStockPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getStockPrice");
|
||||
|
||||
return stock.price;
|
||||
},
|
||||
getStockAskPrice: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockAskPrice", getRamCost("getStockAskPrice"));
|
||||
checkTixApiAccess("getStockAskPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getStockAskPrice");
|
||||
|
||||
return stock.getAskPrice();
|
||||
},
|
||||
getStockBidPrice: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockBidPrice", getRamCost("getStockBidPrice"));
|
||||
checkTixApiAccess("getStockBidPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getStockBidPrice");
|
||||
|
||||
return stock.getBidPrice();
|
||||
},
|
||||
getStockPosition: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockPosition", getRamCost("getStockPosition"));
|
||||
checkTixApiAccess("getStockPosition");
|
||||
const stock = SymbolToStockMap[symbol];
|
||||
if (stock == null) {
|
||||
throw helper.makeRuntimeErrorMsg("getStockPosition", `Invalid stock symbol: ${symbol}`);
|
||||
}
|
||||
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
||||
},
|
||||
getStockMaxShares: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockMaxShares", getRamCost("getStockMaxShares"));
|
||||
checkTixApiAccess("getStockMaxShares");
|
||||
const stock = getStockFromSymbol(symbol, "getStockMaxShares");
|
||||
|
||||
return stock.maxShares;
|
||||
},
|
||||
getStockPurchaseCost: function (symbol: any, shares: any, posType: any): any {
|
||||
helper.updateDynamicRam("getStockPurchaseCost", getRamCost("getStockPurchaseCost"));
|
||||
checkTixApiAccess("getStockPurchaseCost");
|
||||
const stock = getStockFromSymbol(symbol, "getStockPurchaseCost");
|
||||
shares = Math.round(shares);
|
||||
|
||||
let pos;
|
||||
const sanitizedPosType = posType.toLowerCase();
|
||||
if (sanitizedPosType.includes("l")) {
|
||||
pos = PositionTypes.Long;
|
||||
} else if (sanitizedPosType.includes("s")) {
|
||||
pos = PositionTypes.Short;
|
||||
} else {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
const res = getBuyTransactionCost(stock, shares, pos);
|
||||
if (res == null) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
getStockSaleGain: function (symbol: any, shares: any, posType: any): any {
|
||||
helper.updateDynamicRam("getStockSaleGain", getRamCost("getStockSaleGain"));
|
||||
checkTixApiAccess("getStockSaleGain");
|
||||
const stock = getStockFromSymbol(symbol, "getStockSaleGain");
|
||||
shares = Math.round(shares);
|
||||
|
||||
let pos;
|
||||
const sanitizedPosType = posType.toLowerCase();
|
||||
if (sanitizedPosType.includes("l")) {
|
||||
pos = PositionTypes.Long;
|
||||
} else if (sanitizedPosType.includes("s")) {
|
||||
pos = PositionTypes.Short;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const res = getSellTransactionGain(stock, shares, pos);
|
||||
if (res == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
buyStock: function (symbol: any, shares: any): any {
|
||||
helper.updateDynamicRam("buyStock", getRamCost("buyStock"));
|
||||
checkTixApiAccess("buyStock");
|
||||
const stock = getStockFromSymbol(symbol, "buyStock");
|
||||
const res = buyStock(stock, shares, workerScript, {});
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
sellStock: function (symbol: any, shares: any): any {
|
||||
helper.updateDynamicRam("sellStock", getRamCost("sellStock"));
|
||||
checkTixApiAccess("sellStock");
|
||||
const stock = getStockFromSymbol(symbol, "sellStock");
|
||||
const res = sellStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
shortStock: function (symbol: any, shares: any): any {
|
||||
helper.updateDynamicRam("shortStock", getRamCost("shortStock"));
|
||||
checkTixApiAccess("shortStock");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 1) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"shortStock",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "shortStock");
|
||||
const res = shortStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
sellShort: function (symbol: any, shares: any): any {
|
||||
helper.updateDynamicRam("sellShort", getRamCost("sellShort"));
|
||||
checkTixApiAccess("sellShort");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 1) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sellShort",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "sellShort");
|
||||
const res = sellShort(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
placeOrder: function (symbol: any, shares: any, price: any, type: any, pos: any): any {
|
||||
helper.updateDynamicRam("placeOrder", getRamCost("placeOrder"));
|
||||
checkTixApiAccess("placeOrder");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"placeOrder",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "placeOrder");
|
||||
|
||||
let orderType;
|
||||
let orderPos;
|
||||
const ltype = type.toLowerCase();
|
||||
if (ltype.includes("limit") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.LimitBuy;
|
||||
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.LimitSell;
|
||||
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.StopBuy;
|
||||
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.StopSell;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid order type: ${type}`);
|
||||
}
|
||||
|
||||
const lpos = pos.toLowerCase();
|
||||
if (lpos.includes("l")) {
|
||||
orderPos = PositionTypes.Long;
|
||||
} else if (lpos.includes("s")) {
|
||||
orderPos = PositionTypes.Short;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid position type: ${pos}`);
|
||||
}
|
||||
|
||||
return placeOrder(stock, shares, price, orderType, orderPos, workerScript);
|
||||
},
|
||||
cancelOrder: function (symbol: any, shares: any, price: any, type: any, pos: any): any {
|
||||
helper.updateDynamicRam("cancelOrder", getRamCost("cancelOrder"));
|
||||
checkTixApiAccess("cancelOrder");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"cancelOrder",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "cancelOrder");
|
||||
if (isNaN(shares) || isNaN(price)) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"cancelOrder",
|
||||
`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`,
|
||||
);
|
||||
}
|
||||
let orderType;
|
||||
let orderPos;
|
||||
const ltype = type.toLowerCase();
|
||||
if (ltype.includes("limit") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.LimitBuy;
|
||||
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.LimitSell;
|
||||
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.StopBuy;
|
||||
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.StopSell;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid order type: ${type}`);
|
||||
}
|
||||
|
||||
const lpos = pos.toLowerCase();
|
||||
if (lpos.includes("l")) {
|
||||
orderPos = PositionTypes.Long;
|
||||
} else if (lpos.includes("s")) {
|
||||
orderPos = PositionTypes.Short;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid position type: ${pos}`);
|
||||
}
|
||||
const params = {
|
||||
stock: stock,
|
||||
shares: shares,
|
||||
price: price,
|
||||
type: orderType,
|
||||
pos: orderPos,
|
||||
};
|
||||
return cancelOrder(params, workerScript);
|
||||
},
|
||||
getOrders: function (): any {
|
||||
helper.updateDynamicRam("getOrders", getRamCost("getOrders"));
|
||||
checkTixApiAccess("getOrders");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"getOrders",
|
||||
"You must either be in BitNode-8 or have Source-File 8 Level 3.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const orders: any = {};
|
||||
|
||||
const stockMarketOrders = StockMarket["Orders"];
|
||||
for (const symbol in stockMarketOrders) {
|
||||
const orderBook = stockMarketOrders[symbol];
|
||||
if (orderBook.constructor === Array && orderBook.length > 0) {
|
||||
orders[symbol] = [];
|
||||
for (let i = 0; i < orderBook.length; ++i) {
|
||||
orders[symbol].push({
|
||||
shares: orderBook[i].shares,
|
||||
price: orderBook[i].price,
|
||||
type: orderBook[i].type,
|
||||
position: orderBook[i].pos,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return orders;
|
||||
},
|
||||
getStockVolatility: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockVolatility", getRamCost("getStockVolatility"));
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw helper.makeRuntimeErrorMsg("getStockVolatility", "You don't have 4S Market Data TIX API Access!");
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "getStockVolatility");
|
||||
|
||||
return stock.mv / 100; // Convert from percentage to decimal
|
||||
},
|
||||
getStockForecast: function (symbol: any): any {
|
||||
helper.updateDynamicRam("getStockForecast", getRamCost("getStockForecast"));
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw helper.makeRuntimeErrorMsg("getStockForecast", "You don't have 4S Market Data TIX API Access!");
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "getStockForecast");
|
||||
|
||||
let forecast = 50;
|
||||
stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag);
|
||||
return forecast / 100; // Convert from percentage to decimal
|
||||
},
|
||||
purchase4SMarketData: function () {
|
||||
helper.updateDynamicRam("purchase4SMarketData", getRamCost("purchase4SMarketData"));
|
||||
checkTixApiAccess("purchase4SMarketData");
|
||||
|
||||
if (player.has4SData) {
|
||||
workerScript.log("purchase4SMarketData", "Already purchased 4S Market Data.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.money.lt(getStockMarket4SDataCost())) {
|
||||
workerScript.log("purchase4SMarketData", "Not enough money to purchase 4S Market Data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
player.has4SData = true;
|
||||
player.loseMoney(getStockMarket4SDataCost());
|
||||
workerScript.log("purchase4SMarketData", "Purchased 4S Market Data");
|
||||
return true;
|
||||
},
|
||||
purchase4SMarketDataTixApi: function () {
|
||||
helper.updateDynamicRam("purchase4SMarketDataTixApi", getRamCost("purchase4SMarketDataTixApi"));
|
||||
checkTixApiAccess("purchase4SMarketDataTixApi");
|
||||
|
||||
if (player.has4SDataTixApi) {
|
||||
workerScript.log("purchase4SMarketDataTixApi", "Already purchased 4S Market Data TIX API");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.money.lt(getStockMarket4STixApiCost())) {
|
||||
workerScript.log("purchase4SMarketDataTixApi", "Not enough money to purchase 4S Market Data TIX API");
|
||||
return false;
|
||||
}
|
||||
|
||||
player.has4SDataTixApi = true;
|
||||
player.loseMoney(getStockMarket4STixApiCost());
|
||||
workerScript.log("purchase4SMarketDataTixApi", "Purchased 4S Market Data TIX API");
|
||||
return true;
|
||||
},
|
||||
};
|
||||
}
|
||||
36
src/NetscriptFunctions/toNative.ts
Normal file
36
src/NetscriptFunctions/toNative.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Interpreter } from "../ThirdParty/JSInterpreter";
|
||||
|
||||
const defaultInterpreter = new Interpreter("", () => undefined);
|
||||
|
||||
// the acorn interpreter has a bug where it doesn't convert arrays correctly.
|
||||
// so we have to more or less copy it here.
|
||||
export function toNative(pseudoObj: any): any {
|
||||
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: any;
|
||||
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 (const key in pseudoObj.properties) {
|
||||
const val = pseudoObj.properties[key];
|
||||
nativeObj[key] = toNative(val);
|
||||
}
|
||||
}
|
||||
return nativeObj;
|
||||
}
|
||||
@@ -8,6 +8,22 @@ function makeScriptBlob(code: string): Blob {
|
||||
return new Blob([code], { type: "text/javascript" });
|
||||
}
|
||||
|
||||
export function compile(script: Script, scripts: Script[]): void {
|
||||
if (!shouldCompile(script, scripts)) return;
|
||||
// The URL at the top is the one we want to import. It will
|
||||
// recursively import all the other modules in the urlStack.
|
||||
//
|
||||
// Webpack likes to turn the import into a require, which sort of
|
||||
// but not really behaves like import. Particularly, it cannot
|
||||
// load fully dynamic content. So we hide the import from webpack
|
||||
// by placing it inside an eval call.
|
||||
script.markUpdated();
|
||||
const uurls = _getScriptUrls(script, scripts, []);
|
||||
script.url = uurls[uurls.length - 1].url;
|
||||
script.module = new Promise((resolve) => resolve(eval("import(uurls[uurls.length - 1].url)")));
|
||||
script.dependencies = uurls;
|
||||
}
|
||||
|
||||
// Begin executing a user JS script, and return a promise that resolves
|
||||
// or rejects when the script finishes.
|
||||
// - script is a script to execute (see Script.js). We depend only on .filename and .code.
|
||||
@@ -17,23 +33,9 @@ function makeScriptBlob(code: string): Blob {
|
||||
// When the promise returned by this resolves, we'll have finished
|
||||
// running the main function of the script.
|
||||
export async function executeJSScript(scripts: Script[] = [], workerScript: WorkerScript): Promise<void> {
|
||||
let uurls: ScriptUrl[] = [];
|
||||
const script = workerScript.getScript();
|
||||
if (script === null) throw new Error("script is null");
|
||||
if (shouldCompile(script, scripts)) {
|
||||
// The URL at the top is the one we want to import. It will
|
||||
// recursively import all the other modules in the urlStack.
|
||||
//
|
||||
// Webpack likes to turn the import into a require, which sort of
|
||||
// but not really behaves like import. Particularly, it cannot
|
||||
// load fully dynamic content. So we hide the import from webpack
|
||||
// by placing it inside an eval call.
|
||||
script.markUpdated();
|
||||
uurls = _getScriptUrls(script, scripts, []);
|
||||
script.url = uurls[uurls.length - 1].url;
|
||||
script.module = new Promise((resolve) => resolve(eval("import(uurls[uurls.length - 1].url)")));
|
||||
script.dependencies = uurls;
|
||||
}
|
||||
compile(script, scripts);
|
||||
const loadedModule = await script.module;
|
||||
|
||||
const ns = workerScript.env.vars;
|
||||
|
||||
@@ -93,7 +93,7 @@ function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript
|
||||
let result;
|
||||
try {
|
||||
result = f(...args);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
runningFn = null;
|
||||
throw e;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript
|
||||
const importProcessingRes = processNetscript1Imports(code, workerScript);
|
||||
codeWithImports = importProcessingRes.code;
|
||||
codeLineOffset = importProcessingRes.lineOffset;
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
dialogBoxCreate("Error processing Imports in " + workerScript.name + ":<br>" + e);
|
||||
workerScript.env.stopFlag = true;
|
||||
workerScript.running = false;
|
||||
@@ -251,7 +251,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript
|
||||
let interpreter: any;
|
||||
try {
|
||||
interpreter = new Interpreter(codeWithImports, interpreterInitialization, codeLineOffset);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
dialogBoxCreate("Syntax ERROR in " + workerScript.name + ":<br>" + e);
|
||||
workerScript.env.stopFlag = true;
|
||||
workerScript.running = false;
|
||||
@@ -271,7 +271,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript
|
||||
} else {
|
||||
resolve(workerScript);
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
e = e.toString();
|
||||
if (!isScriptErrorMessage(e)) {
|
||||
e = makeRuntimeRejectMsg(workerScript, e);
|
||||
@@ -283,7 +283,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript
|
||||
|
||||
try {
|
||||
runInterpreter();
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (isString(e)) {
|
||||
workerScript.errorMessage = e;
|
||||
return reject(workerScript);
|
||||
@@ -469,11 +469,7 @@ export function startWorkerScript(runningScript: RunningScript, server: BaseServ
|
||||
* @param {Server} server - Server on which the script is to be run
|
||||
* returns {boolean} indicating whether or not the workerScript was successfully added
|
||||
*/
|
||||
export function createAndAddWorkerScript(
|
||||
runningScriptObj: RunningScript,
|
||||
server: BaseServer,
|
||||
parent?: WorkerScript,
|
||||
): boolean {
|
||||
function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseServer, parent?: WorkerScript): boolean {
|
||||
// Update server's ram usage
|
||||
let threads = 1;
|
||||
if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
|
||||
@@ -650,6 +646,11 @@ export function runScriptFromScript(
|
||||
return 0;
|
||||
}
|
||||
|
||||
args = args.map((arg) => {
|
||||
if (typeof arg === "number") return arg;
|
||||
return arg + ""; // force cast to string
|
||||
});
|
||||
|
||||
// Check if the script is already running
|
||||
const runningScriptObj = server.getRunningScript(scriptname, args);
|
||||
if (runningScriptObj != null) {
|
||||
|
||||
@@ -191,6 +191,7 @@ export interface IPlayer {
|
||||
getHomeComputer(): Server;
|
||||
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition | null;
|
||||
getUpgradeHomeRamCost(): number;
|
||||
getUpgradeHomeCoresCost(): number;
|
||||
gotoLocation(to: LocationName): boolean;
|
||||
hasAugmentation(aug: string | Augmentation): boolean;
|
||||
hasCorporation(): boolean;
|
||||
@@ -275,4 +276,5 @@ export interface IPlayer {
|
||||
setBitNodeNumber(n: number): void;
|
||||
getMult(name: string): number;
|
||||
setMult(name: string, mult: number): void;
|
||||
sourceFileLvl(n: number): number;
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ export class PlayerObject implements IPlayer {
|
||||
getHomeComputer: () => Server;
|
||||
getNextCompanyPosition: (company: Company, entryPosType: CompanyPosition) => CompanyPosition | null;
|
||||
getUpgradeHomeRamCost: () => number;
|
||||
getUpgradeHomeCoresCost: () => number;
|
||||
gotoLocation: (to: LocationName) => boolean;
|
||||
hasAugmentation: (aug: string | Augmentation) => boolean;
|
||||
hasCorporation: () => boolean;
|
||||
@@ -282,6 +283,7 @@ export class PlayerObject implements IPlayer {
|
||||
setBitNodeNumber: (n: number) => void;
|
||||
getMult: (name: string) => number;
|
||||
setMult: (name: string, mult: number) => void;
|
||||
sourceFileLvl: (n: number) => number;
|
||||
|
||||
constructor() {
|
||||
//Skills and stats
|
||||
@@ -567,6 +569,7 @@ export class PlayerObject implements IPlayer {
|
||||
this.getCurrentServer = serverMethods.getCurrentServer;
|
||||
this.getHomeComputer = serverMethods.getHomeComputer;
|
||||
this.getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost;
|
||||
this.getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost;
|
||||
this.createHacknetServer = serverMethods.createHacknetServer;
|
||||
this.factionWorkType = "";
|
||||
this.committingCrimeThruSingFn = false;
|
||||
@@ -574,6 +577,7 @@ export class PlayerObject implements IPlayer {
|
||||
|
||||
this.getMult = generalMethods.getMult;
|
||||
this.setMult = generalMethods.setMult;
|
||||
this.sourceFileLvl = generalMethods.sourceFileLvl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,7 @@ import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
|
||||
import React from "react";
|
||||
import { serverMetadata } from "../../Server/data/servers";
|
||||
|
||||
export function init(this: IPlayer): void {
|
||||
/* Initialize Player's home computer */
|
||||
@@ -451,9 +452,8 @@ export function gainIntelligenceExp(this: IPlayer, exp: number): void {
|
||||
}
|
||||
if (SourceFileFlags[5] > 0 || this.intelligence > 0) {
|
||||
this.intelligence_exp += exp;
|
||||
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
|
||||
}
|
||||
|
||||
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
|
||||
}
|
||||
|
||||
//Given a string expression like "str" or "strength", returns the given stat
|
||||
@@ -516,6 +516,7 @@ export function resetWorkStatus(this: IPlayer, generalType?: string, group?: str
|
||||
this.currentWorkFactionDescription = "";
|
||||
this.createProgramName = "";
|
||||
this.className = "";
|
||||
this.workType = "";
|
||||
}
|
||||
|
||||
export function processWorkEarnings(this: IPlayer, numCycles = 1): void {
|
||||
@@ -607,7 +608,9 @@ export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
|
||||
}
|
||||
|
||||
export function cancelationPenalty(this: IPlayer): number {
|
||||
const server = GetServer(this.companyName);
|
||||
const data = serverMetadata.find((s) => s.specialName === this.companyName);
|
||||
if (!data) return 0.5; // Does not have special server.
|
||||
const server = GetServer(data.hostname);
|
||||
if (server instanceof Server) {
|
||||
if (server && server.backdoorInstalled) return 0.75;
|
||||
}
|
||||
@@ -2655,3 +2658,13 @@ export function setMult(this: IPlayer, name: string, mult: number): void {
|
||||
if (!this.hasOwnProperty(name)) return;
|
||||
(this as any)[name] = mult;
|
||||
}
|
||||
|
||||
export function canAccessCotMG(this: IPlayer): boolean {
|
||||
return this.bitNodeN === 13 || SourceFileFlags[13] > 0;
|
||||
}
|
||||
|
||||
export function sourceFileLvl(this: IPlayer, n: number): number {
|
||||
const sf = this.sourceFiles.find((sf) => sf.n === n);
|
||||
if (!sf) return 0;
|
||||
return sf.lvl;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ export function getUpgradeHomeRamCost(this: IPlayer): number {
|
||||
return cost;
|
||||
}
|
||||
|
||||
export function getUpgradeHomeCoresCost(this: IPlayer): number {
|
||||
return 1e9 * Math.pow(7.5, this.getHomeComputer().cpuCores);
|
||||
}
|
||||
|
||||
export function createHacknetServer(this: IPlayer): HacknetServer {
|
||||
const numOwned = this.hacknetNodes.length;
|
||||
const name = `hacknet-node-${numOwned}`;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { EventEmitter } from "../utils/EventEmitter";
|
||||
|
||||
export const PlayerEvents = new EventEmitter<[]>();
|
||||
@@ -1,100 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
export const SleeveFaq = (
|
||||
<>
|
||||
<strong>
|
||||
<u>How do Duplicate Sleeves work?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Duplicate Sleeves are essentially clones. You can use them to perform any work type action, such as working for a
|
||||
company/faction or committing a crime. Having sleeves perform these tasks earns you money, experience, and
|
||||
reputation.
|
||||
<br />
|
||||
<br />
|
||||
Sleeves are their own individuals, which means they each have their own experience and stats.
|
||||
<br />
|
||||
<br />
|
||||
When a sleeve earns experience, it earns experience for itself, the player's original 'consciousness', as well as
|
||||
all of the player's other sleeves.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>What is Synchronization (Sync)?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Synchronization is a measure of how aligned your consciousness is with that of your Duplicate Sleeves. It is a
|
||||
numerical value between 1 and 100, and it affects how much experience is earned when the sleeve is performing a
|
||||
task.
|
||||
<br />
|
||||
<br />
|
||||
Let N be the sleeve's synchronization. When the sleeve earns experience by performing a task, both the sleeve and
|
||||
the player's original host consciousness earn N% of the amount of experience normally earned by the task. All of the
|
||||
player's other sleeves earn ((N/100)^2 * 100)% of the experience.
|
||||
<br />
|
||||
<br />
|
||||
Synchronization can be increased by assigning sleeves to the 'Synchronize' task.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>What is Shock?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeve shock is a measure of how much trauma the sleeve has due to being placed in a new body. It is a numerical
|
||||
value between 0 and 99, where 99 indicates full shock and 0 indicates no shock. Shock affects the amount of
|
||||
experience earned by the sleeve.
|
||||
<br />
|
||||
<br />
|
||||
Sleeve shock slowly decreases over time. You can further increase the rate at which it decreases by assigning
|
||||
sleeves to the 'Shock Recovery' task.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Why can't I work for this company or faction?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Only one of your sleeves can work for a given company/faction a time. To clarify further, if you have two sleeves
|
||||
they can work for two different companies, but they cannot both work for the same company.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Why did my Sleeve stop working?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeves are subject to the same time restrictions as you. This means that they automatically stop working at a
|
||||
company after 8 hours, and stop working for a faction after 20 hours.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>How do I buy Augmentations for my Sleeves?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Your Sleeve needs to have a Shock of 0 in order for you to buy Augmentations for it.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Why can't I buy the X Augmentation for my sleeve?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Certain Augmentations, like Bladeburner-specific ones and NeuroFlux Governor, are not available for sleeves.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>Do sleeves get reset when installing Augmentations or switching BitNodes?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeves are reset when switching BitNodes, but not when installing Augmentations.
|
||||
<br />
|
||||
<br />
|
||||
<strong>
|
||||
<u>What is Memory?</u>
|
||||
</strong>
|
||||
<br />
|
||||
Sleeve memory dictates what a sleeve's synchronization will be when its reset by switching BitNodes. For example, if
|
||||
a sleeve has a memory of 25, then when you switch BitNodes its synchronization will initially be set to 25, rather
|
||||
than 1.
|
||||
<br />
|
||||
<br />
|
||||
Memory can only be increased by purchasing upgrades from The Covenant. It is a persistent stat, meaning it never
|
||||
gets resets back to 1. The maximum possible value for a sleeve's memory is 100.
|
||||
</>
|
||||
);
|
||||
@@ -29,5 +29,4 @@ export function loadPlayer(saveString: string): void {
|
||||
}
|
||||
|
||||
Player.exploits = sanitizeExploits(Player.exploits);
|
||||
console.log(Player.bladeburner);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ function bitFlumeRequirements() {
|
||||
};
|
||||
}
|
||||
|
||||
export interface IProgramCreationParams {
|
||||
interface IProgramCreationParams {
|
||||
key: string;
|
||||
name: string;
|
||||
create: IProgramCreate | null;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Settings } from "./Settings/Settings";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
|
||||
|
||||
import { GameSavedEvents } from "./ui/React/Snackbar";
|
||||
import { SnackbarEvents } from "./ui/React/Snackbar";
|
||||
|
||||
import * as ExportBonus from "./ExportBonus";
|
||||
|
||||
@@ -61,7 +61,7 @@ class BitburnerSaveObject {
|
||||
const saveString = this.getSaveString();
|
||||
|
||||
save(saveString)
|
||||
.then(() => GameSavedEvents.emit())
|
||||
.then(() => SnackbarEvents.emit("Game Saved!", "info"))
|
||||
.catch((err) => console.error(err));
|
||||
}
|
||||
|
||||
@@ -73,9 +73,10 @@ class BitburnerSaveObject {
|
||||
const bn = Player.bitNodeN;
|
||||
const filename = `bitburnerSave_BN${bn}x${SourceFileFlags[bn]}_${epochTime}.json`;
|
||||
const file = new Blob([saveString], { type: "text/plain" });
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
const navigator = window.navigator as any;
|
||||
if (navigator.msSaveOrOpenBlob) {
|
||||
// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else {
|
||||
// Others
|
||||
const a = document.createElement("a"),
|
||||
@@ -153,6 +154,24 @@ function evaluateVersionCompatibility(ver: string): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ver < "0.56.1") {
|
||||
if (anyPlayer.bladeburner === 0) {
|
||||
anyPlayer.bladeburner = null;
|
||||
}
|
||||
if (anyPlayer.gang === 0) {
|
||||
anyPlayer.gang = null;
|
||||
}
|
||||
if (anyPlayer.corporation === 0) {
|
||||
anyPlayer.corporation = null;
|
||||
}
|
||||
// convert all Messages to just filename to save space.
|
||||
const home = anyPlayer.getHomeComputer();
|
||||
for (let i = 0; i < home.messages.length; i++) {
|
||||
if (home.messages[i].filename) {
|
||||
home.messages[i] = home.messages[i].filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadGame(saveString: string): boolean {
|
||||
|
||||
@@ -58,9 +58,10 @@ export class Script {
|
||||
download(): void {
|
||||
const filename = this.filename + ".js";
|
||||
const file = new Blob([this.code], { type: "text/plain" });
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
const navigator = window.navigator as any;
|
||||
if (navigator.msSaveOrOpenBlob) {
|
||||
// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else {
|
||||
// Others
|
||||
const a = document.createElement("a"),
|
||||
@@ -112,6 +113,10 @@ export class Script {
|
||||
this.markUpdated();
|
||||
}
|
||||
|
||||
imports(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Serialize the current object to a JSON save state
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Script", this);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type Position = {
|
||||
interface Position {
|
||||
row: number;
|
||||
column: number;
|
||||
};
|
||||
}
|
||||
|
||||
class PositionTracker {
|
||||
positions: Map<string, Position>;
|
||||
|
||||
@@ -23,6 +23,7 @@ import { Settings } from "../../Settings/Settings";
|
||||
import { iTutorialNextStep, ITutorial, iTutorialSteps } from "../../InteractiveTutorial";
|
||||
import { debounce } from "lodash";
|
||||
import { saveObject } from "../../SaveObject";
|
||||
import { loadThemes } from "./themes";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
import Typography from "@mui/material/Typography";
|
||||
@@ -54,12 +55,13 @@ export function SetupTextEditor(): void {
|
||||
symbols = populate(ns);
|
||||
|
||||
const exclude = ["heart", "break", "exploit", "bypass", "corporation"];
|
||||
symbols = symbols.filter((symbol: string) => !exclude.includes(symbol));
|
||||
symbols = symbols.filter((symbol: string) => !exclude.includes(symbol)).sort();
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
filename: string;
|
||||
code: string;
|
||||
hostname: string;
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
}
|
||||
@@ -74,17 +76,23 @@ interface IProps {
|
||||
// https://www.npmjs.com/package/@monaco-editor/react#development-playground
|
||||
// https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-custom-languages
|
||||
// https://github.com/threehams/typescript-error-guide/blob/master/stories/components/Editor.tsx#L11-L39
|
||||
// https://blog.checklyhq.com/customizing-monaco/
|
||||
|
||||
// These variables are used to reload a script when it's clicked on. Because we
|
||||
// won't have references to the old script.
|
||||
let lastFilename = "";
|
||||
let lastCode = "";
|
||||
let hostname = "";
|
||||
let lastPosition: monaco.Position | null = null;
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
const editorRef = useRef<IStandaloneCodeEditor | null>(null);
|
||||
const [filename, setFilename] = useState(props.filename ? props.filename : lastFilename);
|
||||
const [code, setCode] = useState<string>(props.filename ? props.code : lastCode);
|
||||
hostname = props.filename ? props.hostname : hostname;
|
||||
if (hostname === "") {
|
||||
hostname = props.player.getCurrentServer().hostname;
|
||||
}
|
||||
const [ram, setRAM] = useState("RAM: ???");
|
||||
const [updatingRam, setUpdatingRam] = useState(false);
|
||||
const [optionsOpen, setOptionsOpen] = useState(false);
|
||||
@@ -127,7 +135,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) {
|
||||
//Make sure filename + code properly follow tutorial
|
||||
if (filename !== "n00dles.script") {
|
||||
dialogBoxCreate("Leave the script name as 'n00dles'!");
|
||||
dialogBoxCreate("Leave the script name as 'n00dles.script'!");
|
||||
return;
|
||||
}
|
||||
if (code.replace(/\s/g, "").indexOf("while(true){hack('n00dles');}") == -1) {
|
||||
@@ -141,14 +149,14 @@ export function Root(props: IProps): React.ReactElement {
|
||||
let found = false;
|
||||
for (let i = 0; i < server.scripts.length; i++) {
|
||||
if (filename == server.scripts[i].filename) {
|
||||
server.scripts[i].saveScript(filename, code, props.player.currentServer, server.scripts);
|
||||
server.scripts[i].saveScript(filename, code, hostname, server.scripts);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
const script = new Script();
|
||||
script.saveScript(filename, code, props.player.currentServer, server.scripts);
|
||||
script.saveScript(filename, code, hostname, server.scripts);
|
||||
server.scripts.push(script);
|
||||
}
|
||||
|
||||
@@ -310,19 +318,38 @@ export function Root(props: IProps): React.ReactElement {
|
||||
return { suggestions: suggestions };
|
||||
},
|
||||
});
|
||||
(async function () {
|
||||
// We have to improve the default js language otherwise theme sucks
|
||||
const l = await monaco.languages
|
||||
.getLanguages()
|
||||
.find((l: any) => l.id === "javascript")
|
||||
.loader();
|
||||
l.language.tokenizer.root.unshift(["ns", { token: "ns" }]);
|
||||
for (const symbol of symbols) l.language.tokenizer.root.unshift(["\\." + symbol, { token: "netscriptfunction" }]);
|
||||
const otherKeywords = ["let", "const", "var", "function"];
|
||||
const otherKeyvars = ["true", "false", "null", "undefined"];
|
||||
otherKeywords.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeywords" }]));
|
||||
otherKeyvars.forEach((k) => l.language.tokenizer.root.unshift([k, { token: "otherkeyvars" }]));
|
||||
l.language.tokenizer.root.unshift(["this", { token: "this" }]);
|
||||
})();
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, "netscript.d.ts");
|
||||
monaco.languages.typescript.typescriptDefaults.addExtraLib(libSource, "netscript.d.ts");
|
||||
loadThemes(monaco);
|
||||
}
|
||||
|
||||
// 370px 71%, 725px 85.1%, 1085px 90%, 1300px 91.7%
|
||||
// fuck around in desmos until you find a function
|
||||
const p = 11000 / -window.innerHeight + 100;
|
||||
return (
|
||||
<>
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
<TextField
|
||||
placeholder="filename"
|
||||
type="text"
|
||||
tabIndex={1}
|
||||
value={filename}
|
||||
onChange={onFilenameChange}
|
||||
InputProps={{ startAdornment: <Typography>Script name: </Typography> }}
|
||||
InputProps={{ startAdornment: <Typography>{hostname}:~/</Typography> }}
|
||||
/>
|
||||
<IconButton onClick={() => setOptionsOpen(true)}>
|
||||
<>
|
||||
@@ -335,7 +362,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
beforeMount={beforeMount}
|
||||
onMount={onMount}
|
||||
loading={<Typography>Loading script editor!</Typography>}
|
||||
height="90%"
|
||||
height={p + "%"}
|
||||
defaultLanguage="javascript"
|
||||
defaultValue={code}
|
||||
onChange={updateCode}
|
||||
|
||||
@@ -19,6 +19,10 @@ export async function loadThemes(monaco: { editor: any }): Promise<void> {
|
||||
token: "number",
|
||||
foreground: "ae81ff",
|
||||
},
|
||||
{
|
||||
token: "otherkeyvars",
|
||||
foreground: "ae81ff",
|
||||
},
|
||||
{
|
||||
foreground: "ae81ff",
|
||||
token: "function",
|
||||
@@ -31,11 +35,22 @@ export async function loadThemes(monaco: { editor: any }): Promise<void> {
|
||||
token: "storage.type.function.js",
|
||||
foreground: "ae81ff",
|
||||
},
|
||||
|
||||
// {
|
||||
// foreground: "ae81ff",
|
||||
// token: "entity.name.function",
|
||||
// },
|
||||
{
|
||||
token: "ns",
|
||||
foreground: "97d92b",
|
||||
},
|
||||
{
|
||||
token: "netscriptfunction",
|
||||
foreground: "53d3e4",
|
||||
},
|
||||
{
|
||||
token: "otherkeywords",
|
||||
foreground: "53d3e4",
|
||||
},
|
||||
{
|
||||
token: "this",
|
||||
foreground: "fd971f",
|
||||
},
|
||||
],
|
||||
colors: {
|
||||
"editor.foreground": "#F8F8F2",
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Abstract Base Class for any Server object
|
||||
*/
|
||||
import { CodingContract } from "../CodingContracts";
|
||||
import { Message } from "../Message/Message";
|
||||
import { RunningScript } from "../Script/RunningScript";
|
||||
import { Script } from "../Script/Script";
|
||||
import { isValidFilePath } from "../Terminal/DirectoryHelpers";
|
||||
@@ -61,7 +60,7 @@ export class BaseServer {
|
||||
// For Literature files, this array contains only the filename (string)
|
||||
// For Messages, it contains the actual Message object
|
||||
// TODO Separate literature files into its own property
|
||||
messages: (Message | string)[] = [];
|
||||
messages: string[] = [];
|
||||
|
||||
// Name of company/faction/etc. that this server belongs to.
|
||||
// Optional, not applicable to all Servers
|
||||
|
||||
@@ -132,7 +132,6 @@ export class Server extends BaseServer {
|
||||
const aboveCap = this.moneyMax - softCap;
|
||||
n = 1 + (n - 1) / Math.log(aboveCap) / Math.log(8);
|
||||
}
|
||||
console.log(n);
|
||||
|
||||
this.moneyMax *= n;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,14 @@ export function getPurchaseServerCost(ram: number): number {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return sanitizedRam * CONSTANTS.BaseCostFor1GBOfRamServer * BitNodeMultipliers.PurchasedServerCost;
|
||||
const upg = Math.max(0, Math.log(sanitizedRam) / Math.log(2) - 9);
|
||||
|
||||
return (
|
||||
sanitizedRam *
|
||||
CONSTANTS.BaseCostFor1GBOfRamServer *
|
||||
BitNodeMultipliers.PurchasedServerCost *
|
||||
Math.pow(BitNodeMultipliers.PurchasedServerSoftcap, upg)
|
||||
);
|
||||
}
|
||||
|
||||
export function getPurchaseServerLimit(): number {
|
||||
|
||||
@@ -239,7 +239,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
SuppressMessages: defaultSettings.SuppressMessages,
|
||||
SuppressTravelConfirmation: defaultSettings.SuppressTravelConfirmation,
|
||||
SuppressBladeburnerPopup: defaultSettings.SuppressBladeburnerPopup,
|
||||
MonacoTheme: "vs-dark",
|
||||
MonacoTheme: "monokai",
|
||||
MonacoInsertSpaces: false,
|
||||
MonacoFontSize: 20,
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ export function initSymbolToStockMap(): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function stockMarketCycle(): void {
|
||||
function stockMarketCycle(): void {
|
||||
for (const name in StockMarket) {
|
||||
const stock = StockMarket[name];
|
||||
if (!(stock instanceof Stock)) {
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
export function getStockMarketAccountCost(): number {
|
||||
return CONSTANTS.WSEAccountCost;
|
||||
}
|
||||
|
||||
export function getStockMarketTixApiCost(): number {
|
||||
return CONSTANTS.TIXAPICost;
|
||||
}
|
||||
|
||||
export function getStockMarket4SDataCost(): number {
|
||||
return CONSTANTS.MarketData4SCost * BitNodeMultipliers.FourSigmaMarketDataCost;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
|
||||
type txFn = (stock: Stock, shares: number) => boolean;
|
||||
export type placeOrderFn = (
|
||||
type placeOrderFn = (
|
||||
stock: Stock,
|
||||
shares: number,
|
||||
price: number,
|
||||
|
||||
@@ -39,8 +39,8 @@ enum SelectorOrderType {
|
||||
Stop = "Stop Order",
|
||||
}
|
||||
|
||||
export type txFn = (stock: Stock, shares: number) => boolean;
|
||||
export type placeOrderFn = (
|
||||
type txFn = (stock: Stock, shares: number) => boolean;
|
||||
type placeOrderFn = (
|
||||
stock: Stock,
|
||||
shares: number,
|
||||
price: number,
|
||||
|
||||
@@ -47,7 +47,7 @@ function LongPosition(props: IProps): React.ReactElement {
|
||||
</Box>
|
||||
<Typography>Shares: {numeralWrapper.formatShares(stock.playerShares)}</Typography>
|
||||
<Typography>
|
||||
Average Price: <Money money={stock.playerAvgPx} /> (Total Cost: <Money money={totalCost} />
|
||||
Average Price: <Money money={stock.playerAvgPx} /> (Total Cost: <Money money={totalCost} />)
|
||||
</Typography>
|
||||
<Typography>
|
||||
Profit: <Money money={gains} /> ({numeralWrapper.formatPercentage(percentageGains)})
|
||||
|
||||
@@ -16,8 +16,8 @@ import { PositionTypes } from "../data/PositionTypes";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
|
||||
export type txFn = (stock: Stock, shares: number) => boolean;
|
||||
export type placeOrderFn = (
|
||||
type txFn = (stock: Stock, shares: number) => boolean;
|
||||
type placeOrderFn = (
|
||||
stock: Stock,
|
||||
shares: number,
|
||||
price: number,
|
||||
|
||||
@@ -35,7 +35,7 @@ export function removeTrailingSlash(s: string): string {
|
||||
* Checks whether a string is a valid filename. Only used for the filename itself,
|
||||
* not the entire filepath
|
||||
*/
|
||||
export function isValidFilename(filename: string): boolean {
|
||||
function isValidFilename(filename: string): boolean {
|
||||
// Allows alphanumerics, hyphens, underscores, and percentage signs
|
||||
// Must have a file extension
|
||||
const regex = /^[.a-zA-Z0-9_-]+[.][a-zA-Z0-9]+(?:-\d+(?:\.\d*)?%-INC)?$/;
|
||||
@@ -48,7 +48,7 @@ export function isValidFilename(filename: string): boolean {
|
||||
* Checks whether a string is a valid directory name. Only used for the directory itself,
|
||||
* not an entire path
|
||||
*/
|
||||
export function isValidDirectoryName(name: string): boolean {
|
||||
function isValidDirectoryName(name: string): boolean {
|
||||
// Allows alphanumerics, hyphens, underscores, and percentage signs.
|
||||
// Name can begin with a single period, but otherwise cannot have any
|
||||
const regex = /^.?[a-zA-Z0-9_-]+$/;
|
||||
|
||||
@@ -543,7 +543,6 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
// TODO: remove this once we figure out the height issue.
|
||||
this.outputHistory = [new Output(`Bitburner v${CONSTANTS.Version}`, "primary")];
|
||||
TerminalEvents.emit();
|
||||
TerminalClearEvents.emit();
|
||||
|
||||
@@ -3,7 +3,6 @@ import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { showMessage } from "../../Message/MessageHelpers";
|
||||
import { Message } from "../../Message/Message";
|
||||
import { showLiterature } from "../../Literature/LiteratureHelpers";
|
||||
|
||||
export function cat(
|
||||
@@ -29,12 +28,12 @@ export function cat(
|
||||
for (let i = 0; i < server.messages.length; ++i) {
|
||||
if (filename.endsWith(".lit") && server.messages[i] === filename) {
|
||||
const file = server.messages[i];
|
||||
if (file instanceof Message) throw new Error(".lit file should not be a .msg");
|
||||
if (file.endsWith(".msg")) throw new Error(".lit file should not be a .msg");
|
||||
showLiterature(file);
|
||||
return;
|
||||
} else if (filename.endsWith(".msg")) {
|
||||
const file = server.messages[i] as Message;
|
||||
if (file.filename !== filename) continue;
|
||||
const file = server.messages[i];
|
||||
if (file !== filename) continue;
|
||||
showMessage(file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { Message } from "../../Message/Message";
|
||||
import { getFirstParentDirectory, isValidDirectoryPath, evaluateDirectoryPath } from "../../Terminal/DirectoryHelpers";
|
||||
|
||||
export function ls(
|
||||
@@ -103,8 +102,7 @@ export function ls(
|
||||
for (const script of s.scripts) handleFn(script.filename, allScripts);
|
||||
for (const txt of s.textFiles) handleFn(txt.fn, allTextFiles);
|
||||
for (const contract of s.contracts) handleFn(contract.fn, allContracts);
|
||||
for (const msgOrLit of s.messages)
|
||||
msgOrLit instanceof Message ? handleFn(msgOrLit.filename, allMessages) : handleFn(msgOrLit, allMessages);
|
||||
for (const msgOrLit of s.messages) handleFn(msgOrLit, allMessages);
|
||||
|
||||
// Sort the files/folders alphabetically then print each
|
||||
allPrograms.sort();
|
||||
|
||||
@@ -19,15 +19,6 @@ export function run(
|
||||
} else {
|
||||
const executableName = args[0] + "";
|
||||
|
||||
// Secret Music player!
|
||||
// if (executableName === "musicplayer") {
|
||||
// post(
|
||||
// '<iframe src="https://open.spotify.com/embed/user/danielyxie/playlist/1ORnnL6YNvXOracUaUV2kh" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>',
|
||||
// false,
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Check if its a script or just a program/executable
|
||||
if (isScriptFilename(executableName)) {
|
||||
runScript(terminal, router, player, server, args);
|
||||
|
||||
@@ -34,7 +34,7 @@ export function scp(
|
||||
if (scriptname.endsWith(".lit")) {
|
||||
let found = false;
|
||||
for (let i = 0; i < server.messages.length; ++i) {
|
||||
if (!(server.messages[i] instanceof Message) && server.messages[i] == scriptname) {
|
||||
if (server.messages[i] == scriptname) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@ import { getSubdirectories } from "./DirectoryServerHelpers";
|
||||
|
||||
import { Aliases, GlobalAliases } from "../Alias";
|
||||
import { DarkWebItems } from "../DarkWeb/DarkWebItems";
|
||||
import { Message } from "../Message/Message";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { GetServer, GetAllServers } from "../Server/AllServers";
|
||||
import { ParseCommand, ParseCommands } from "./Parser";
|
||||
import { isScriptFilename } from "../Script/isScriptFilename";
|
||||
import { compile } from "../NetscriptJSEvaluator";
|
||||
import { Flags } from "../NetscriptFunctions/Flags";
|
||||
import * as libarg from "arg";
|
||||
|
||||
// An array of all Terminal commands
|
||||
const commands = [
|
||||
@@ -48,12 +52,12 @@ const commands = [
|
||||
"weaken",
|
||||
];
|
||||
|
||||
export function determineAllPossibilitiesForTabCompletion(
|
||||
export async function determineAllPossibilitiesForTabCompletion(
|
||||
p: IPlayer,
|
||||
input: string,
|
||||
index: number,
|
||||
currPath = "",
|
||||
): string[] {
|
||||
): Promise<string[]> {
|
||||
let allPos: string[] = [];
|
||||
allPos = allPos.concat(Object.keys(GlobalAliases));
|
||||
const currServ = p.getCurrentServer();
|
||||
@@ -71,7 +75,7 @@ export function determineAllPossibilitiesForTabCompletion(
|
||||
|
||||
function addAllLitFiles(): void {
|
||||
for (const file of currServ.messages) {
|
||||
if (!(file instanceof Message)) {
|
||||
if (!file.endsWith(".msg")) {
|
||||
allPos.push(file);
|
||||
}
|
||||
}
|
||||
@@ -79,8 +83,8 @@ export function determineAllPossibilitiesForTabCompletion(
|
||||
|
||||
function addAllMessages(): void {
|
||||
for (const file of currServ.messages) {
|
||||
if (file instanceof Message) {
|
||||
allPos.push(file.filename);
|
||||
if (file.endsWith(".msg")) {
|
||||
allPos.push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,13 +291,58 @@ export function determineAllPossibilitiesForTabCompletion(
|
||||
return allPos;
|
||||
}
|
||||
|
||||
async function scriptAutocomplete(): Promise<string[] | undefined> {
|
||||
if (!isCommand("run")) return;
|
||||
const commands = ParseCommands(input);
|
||||
if (commands.length === 0) return;
|
||||
const command = ParseCommand(commands[commands.length - 1]);
|
||||
const filename = command[1] + "";
|
||||
if (!isScriptFilename(filename)) return; // Not a script.
|
||||
if (filename.endsWith(".script")) return; // Doesn't work with ns1.
|
||||
const script = currServ.scripts.find((script) => script.filename === filename);
|
||||
if (!script) return; // Doesn't exist.
|
||||
if (!script.module) {
|
||||
compile(script, currServ.scripts);
|
||||
}
|
||||
const loadedModule = await script.module;
|
||||
if (!loadedModule.autocomplete) return; // Doesn't have an autocomplete function.
|
||||
|
||||
const runArgs = { "--tail": Boolean, "-t": Number };
|
||||
const flags = libarg(runArgs, {
|
||||
permissive: true,
|
||||
argv: command.slice(2),
|
||||
});
|
||||
const flagFunc = Flags(flags._);
|
||||
let pos: string[] = [];
|
||||
let pos2: string[] = [];
|
||||
pos = pos.concat(
|
||||
loadedModule.autocomplete(
|
||||
{
|
||||
servers: GetAllServers().map((server) => server.hostname),
|
||||
scripts: currServ.scripts.map((script) => script.filename),
|
||||
txts: currServ.textFiles.map((txt) => txt.fn),
|
||||
flags: (schema: any) => {
|
||||
pos2 = schema.map((f: any) => "--" + f[0]);
|
||||
try {
|
||||
return flagFunc(schema);
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
flags._,
|
||||
),
|
||||
);
|
||||
return pos.concat(pos2);
|
||||
}
|
||||
const pos = await scriptAutocomplete();
|
||||
if (pos) return pos;
|
||||
|
||||
if (isCommand("run")) {
|
||||
addAllScripts();
|
||||
addAllPrograms();
|
||||
addAllCodingContracts();
|
||||
addAllDirectories();
|
||||
|
||||
return allPos;
|
||||
}
|
||||
|
||||
if (isCommand("cat")) {
|
||||
|
||||
@@ -44,7 +44,7 @@ export function tabCompletion(
|
||||
} else if (allPossibilities.length === 1) {
|
||||
if (arg === "") {
|
||||
//Autocomplete command
|
||||
val = allPossibilities[0] + " ";
|
||||
val = allPossibilities[0];
|
||||
} else {
|
||||
val = command + " " + allPossibilities[0];
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
|
||||
return () => document.removeEventListener("keydown", keyDown);
|
||||
});
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
async function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): Promise<void> {
|
||||
// Run command.
|
||||
if (event.keyCode === KEY.ENTER && value !== "") {
|
||||
event.preventDefault();
|
||||
@@ -190,7 +190,7 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
|
||||
if (index < -1) {
|
||||
index = 0;
|
||||
}
|
||||
const allPos = determineAllPossibilitiesForTabCompletion(player, copy, index, terminal.cwd());
|
||||
const allPos = await determineAllPossibilitiesForTabCompletion(player, copy, index, terminal.cwd());
|
||||
if (allPos.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -213,8 +213,9 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
|
||||
command = commandArray.join(" ");
|
||||
}
|
||||
|
||||
const newValue = tabCompletion(command, arg, allPos, value);
|
||||
let newValue = tabCompletion(command, arg, allPos, value);
|
||||
if (typeof newValue === "string" && newValue !== "") {
|
||||
if (!newValue.endsWith(" ") && !newValue.endsWith("/") && allPos.length === 1) newValue += " ";
|
||||
saveValue(newValue);
|
||||
}
|
||||
if (Array.isArray(newValue)) {
|
||||
|
||||
@@ -35,9 +35,10 @@ export class TextFile {
|
||||
const filename: string = this.fn;
|
||||
const file: Blob = new Blob([this.text], { type: "text/plain" });
|
||||
/* tslint:disable-next-line:strict-boolean-expressions */
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
const navigator = window.navigator as any;
|
||||
if (navigator.msSaveOrOpenBlob) {
|
||||
// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else {
|
||||
// Others
|
||||
const a: HTMLAnchorElement = document.createElement("a");
|
||||
|
||||
@@ -12,7 +12,7 @@ export type SolverFunc = (data: any, answer: string) => boolean;
|
||||
Requires the 'data' of a Contract as input */
|
||||
export type DescriptionFunc = (data: any) => string;
|
||||
|
||||
export interface ICodingContractTypeMetadata {
|
||||
interface ICodingContractTypeMetadata {
|
||||
desc: DescriptionFunc;
|
||||
difficulty: number;
|
||||
gen: GeneratorFunc;
|
||||
|
||||
@@ -10,11 +10,6 @@ export interface IMap<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs some action, with no returned value.
|
||||
*/
|
||||
export type Action = () => void;
|
||||
|
||||
/**
|
||||
* Contains a method to initialize itself to a known state.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user