mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-29 19:13:49 +01:00
convert all hacknet to ts
This commit is contained in:
parent
c97fece747
commit
b7e07bc7f2
@ -2,366 +2,433 @@ const numSpaces = 4;
|
|||||||
const maxLineLength = 160;
|
const maxLineLength = 160;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
env: {
|
"env": {
|
||||||
es6: true,
|
"es6": true,
|
||||||
node: true,
|
"node": true
|
||||||
},
|
|
||||||
extends: "eslint:recommended",
|
|
||||||
parserOptions: {
|
|
||||||
ecmaFeatures: {
|
|
||||||
experimentalObjectRestSpread: true,
|
|
||||||
},
|
},
|
||||||
ecmaVersion: 8,
|
"extends": "eslint:recommended",
|
||||||
sourceType: "module",
|
"parserOptions": {
|
||||||
},
|
"ecmaFeatures": {
|
||||||
rules: {
|
"experimentalObjectRestSpread": true
|
||||||
"accessor-pairs": [
|
},
|
||||||
"error",
|
"ecmaVersion": 8,
|
||||||
{
|
"sourceType": "module"
|
||||||
getWithoutSet: false,
|
},
|
||||||
setWithoutGet: true,
|
"rules": {
|
||||||
},
|
"accessor-pairs": [
|
||||||
],
|
"error",
|
||||||
"array-bracket-newline": ["error"],
|
{
|
||||||
"array-bracket-spacing": ["error"],
|
"getWithoutSet": false,
|
||||||
"array-callback-return": ["error"],
|
"setWithoutGet": true
|
||||||
"array-element-newline": ["error"],
|
}
|
||||||
"arrow-body-style": ["error"],
|
],
|
||||||
"arrow-parens": ["error"],
|
"array-bracket-newline": ["error"],
|
||||||
"arrow-spacing": ["error"],
|
"array-bracket-spacing": ["error"],
|
||||||
"block-scoped-var": ["error"],
|
"array-callback-return": ["error"],
|
||||||
"block-spacing": ["error"],
|
"array-element-newline": ["error"],
|
||||||
"brace-style": ["error"],
|
"arrow-body-style": ["error"],
|
||||||
"callback-return": ["error"],
|
"arrow-parens": ["error"],
|
||||||
camelcase: ["error"],
|
"arrow-spacing": ["error"],
|
||||||
"capitalized-comments": ["error"],
|
"block-scoped-var": ["error"],
|
||||||
"class-methods-use-this": ["error"],
|
"block-spacing": ["error"],
|
||||||
"comma-dangle": ["error"],
|
"brace-style": ["error"],
|
||||||
"comma-spacing": ["error"],
|
"callback-return": ["error"],
|
||||||
"comma-style": ["error", "last"],
|
"camelcase": ["error"],
|
||||||
complexity: ["error"],
|
"capitalized-comments": ["error"],
|
||||||
"computed-property-spacing": ["error", "never"],
|
"class-methods-use-this": ["error"],
|
||||||
"consistent-return": ["error"],
|
"comma-dangle": ["error"],
|
||||||
"consistent-this": ["error"],
|
"comma-spacing": ["error"],
|
||||||
"constructor-super": ["error"],
|
"comma-style": [
|
||||||
curly: ["error"],
|
"error",
|
||||||
"default-case": ["error"],
|
"last"
|
||||||
"dot-location": ["error", "property"],
|
],
|
||||||
"dot-notation": ["error"],
|
"complexity": ["error"],
|
||||||
"eol-last": ["error"],
|
"computed-property-spacing": [
|
||||||
eqeqeq: ["error"],
|
"error",
|
||||||
"for-direction": ["error"],
|
"never"
|
||||||
"func-call-spacing": ["error"],
|
],
|
||||||
"func-name-matching": ["error"],
|
"consistent-return": ["error"],
|
||||||
"func-names": ["error", "never"],
|
"consistent-this": ["error"],
|
||||||
"func-style": ["error"],
|
"constructor-super": ["error"],
|
||||||
"function-paren-newline": ["error"],
|
"curly": ["error"],
|
||||||
"generator-star-spacing": ["error", "before"],
|
"default-case": ["error"],
|
||||||
"getter-return": [
|
"dot-location": [
|
||||||
"error",
|
"error",
|
||||||
{
|
"property"
|
||||||
allowImplicit: false,
|
],
|
||||||
},
|
"dot-notation": ["error"],
|
||||||
],
|
"eol-last": ["error"],
|
||||||
"global-require": ["error"],
|
"eqeqeq": ["error"],
|
||||||
"guard-for-in": ["error"],
|
"for-direction": ["error"],
|
||||||
"handle-callback-err": ["error"],
|
"func-call-spacing": ["error"],
|
||||||
"id-blacklist": ["error"],
|
"func-name-matching": ["error"],
|
||||||
"id-length": ["error"],
|
"func-names": [
|
||||||
"id-match": ["error"],
|
"error",
|
||||||
"implicit-arrow-linebreak": ["error", "beside"],
|
"never"
|
||||||
indent: [
|
],
|
||||||
"error",
|
"func-style": ["error"],
|
||||||
numSpaces,
|
"function-paren-newline": ["error"],
|
||||||
{
|
"generator-star-spacing": [
|
||||||
SwitchCase: 1,
|
"error",
|
||||||
},
|
"before"
|
||||||
],
|
],
|
||||||
"init-declarations": ["error"],
|
"getter-return": [
|
||||||
"jsx-quotes": ["error"],
|
"error",
|
||||||
"key-spacing": ["error"],
|
{
|
||||||
"keyword-spacing": ["error"],
|
"allowImplicit": false
|
||||||
"line-comment-position": ["error"],
|
}
|
||||||
"linebreak-style": ["error", "windows"],
|
],
|
||||||
"lines-around-comment": ["error"],
|
"global-require": ["error"],
|
||||||
"lines-between-class-members": ["error"],
|
"guard-for-in": ["error"],
|
||||||
"max-depth": ["error"],
|
"handle-callback-err": ["error"],
|
||||||
"max-len": ["error", maxLineLength],
|
"id-blacklist": ["error"],
|
||||||
"max-lines": [
|
"id-length": ["error"],
|
||||||
"error",
|
"id-match": ["error"],
|
||||||
{
|
"implicit-arrow-linebreak": [
|
||||||
skipBlankLines: true,
|
"error",
|
||||||
skipComments: true,
|
"beside"
|
||||||
},
|
],
|
||||||
],
|
"indent": [
|
||||||
"max-nested-callbacks": ["error"],
|
"error",
|
||||||
"max-params": ["error"],
|
numSpaces,
|
||||||
"max-statements": ["error"],
|
{
|
||||||
"max-statements-per-line": ["error"],
|
"SwitchCase": 1
|
||||||
"multiline-comment-style": ["off", "starred-block"],
|
}
|
||||||
"multiline-ternary": ["error", "never"],
|
],
|
||||||
"new-cap": ["error"],
|
"init-declarations": ["error"],
|
||||||
"new-parens": ["error"],
|
"jsx-quotes": ["error"],
|
||||||
// TODO: configure this...
|
"key-spacing": ["error"],
|
||||||
"newline-before-return": ["error"],
|
"keyword-spacing": ["error"],
|
||||||
"newline-per-chained-call": ["error"],
|
"line-comment-position": ["error"],
|
||||||
"no-alert": ["error"],
|
"linebreak-style": [
|
||||||
"no-array-constructor": ["error"],
|
"error",
|
||||||
"no-await-in-loop": ["error"],
|
"windows"
|
||||||
"no-bitwise": ["error"],
|
],
|
||||||
"no-buffer-constructor": ["error"],
|
"lines-around-comment": ["error"],
|
||||||
"no-caller": ["error"],
|
"lines-between-class-members": ["error"],
|
||||||
"no-case-declarations": ["error"],
|
"max-depth": ["error"],
|
||||||
"no-catch-shadow": ["error"],
|
"max-len": [
|
||||||
"no-class-assign": ["error"],
|
"error",
|
||||||
"no-compare-neg-zero": ["error"],
|
maxLineLength
|
||||||
"no-cond-assign": ["error", "except-parens"],
|
],
|
||||||
"no-confusing-arrow": ["error"],
|
"max-lines": [
|
||||||
"no-console": ["error"],
|
"error",
|
||||||
"no-const-assign": ["error"],
|
{
|
||||||
"no-constant-condition": [
|
"skipBlankLines": true,
|
||||||
"error",
|
"skipComments": true
|
||||||
{
|
}
|
||||||
checkLoops: false,
|
],
|
||||||
},
|
"max-nested-callbacks": ["error"],
|
||||||
],
|
"max-params": ["error"],
|
||||||
"no-continue": ["off"],
|
"max-statements": ["error"],
|
||||||
"no-control-regex": ["error"],
|
"max-statements-per-line": ["error"],
|
||||||
"no-debugger": ["error"],
|
"multiline-comment-style": [
|
||||||
"no-delete-var": ["error"],
|
"off",
|
||||||
"no-div-regex": ["error"],
|
"starred-block"
|
||||||
"no-dupe-args": ["error"],
|
],
|
||||||
"no-dupe-class-members": ["error"],
|
"multiline-ternary": [
|
||||||
"no-dupe-keys": ["error"],
|
"error",
|
||||||
"no-duplicate-case": ["error"],
|
"never"
|
||||||
"no-duplicate-imports": [
|
],
|
||||||
"error",
|
"new-cap": ["error"],
|
||||||
{
|
"new-parens": ["error"],
|
||||||
includeExports: true,
|
// TODO: configure this...
|
||||||
},
|
"newline-before-return": ["error"],
|
||||||
],
|
"newline-per-chained-call": ["error"],
|
||||||
"no-else-return": ["error"],
|
"no-alert": ["error"],
|
||||||
"no-empty": [
|
"no-array-constructor": ["error"],
|
||||||
"error",
|
"no-await-in-loop": ["error"],
|
||||||
{
|
"no-bitwise": ["error"],
|
||||||
allowEmptyCatch: false,
|
"no-buffer-constructor": ["error"],
|
||||||
},
|
"no-caller": ["error"],
|
||||||
],
|
"no-case-declarations": ["error"],
|
||||||
"no-empty-character-class": ["error"],
|
"no-catch-shadow": ["error"],
|
||||||
"no-empty-function": ["error"],
|
"no-class-assign": ["error"],
|
||||||
"no-empty-pattern": ["error"],
|
"no-compare-neg-zero": ["error"],
|
||||||
"no-eq-null": ["error"],
|
"no-cond-assign": [
|
||||||
"no-eval": ["error"],
|
"error",
|
||||||
"no-ex-assign": ["error"],
|
"except-parens"
|
||||||
"no-extend-native": ["error"],
|
],
|
||||||
"no-extra-bind": ["error"],
|
"no-confusing-arrow": ["error"],
|
||||||
"no-extra-boolean-cast": ["error"],
|
"no-console": ["error"],
|
||||||
"no-extra-label": ["error"],
|
"no-const-assign": ["error"],
|
||||||
"no-extra-parens": [
|
"no-constant-condition": [
|
||||||
"error",
|
"error",
|
||||||
"all",
|
{
|
||||||
{
|
"checkLoops": false
|
||||||
conditionalAssign: false,
|
}
|
||||||
},
|
],
|
||||||
],
|
"no-continue": ["off"],
|
||||||
"no-extra-semi": ["error"],
|
"no-control-regex": ["error"],
|
||||||
"no-fallthrough": ["error"],
|
"no-debugger": ["error"],
|
||||||
"no-floating-decimal": ["error"],
|
"no-delete-var": ["error"],
|
||||||
"no-func-assign": ["error"],
|
"no-div-regex": ["error"],
|
||||||
"no-global-assign": ["error"],
|
"no-dupe-args": ["error"],
|
||||||
"no-implicit-coercion": ["error"],
|
"no-dupe-class-members": ["error"],
|
||||||
"no-implicit-globals": ["error"],
|
"no-dupe-keys": ["error"],
|
||||||
"no-implied-eval": ["error"],
|
"no-duplicate-case": ["error"],
|
||||||
"no-inline-comments": ["error"],
|
"no-duplicate-imports": [
|
||||||
"no-inner-declarations": ["error", "both"],
|
"error",
|
||||||
"no-invalid-regexp": ["error"],
|
{
|
||||||
"no-invalid-this": ["error"],
|
"includeExports": true
|
||||||
"no-irregular-whitespace": [
|
}
|
||||||
"error",
|
],
|
||||||
{
|
"no-else-return": ["error"],
|
||||||
skipComments: false,
|
"no-empty": [
|
||||||
skipRegExps: false,
|
"error",
|
||||||
skipStrings: false,
|
{
|
||||||
skipTemplates: false,
|
"allowEmptyCatch": false
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
"no-iterator": ["error"],
|
"no-empty-character-class": ["error"],
|
||||||
"no-label-var": ["error"],
|
"no-empty-function": ["error"],
|
||||||
"no-labels": ["error"],
|
"no-empty-pattern": ["error"],
|
||||||
"no-lone-blocks": ["error"],
|
"no-eq-null": ["error"],
|
||||||
"no-lonely-if": ["error"],
|
"no-eval": ["error"],
|
||||||
"no-loop-func": ["error"],
|
"no-ex-assign": ["error"],
|
||||||
"no-magic-numbers": [
|
"no-extend-native": ["error"],
|
||||||
"error",
|
"no-extra-bind": ["error"],
|
||||||
{
|
"no-extra-boolean-cast": ["error"],
|
||||||
ignore: [-1, 0, 1],
|
"no-extra-label": ["error"],
|
||||||
ignoreArrayIndexes: true,
|
"no-extra-parens": [
|
||||||
},
|
"error",
|
||||||
],
|
"all",
|
||||||
"no-mixed-operators": ["error"],
|
{
|
||||||
"no-mixed-requires": ["error"],
|
"conditionalAssign": false
|
||||||
"no-mixed-spaces-and-tabs": ["error"],
|
}
|
||||||
"no-multi-assign": ["error"],
|
],
|
||||||
"no-multi-spaces": ["error"],
|
"no-extra-semi": ["error"],
|
||||||
"no-multi-str": ["error"],
|
"no-fallthrough": ["error"],
|
||||||
"no-multiple-empty-lines": [
|
"no-floating-decimal": ["error"],
|
||||||
"error",
|
"no-func-assign": ["error"],
|
||||||
{
|
"no-global-assign": ["error"],
|
||||||
max: 1,
|
"no-implicit-coercion": ["error"],
|
||||||
},
|
"no-implicit-globals": ["error"],
|
||||||
],
|
"no-implied-eval": ["error"],
|
||||||
"no-native-reassign": ["error"],
|
"no-inline-comments": ["error"],
|
||||||
"no-negated-condition": ["error"],
|
"no-inner-declarations": [
|
||||||
"no-negated-in-lhs": ["error"],
|
"error",
|
||||||
"no-nested-ternary": ["error"],
|
"both"
|
||||||
"no-new": ["error"],
|
],
|
||||||
"no-new-func": ["error"],
|
"no-invalid-regexp": ["error"],
|
||||||
"no-new-object": ["error"],
|
"no-invalid-this": ["error"],
|
||||||
"no-new-require": ["error"],
|
"no-irregular-whitespace": [
|
||||||
"no-new-symbol": ["error"],
|
"error",
|
||||||
"no-new-wrappers": ["error"],
|
{
|
||||||
"no-obj-calls": ["error"],
|
"skipComments": false,
|
||||||
"no-octal": ["error"],
|
"skipRegExps": false,
|
||||||
"no-octal-escape": ["error"],
|
"skipStrings": false,
|
||||||
"no-param-reassign": ["error"],
|
"skipTemplates": false
|
||||||
"no-path-concat": ["error"],
|
}
|
||||||
"no-plusplus": [
|
],
|
||||||
"error",
|
"no-iterator": ["error"],
|
||||||
{
|
"no-label-var": ["error"],
|
||||||
allowForLoopAfterthoughts: true,
|
"no-labels": ["error"],
|
||||||
},
|
"no-lone-blocks": ["error"],
|
||||||
],
|
"no-lonely-if": ["error"],
|
||||||
"no-process-env": ["error"],
|
"no-loop-func": ["error"],
|
||||||
"no-process-exit": ["error"],
|
"no-magic-numbers": [
|
||||||
"no-proto": ["error"],
|
"error",
|
||||||
"no-prototype-builtins": ["error"],
|
{
|
||||||
"no-redeclare": ["error"],
|
"ignore": [
|
||||||
"no-regex-spaces": ["error"],
|
-1,
|
||||||
"no-restricted-globals": ["error"],
|
0,
|
||||||
"no-restricted-imports": ["error"],
|
1
|
||||||
"no-restricted-modules": ["error"],
|
],
|
||||||
"no-restricted-properties": [
|
"ignoreArrayIndexes": true
|
||||||
"error",
|
}
|
||||||
{
|
],
|
||||||
message: "'log' is too general, use an appropriate level when logging.",
|
"no-mixed-operators": ["error"],
|
||||||
object: "console",
|
"no-mixed-requires": ["error"],
|
||||||
property: "log",
|
"no-mixed-spaces-and-tabs": ["error"],
|
||||||
},
|
"no-multi-assign": ["error"],
|
||||||
],
|
"no-multi-spaces": ["error"],
|
||||||
"no-restricted-syntax": ["error"],
|
"no-multi-str": ["error"],
|
||||||
"no-return-assign": ["error"],
|
"no-multiple-empty-lines": [
|
||||||
"no-return-await": ["error"],
|
"error",
|
||||||
"no-script-url": ["error"],
|
{
|
||||||
"no-self-assign": [
|
"max": 1
|
||||||
"error",
|
}
|
||||||
{
|
],
|
||||||
props: false,
|
"no-native-reassign": ["error"],
|
||||||
},
|
"no-negated-condition": ["error"],
|
||||||
],
|
"no-negated-in-lhs": ["error"],
|
||||||
"no-self-compare": ["error"],
|
"no-nested-ternary": ["error"],
|
||||||
"no-sequences": ["error"],
|
"no-new": ["error"],
|
||||||
"no-shadow": ["error"],
|
"no-new-func": ["error"],
|
||||||
"no-shadow-restricted-names": ["error"],
|
"no-new-object": ["error"],
|
||||||
"no-spaced-func": ["error"],
|
"no-new-require": ["error"],
|
||||||
"no-sparse-arrays": ["error"],
|
"no-new-symbol": ["error"],
|
||||||
"no-sync": ["error"],
|
"no-new-wrappers": ["error"],
|
||||||
"no-tabs": ["error"],
|
"no-obj-calls": ["error"],
|
||||||
"no-template-curly-in-string": ["error"],
|
"no-octal": ["error"],
|
||||||
"no-ternary": ["off"],
|
"no-octal-escape": ["error"],
|
||||||
"no-this-before-super": ["error"],
|
"no-param-reassign": ["error"],
|
||||||
"no-throw-literal": ["error"],
|
"no-path-concat": ["error"],
|
||||||
"no-trailing-spaces": ["error"],
|
"no-plusplus": [
|
||||||
"no-undef": ["error"],
|
"error",
|
||||||
"no-undef-init": ["error"],
|
{
|
||||||
"no-undefined": ["error"],
|
"allowForLoopAfterthoughts": true
|
||||||
"no-underscore-dangle": ["error"],
|
}
|
||||||
"no-unexpected-multiline": ["error"],
|
],
|
||||||
"no-unmodified-loop-condition": ["error"],
|
"no-process-env": ["error"],
|
||||||
"no-unneeded-ternary": ["error"],
|
"no-process-exit": ["error"],
|
||||||
"no-unreachable": ["error"],
|
"no-proto": ["error"],
|
||||||
"no-unsafe-finally": ["error"],
|
"no-prototype-builtins": ["error"],
|
||||||
"no-unsafe-negation": ["error"],
|
"no-redeclare": ["error"],
|
||||||
"no-unused-expressions": ["error"],
|
"no-regex-spaces": ["error"],
|
||||||
"no-unused-labels": ["error"],
|
"no-restricted-globals": ["error"],
|
||||||
"no-unused-vars": ["error"],
|
"no-restricted-imports": ["error"],
|
||||||
"no-use-before-define": ["error"],
|
"no-restricted-modules": ["error"],
|
||||||
"no-useless-call": ["error"],
|
"no-restricted-properties": [
|
||||||
"no-useless-computed-key": ["error"],
|
"error",
|
||||||
"no-useless-concat": ["error"],
|
{
|
||||||
"no-useless-constructor": ["error"],
|
"message": "'log' is too general, use an appropriate level when logging.",
|
||||||
"no-useless-escape": ["error"],
|
"object": "console",
|
||||||
"no-useless-rename": [
|
"property": "log"
|
||||||
"error",
|
}
|
||||||
{
|
],
|
||||||
ignoreDestructuring: false,
|
"no-restricted-syntax": ["error"],
|
||||||
ignoreExport: false,
|
"no-return-assign": ["error"],
|
||||||
ignoreImport: false,
|
"no-return-await": ["error"],
|
||||||
},
|
"no-script-url": ["error"],
|
||||||
],
|
"no-self-assign": [
|
||||||
"no-useless-return": ["error"],
|
"error",
|
||||||
"no-var": ["error"],
|
{
|
||||||
"no-void": ["error"],
|
"props": false
|
||||||
"no-warning-comments": ["error"],
|
}
|
||||||
"no-whitespace-before-property": ["error"],
|
],
|
||||||
"no-with": ["error"],
|
"no-self-compare": ["error"],
|
||||||
"nonblock-statement-body-position": ["error", "below"],
|
"no-sequences": ["error"],
|
||||||
"object-curly-newline": ["error"],
|
"no-shadow": ["error"],
|
||||||
"object-curly-spacing": ["error"],
|
"no-shadow-restricted-names": ["error"],
|
||||||
"object-property-newline": ["error"],
|
"no-spaced-func": ["error"],
|
||||||
"object-shorthand": ["error"],
|
"no-sparse-arrays": ["error"],
|
||||||
"one-var": ["off"],
|
"no-sync": ["error"],
|
||||||
"one-var-declaration-per-line": ["error"],
|
"no-tabs": ["error"],
|
||||||
"operator-assignment": ["error"],
|
"no-template-curly-in-string": ["error"],
|
||||||
"operator-linebreak": ["error", "none"],
|
"no-ternary": ["off"],
|
||||||
"padded-blocks": ["off"],
|
"no-this-before-super": ["error"],
|
||||||
"padding-line-between-statements": ["error"],
|
"no-throw-literal": ["error"],
|
||||||
"prefer-arrow-callback": ["error"],
|
"no-trailing-spaces": ["error"],
|
||||||
"prefer-const": ["error"],
|
"no-undef": ["error"],
|
||||||
"prefer-destructuring": ["off"],
|
"no-undef-init": ["error"],
|
||||||
"prefer-numeric-literals": ["error"],
|
"no-undefined": ["error"],
|
||||||
"prefer-promise-reject-errors": ["off"],
|
"no-underscore-dangle": ["error"],
|
||||||
"prefer-reflect": ["error"],
|
"no-unexpected-multiline": ["error"],
|
||||||
"prefer-rest-params": ["error"],
|
"no-unmodified-loop-condition": ["error"],
|
||||||
"prefer-spread": ["error"],
|
"no-unneeded-ternary": ["error"],
|
||||||
"prefer-template": ["error"],
|
"no-unreachable": ["error"],
|
||||||
"quote-props": ["error"],
|
"no-unsafe-finally": ["error"],
|
||||||
quotes: ["error"],
|
"no-unsafe-negation": ["error"],
|
||||||
radix: ["error", "as-needed"],
|
"no-unused-expressions": ["error"],
|
||||||
"require-await": ["error"],
|
"no-unused-labels": ["error"],
|
||||||
"require-jsdoc": ["off"],
|
"no-unused-vars": ["error"],
|
||||||
"require-yield": ["error"],
|
"no-use-before-define": ["error"],
|
||||||
"rest-spread-spacing": ["error", "never"],
|
"no-useless-call": ["error"],
|
||||||
semi: ["error"],
|
"no-useless-computed-key": ["error"],
|
||||||
"semi-spacing": ["error"],
|
"no-useless-concat": ["error"],
|
||||||
"semi-style": ["error", "last"],
|
"no-useless-constructor": ["error"],
|
||||||
"sort-imports": ["error"],
|
"no-useless-escape": ["error"],
|
||||||
"sort-keys": ["error"],
|
"no-useless-rename": [
|
||||||
"sort-vars": ["error"],
|
"error",
|
||||||
"space-before-blocks": ["error"],
|
{
|
||||||
"space-before-function-paren": ["off"],
|
"ignoreDestructuring": false,
|
||||||
"space-in-parens": ["error"],
|
"ignoreExport": false,
|
||||||
"space-infix-ops": ["error"],
|
"ignoreImport": false
|
||||||
"space-unary-ops": ["error"],
|
}
|
||||||
"spaced-comment": ["error"],
|
],
|
||||||
strict: ["error"],
|
"no-useless-return": ["error"],
|
||||||
"switch-colon-spacing": [
|
"no-var": ["error"],
|
||||||
"error",
|
"no-void": ["error"],
|
||||||
{
|
"no-warning-comments": ["error"],
|
||||||
after: true,
|
"no-whitespace-before-property": ["error"],
|
||||||
before: false,
|
"no-with": ["error"],
|
||||||
},
|
"nonblock-statement-body-position": [
|
||||||
],
|
"error",
|
||||||
"symbol-description": ["error"],
|
"below"
|
||||||
"template-curly-spacing": ["error"],
|
],
|
||||||
"template-tag-spacing": ["error"],
|
"object-curly-newline": ["error"],
|
||||||
"unicode-bom": ["error", "never"],
|
"object-curly-spacing": ["error"],
|
||||||
"use-isnan": ["error"],
|
"object-property-newline": ["error"],
|
||||||
"valid-jsdoc": ["error"],
|
"object-shorthand": ["error"],
|
||||||
"valid-typeof": ["error"],
|
"one-var": ["off"],
|
||||||
"vars-on-top": ["error"],
|
"one-var-declaration-per-line": ["error"],
|
||||||
"wrap-iife": ["error", "any"],
|
"operator-assignment": ["error"],
|
||||||
"wrap-regex": ["error"],
|
"operator-linebreak": [
|
||||||
"yield-star-spacing": ["error", "before"],
|
"error",
|
||||||
yoda: ["error", "never"],
|
"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 exec = require("child_process").exec;
|
||||||
const semver = require("./semver");
|
const semver = require("./semver");
|
||||||
|
|
||||||
const getPackageJson = () =>
|
const getPackageJson = () => new Promise((resolve, reject) => {
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
try {
|
try {
|
||||||
/* eslint-disable-next-line global-require */
|
/* eslint-disable-next-line global-require */
|
||||||
resolve(require(path.resolve(process.cwd(), "package.json")));
|
resolve(require(path.resolve(process.cwd(), "package.json")));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getEngines = (data) =>
|
const getEngines = (data) => new Promise((resolve, reject) => {
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
let versions = null;
|
let versions = null;
|
||||||
|
|
||||||
if (data.engines) {
|
if (data.engines) {
|
||||||
versions = data.engines;
|
versions = data.engines;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (versions) {
|
if (versions) {
|
||||||
resolve(versions);
|
resolve(versions);
|
||||||
} else {
|
} else {
|
||||||
reject("Missing or improper 'engines' property in 'package.json'");
|
reject("Missing or improper 'engines' property in 'package.json'");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const checkNpmVersion = (engines) =>
|
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
exec("npm -v", (error, stdout, stderr) => {
|
exec("npm -v", (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(`Unable to find NPM version\n${stderr}`);
|
reject(`Unable to find NPM version\n${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const npmVersion = stdout.trim();
|
const npmVersion = stdout.trim();
|
||||||
const engineVersion = engines.npm || ">=0";
|
const engineVersion = engines.npm || ">=0";
|
||||||
|
|
||||||
if (semver.satisfies(npmVersion, engineVersion)) {
|
if (semver.satisfies(npmVersion, engineVersion)) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
reject(
|
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
|
||||||
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const checkNodeVersion = (engines) =>
|
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
const nodeVersion = process.version.substring(1);
|
const nodeVersion = process.version.substring(1);
|
||||||
|
|
||||||
if (semver.satisfies(nodeVersion, engines.node)) {
|
if (semver.satisfies(nodeVersion, engines.node)) {
|
||||||
resolve(engines);
|
resolve(engines);
|
||||||
} else {
|
} else {
|
||||||
reject(
|
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
|
||||||
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
getPackageJson()
|
getPackageJson()
|
||||||
.then(getEngines)
|
.then(getEngines)
|
||||||
.then(checkNodeVersion)
|
.then(checkNodeVersion)
|
||||||
.then(checkNpmVersion)
|
.then(checkNpmVersion)
|
||||||
.then(
|
.then(
|
||||||
() => true,
|
() => true,
|
||||||
(error) => {
|
(error) => {
|
||||||
// Specifically disable these as the error message gets lost in the normal unhandled output.
|
// Specifically disable these as the error message gets lost in the normal unhandled output.
|
||||||
/* eslint-disable no-console, no-process-exit */
|
/* eslint-disable no-console, no-process-exit */
|
||||||
console.error(error);
|
console.error(error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1928,7 +1928,7 @@ export class Bladeburner implements IBladeburner {
|
|||||||
|
|
||||||
// Count increase for contracts/operations
|
// Count increase for contracts/operations
|
||||||
for (const contract of Object.values(this.contracts) as Contract[]) {
|
for (const contract of Object.values(this.contracts) as Contract[]) {
|
||||||
let growthF = Growths[contract.name];
|
const growthF = Growths[contract.name];
|
||||||
if (growthF === undefined) throw new Error(`growth formula for action '${contract.name}' is undefined`);
|
if (growthF === undefined) throw new Error(`growth formula for action '${contract.name}' is undefined`);
|
||||||
contract.count += (seconds * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
contract.count += (seconds * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,7 @@ export function BlackOpList(props: IProps): React.ReactElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
blackops = blackops.filter(
|
blackops = blackops.filter(
|
||||||
(blackop: BlackOperation, i: number) =>
|
(blackop: BlackOperation, i: number) => !(
|
||||||
!(
|
|
||||||
props.bladeburner.blackops[blackops[i].name] == null &&
|
props.bladeburner.blackops[blackops[i].name] == null &&
|
||||||
i !== 0 &&
|
i !== 0 &&
|
||||||
props.bladeburner.blackops[blackops[i - 1].name] == null
|
props.bladeburner.blackops[blackops[i - 1].name] == null
|
||||||
|
@ -61,8 +61,7 @@ export function CityTabs(props: IProps): React.ReactElement {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{Object.values(props.division.offices).map(
|
{Object.values(props.division.offices).map(
|
||||||
(office: OfficeSpace | 0) =>
|
(office: OfficeSpace | 0) => office !== 0 && (
|
||||||
office !== 0 && (
|
|
||||||
<CityTab
|
<CityTab
|
||||||
current={city === office.loc}
|
current={city === office.loc}
|
||||||
key={office.loc}
|
key={office.loc}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { useRef } from "react";
|
import React, { useRef } from "react";
|
||||||
import { IIndustry } from "../IIndustry";
|
import { IIndustry } from "../IIndustry";
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
|
||||||
import { CorporationConstants } from "../data/Constants";
|
import { CorporationConstants } from "../data/Constants";
|
||||||
import { removePopup } from "../../ui/React/createPopup";
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
@ -20,8 +20,7 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
|
|||||||
const allIndustries = Object.keys(Industries).sort();
|
const allIndustries = Object.keys(Industries).sort();
|
||||||
const possibleIndustries = allIndustries
|
const possibleIndustries = allIndustries
|
||||||
.filter(
|
.filter(
|
||||||
(industryType: string) =>
|
(industryType: string) => props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||||
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
|
||||||
)
|
)
|
||||||
.sort();
|
.sort();
|
||||||
if (possibleIndustries.length === 0) return <></>;
|
if (possibleIndustries.length === 0) return <></>;
|
||||||
|
@ -424,7 +424,6 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
|||||||
)}
|
)}
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{/* TODO: add flashing here */}
|
|
||||||
<button className={`std-button${shouldFlash() ? " flashing-button" : ""}`} onClick={openSellMaterialPopup}>
|
<button className={`std-button${shouldFlash() ? " flashing-button" : ""}`} onClick={openSellMaterialPopup}>
|
||||||
{sellButtonText}
|
{sellButtonText}
|
||||||
</button>
|
</button>
|
||||||
@ -481,17 +480,6 @@ export function IndustryWarehouse(props: IProps): React.ReactElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Industry material Requirements
|
|
||||||
let generalReqsText = "This Industry uses [" + Object.keys(props.division.reqMats).join(", ") + "] in order to ";
|
|
||||||
if (props.division.prodMats.length > 0) {
|
|
||||||
generalReqsText += "produce [" + props.division.prodMats.join(", ") + "] ";
|
|
||||||
if (props.division.makesProducts) {
|
|
||||||
generalReqsText += " and " + props.division.getProductDescriptionText();
|
|
||||||
}
|
|
||||||
} else if (props.division.makesProducts) {
|
|
||||||
generalReqsText += props.division.getProductDescriptionText() + ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
const ratioLines = [];
|
const ratioLines = [];
|
||||||
for (const matName in props.division.reqMats) {
|
for (const matName in props.division.reqMats) {
|
||||||
if (props.division.reqMats.hasOwnProperty(matName)) {
|
if (props.division.reqMats.hasOwnProperty(matName)) {
|
||||||
@ -504,16 +492,6 @@ export function IndustryWarehouse(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let createdItemsText = "in order to create ";
|
|
||||||
if (props.division.prodMats.length > 0) {
|
|
||||||
createdItemsText += "one of each produced Material (" + props.division.prodMats.join(", ") + ") ";
|
|
||||||
if (props.division.makesProducts) {
|
|
||||||
createdItemsText += "or to create one of its Products";
|
|
||||||
}
|
|
||||||
} else if (props.division.makesProducts) {
|
|
||||||
createdItemsText += "one of its Products";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current State:
|
// Current State:
|
||||||
let stateText;
|
let stateText;
|
||||||
switch (props.division.state) {
|
switch (props.division.state) {
|
||||||
|
@ -17,8 +17,7 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
|
|||||||
const allIndustries = Object.keys(Industries).sort();
|
const allIndustries = Object.keys(Industries).sort();
|
||||||
const possibleIndustries = allIndustries
|
const possibleIndustries = allIndustries
|
||||||
.filter(
|
.filter(
|
||||||
(industryType: string) =>
|
(industryType: string) => props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||||
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
|
||||||
)
|
)
|
||||||
.sort();
|
.sort();
|
||||||
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : "");
|
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : "");
|
||||||
|
@ -5,7 +5,6 @@ import { ICorporation } from "../ICorporation";
|
|||||||
import { IIndustry } from "../IIndustry";
|
import { IIndustry } from "../IIndustry";
|
||||||
import { SetSmartSupply } from "../Actions";
|
import { SetSmartSupply } from "../Actions";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { isRelevantMaterial } from "./Helpers";
|
|
||||||
import { Material } from "../Material";
|
import { Material } from "../Material";
|
||||||
|
|
||||||
interface ILeftoverProps {
|
interface ILeftoverProps {
|
||||||
@ -43,7 +42,7 @@ interface IProps {
|
|||||||
|
|
||||||
export function SmartSupplyPopup(props: IProps): React.ReactElement {
|
export function SmartSupplyPopup(props: IProps): React.ReactElement {
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
function rerender() {
|
function rerender(): void {
|
||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
}
|
}
|
||||||
// Smart Supply Checkbox
|
// Smart Supply Checkbox
|
||||||
|
@ -737,8 +737,7 @@ class DevMenuComponent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let sourceFiles = [];
|
let sourceFiles = [];
|
||||||
validSFN.forEach((i) =>
|
validSFN.forEach((i) => sourceFiles.push(
|
||||||
sourceFiles.push(
|
|
||||||
<tr key={"sf-" + i}>
|
<tr key={"sf-" + i}>
|
||||||
<td>
|
<td>
|
||||||
<span className="text">SF-{i}:</span>
|
<span className="text">SF-{i}:</span>
|
||||||
|
@ -123,8 +123,7 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
|||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
const augs = this.getAugsSorted();
|
const augs = this.getAugsSorted();
|
||||||
const purchasable = augs.filter(
|
const purchasable = augs.filter(
|
||||||
(aug: string) =>
|
(aug: string) => aug === AugmentationNames.NeuroFluxGovernor ||
|
||||||
aug === AugmentationNames.NeuroFluxGovernor ||
|
|
||||||
(!this.props.p.augmentations.some((a) => a.name === aug) &&
|
(!this.props.p.augmentations.some((a) => a.name === aug) &&
|
||||||
!this.props.p.queuedAugmentations.some((a) => a.name === aug)),
|
!this.props.p.queuedAugmentations.some((a) => a.name === aug)),
|
||||||
);
|
);
|
||||||
|
@ -18,117 +18,109 @@ import { HashUpgrades } from "./HashUpgrades";
|
|||||||
|
|
||||||
import { generateRandomContract } from "../CodingContractGenerator";
|
import { generateRandomContract } from "../CodingContractGenerator";
|
||||||
import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial";
|
import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial";
|
||||||
import { Player } from "../Player";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { AllServers } from "../Server/AllServers";
|
import { AllServers } from "../Server/AllServers";
|
||||||
import { GetServerByHostname } from "../Server/ServerHelpers";
|
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||||
|
import { Server } from "../Server/Server";
|
||||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||||
import { Page, routing } from "../ui/navigationTracking";
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import ReactDOM from "react-dom";
|
|
||||||
import { HacknetRoot } from "./ui/Root";
|
|
||||||
|
|
||||||
let hacknetNodesDiv;
|
|
||||||
function hacknetNodesInit() {
|
|
||||||
hacknetNodesDiv = document.getElementById("hacknet-nodes-container");
|
|
||||||
document.removeEventListener("DOMContentLoaded", hacknetNodesInit);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", hacknetNodesInit);
|
|
||||||
|
|
||||||
// Returns a boolean indicating whether the player has Hacknet Servers
|
// Returns a boolean indicating whether the player has Hacknet Servers
|
||||||
// (the upgraded form of Hacknet Nodes)
|
// (the upgraded form of Hacknet Nodes)
|
||||||
export function hasHacknetServers() {
|
export function hasHacknetServers(player: IPlayer): boolean {
|
||||||
return Player.bitNodeN === 9 || SourceFileFlags[9] > 0;
|
return player.bitNodeN === 9 || SourceFileFlags[9] > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseHacknet() {
|
export function purchaseHacknet(player: IPlayer): number {
|
||||||
/* INTERACTIVE TUTORIAL */
|
/* INTERACTIVE TUTORIAL */
|
||||||
if (ITutorial.isRunning) {
|
if (ITutorial.isRunning) {
|
||||||
if (ITutorial.currStep === iTutorialSteps.HacknetNodesIntroduction) {
|
if (ITutorial.currStep === iTutorialSteps.HacknetNodesIntroduction) {
|
||||||
iTutorialNextStep();
|
iTutorialNextStep();
|
||||||
} else {
|
} else {
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* END INTERACTIVE TUTORIAL */
|
/* END INTERACTIVE TUTORIAL */
|
||||||
|
|
||||||
const numOwned = Player.hacknetNodes.length;
|
const numOwned = player.hacknetNodes.length;
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(player)) {
|
||||||
const cost = getCostOfNextHacknetServer();
|
const cost = getCostOfNextHacknetServer(player);
|
||||||
if (isNaN(cost)) {
|
if (isNaN(cost)) {
|
||||||
throw new Error(`Calculated cost of purchasing HacknetServer is NaN`);
|
throw new Error(`Calculated cost of purchasing HacknetServer is NaN`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(cost)) {
|
if (!player.canAfford(cost)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Player.loseMoney(cost);
|
player.loseMoney(cost);
|
||||||
Player.createHacknetServer();
|
player.createHacknetServer();
|
||||||
updateHashManagerCapacity();
|
updateHashManagerCapacity(player);
|
||||||
|
|
||||||
return numOwned;
|
return numOwned;
|
||||||
} else {
|
} else {
|
||||||
const cost = getCostOfNextHacknetNode();
|
const cost = getCostOfNextHacknetNode(player);
|
||||||
if (isNaN(cost)) {
|
if (isNaN(cost)) {
|
||||||
throw new Error(`Calculated cost of purchasing HacknetNode is NaN`);
|
throw new Error(`Calculated cost of purchasing HacknetNode is NaN`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(cost)) {
|
if (!player.canAfford(cost)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto generate a name for the Node
|
// Auto generate a name for the Node
|
||||||
const name = "hacknet-node-" + numOwned;
|
const name = "hacknet-node-" + numOwned;
|
||||||
const node = new HacknetNode(name, Player.hacknet_node_money_mult);
|
const node = new HacknetNode(name, player.hacknet_node_money_mult);
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
player.loseMoney(cost);
|
||||||
Player.hacknetNodes.push(node);
|
player.hacknetNodes.push(node);
|
||||||
|
|
||||||
return numOwned;
|
return numOwned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasMaxNumberHacknetServers() {
|
export function hasMaxNumberHacknetServers(player: IPlayer): boolean {
|
||||||
return hasHacknetServers() && Player.hacknetNodes.length >= HacknetServerConstants.MaxServers;
|
return hasHacknetServers(player) && player.hacknetNodes.length >= HacknetServerConstants.MaxServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCostOfNextHacknetNode() {
|
export function getCostOfNextHacknetNode(player: IPlayer): number {
|
||||||
return calculateNodeCost(Player.hacknetNodes.length + 1, Player.hacknet_node_purchase_cost_mult);
|
return calculateNodeCost(player.hacknetNodes.length + 1, player.hacknet_node_purchase_cost_mult);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCostOfNextHacknetServer() {
|
export function getCostOfNextHacknetServer(player: IPlayer): number {
|
||||||
return calculateServerCost(Player.hacknetNodes.length + 1, Player.hacknet_node_purchase_cost_mult);
|
return calculateServerCost(player.hacknetNodes.length + 1, player.hacknet_node_purchase_cost_mult);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's level
|
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's level
|
||||||
export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
|
export function getMaxNumberLevelUpgrades(
|
||||||
|
player: IPlayer,
|
||||||
|
nodeObj: HacknetNode | HacknetServer,
|
||||||
|
maxLevel: number,
|
||||||
|
): number {
|
||||||
if (maxLevel == null) {
|
if (maxLevel == null) {
|
||||||
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
|
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1, Player.hacknet_node_level_cost_mult))) {
|
if (player.money.lt(nodeObj.calculateLevelUpgradeCost(1, player.hacknet_node_level_cost_mult))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let min = 1;
|
let min = 1;
|
||||||
let max = maxLevel - 1;
|
let max = maxLevel - 1;
|
||||||
let levelsToMax = maxLevel - nodeObj.level;
|
const levelsToMax = maxLevel - nodeObj.level;
|
||||||
if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, Player.hacknet_node_level_cost_mult))) {
|
if (player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, player.hacknet_node_level_cost_mult))) {
|
||||||
return levelsToMax;
|
return levelsToMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (min <= max) {
|
while (min <= max) {
|
||||||
var curr = ((min + max) / 2) | 0;
|
const curr = ((min + max) / 2) | 0;
|
||||||
if (
|
if (
|
||||||
curr !== maxLevel &&
|
curr !== maxLevel &&
|
||||||
Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult)) &&
|
player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult)) &&
|
||||||
Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, Player.hacknet_node_level_cost_mult))
|
player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, player.hacknet_node_level_cost_mult))
|
||||||
) {
|
) {
|
||||||
return Math.min(levelsToMax, curr);
|
return Math.min(levelsToMax, curr);
|
||||||
} else if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult))) {
|
} else if (player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult))) {
|
||||||
max = curr - 1;
|
max = curr - 1;
|
||||||
} else if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult))) {
|
} else if (player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult))) {
|
||||||
min = curr + 1;
|
min = curr + 1;
|
||||||
} else {
|
} else {
|
||||||
return Math.min(levelsToMax, curr);
|
return Math.min(levelsToMax, curr);
|
||||||
@ -138,12 +130,16 @@ export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's RAM
|
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's RAM
|
||||||
export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
export function getMaxNumberRamUpgrades(
|
||||||
|
player: IPlayer,
|
||||||
|
nodeObj: HacknetNode | HacknetServer,
|
||||||
|
maxLevel: number,
|
||||||
|
): number {
|
||||||
if (maxLevel == null) {
|
if (maxLevel == null) {
|
||||||
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
|
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.money.lt(nodeObj.calculateRamUpgradeCost(1, Player.hacknet_node_ram_cost_mult))) {
|
if (player.money.lt(nodeObj.calculateRamUpgradeCost(1, player.hacknet_node_ram_cost_mult))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,13 +149,13 @@ export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
|||||||
} else {
|
} else {
|
||||||
levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram));
|
levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram));
|
||||||
}
|
}
|
||||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, Player.hacknet_node_ram_cost_mult))) {
|
if (player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, player.hacknet_node_ram_cost_mult))) {
|
||||||
return levelsToMax;
|
return levelsToMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
//We'll just loop until we find the max
|
//We'll just loop until we find the max
|
||||||
for (let i = levelsToMax - 1; i >= 0; --i) {
|
for (let i = levelsToMax - 1; i >= 0; --i) {
|
||||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(i, Player.hacknet_node_ram_cost_mult))) {
|
if (player.money.gt(nodeObj.calculateRamUpgradeCost(i, player.hacknet_node_ram_cost_mult))) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,34 +163,38 @@ export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cores
|
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cores
|
||||||
export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
|
export function getMaxNumberCoreUpgrades(
|
||||||
|
player: IPlayer,
|
||||||
|
nodeObj: HacknetNode | HacknetServer,
|
||||||
|
maxLevel: number,
|
||||||
|
): number {
|
||||||
if (maxLevel == null) {
|
if (maxLevel == null) {
|
||||||
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
|
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(1, Player.hacknet_node_core_cost_mult))) {
|
if (player.money.lt(nodeObj.calculateCoreUpgradeCost(1, player.hacknet_node_core_cost_mult))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let min = 1;
|
let min = 1;
|
||||||
let max = maxLevel - 1;
|
let max = maxLevel - 1;
|
||||||
const levelsToMax = maxLevel - nodeObj.cores;
|
const levelsToMax = maxLevel - nodeObj.cores;
|
||||||
if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, Player.hacknet_node_core_cost_mult))) {
|
if (player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, player.hacknet_node_core_cost_mult))) {
|
||||||
return levelsToMax;
|
return levelsToMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a binary search to find the max possible number of upgrades
|
// Use a binary search to find the max possible number of upgrades
|
||||||
while (min <= max) {
|
while (min <= max) {
|
||||||
let curr = ((min + max) / 2) | 0;
|
const curr = ((min + max) / 2) | 0;
|
||||||
if (
|
if (
|
||||||
curr != maxLevel &&
|
curr != maxLevel &&
|
||||||
Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult)) &&
|
player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult)) &&
|
||||||
Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, Player.hacknet_node_core_cost_mult))
|
player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, player.hacknet_node_core_cost_mult))
|
||||||
) {
|
) {
|
||||||
return Math.min(levelsToMax, curr);
|
return Math.min(levelsToMax, curr);
|
||||||
} else if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult))) {
|
} else if (player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult))) {
|
||||||
max = curr - 1;
|
max = curr - 1;
|
||||||
} else if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult))) {
|
} else if (player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult))) {
|
||||||
min = curr + 1;
|
min = curr + 1;
|
||||||
} else {
|
} else {
|
||||||
return Math.min(levelsToMax, curr);
|
return Math.min(levelsToMax, curr);
|
||||||
@ -205,34 +205,34 @@ export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cache
|
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cache
|
||||||
export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
|
export function getMaxNumberCacheUpgrades(player: IPlayer, nodeObj: HacknetServer, maxLevel: number): number {
|
||||||
if (maxLevel == null) {
|
if (maxLevel == null) {
|
||||||
throw new Error(`getMaxNumberCacheUpgrades() called without maxLevel arg`);
|
throw new Error(`getMaxNumberCacheUpgrades() called without maxLevel arg`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(nodeObj.calculateCacheUpgradeCost(1))) {
|
if (!player.canAfford(nodeObj.calculateCacheUpgradeCost(1))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let min = 1;
|
let min = 1;
|
||||||
let max = maxLevel - 1;
|
let max = maxLevel - 1;
|
||||||
const levelsToMax = maxLevel - nodeObj.cache;
|
const levelsToMax = maxLevel - nodeObj.cache;
|
||||||
if (Player.canAfford(nodeObj.calculateCacheUpgradeCost(levelsToMax))) {
|
if (player.canAfford(nodeObj.calculateCacheUpgradeCost(levelsToMax))) {
|
||||||
return levelsToMax;
|
return levelsToMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a binary search to find the max possible number of upgrades
|
// Use a binary search to find the max possible number of upgrades
|
||||||
while (min <= max) {
|
while (min <= max) {
|
||||||
let curr = ((min + max) / 2) | 0;
|
const curr = ((min + max) / 2) | 0;
|
||||||
if (
|
if (
|
||||||
curr != maxLevel &&
|
curr != maxLevel &&
|
||||||
Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr)) &&
|
player.canAfford(nodeObj.calculateCacheUpgradeCost(curr)) &&
|
||||||
!Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr + 1))
|
!player.canAfford(nodeObj.calculateCacheUpgradeCost(curr + 1))
|
||||||
) {
|
) {
|
||||||
return Math.min(levelsToMax, curr);
|
return Math.min(levelsToMax, curr);
|
||||||
} else if (!Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
} else if (!player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
||||||
max = curr - 1;
|
max = curr - 1;
|
||||||
} else if (Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
} else if (player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
||||||
min = curr + 1;
|
min = curr + 1;
|
||||||
} else {
|
} else {
|
||||||
return Math.min(levelsToMax, curr);
|
return Math.min(levelsToMax, curr);
|
||||||
@ -242,9 +242,9 @@ export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseLevelUpgrade(node, levels = 1) {
|
export function purchaseLevelUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
|
||||||
const sanitizedLevels = Math.round(levels);
|
const sanitizedLevels = Math.round(levels);
|
||||||
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, Player.hacknet_node_level_cost_mult);
|
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, player.hacknet_node_level_cost_mult);
|
||||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -260,60 +260,61 @@ export function purchaseLevelUpgrade(node, levels = 1) {
|
|||||||
// the maximum number of upgrades and use that
|
// the maximum number of upgrades and use that
|
||||||
if (node.level + sanitizedLevels > (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel)) {
|
if (node.level + sanitizedLevels > (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel)) {
|
||||||
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel) - node.level);
|
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel) - node.level);
|
||||||
return purchaseLevelUpgrade(node, diff);
|
return purchaseLevelUpgrade(player, node, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(cost)) {
|
if (!player.canAfford(cost)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
player.loseMoney(cost);
|
||||||
node.upgradeLevel(sanitizedLevels, Player.hacknet_node_money_mult);
|
node.upgradeLevel(sanitizedLevels, player.hacknet_node_money_mult);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseRamUpgrade(node, levels = 1) {
|
export function purchaseRamUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
|
||||||
const sanitizedLevels = Math.round(levels);
|
const sanitizedLevels = Math.round(levels);
|
||||||
const cost = node.calculateRamUpgradeCost(sanitizedLevels, Player.hacknet_node_ram_cost_mult);
|
const cost = node.calculateRamUpgradeCost(sanitizedLevels, player.hacknet_node_ram_cost_mult);
|
||||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isServer = node instanceof HacknetServer;
|
if (node instanceof HacknetServer && node.maxRam >= HacknetServerConstants.MaxRam) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Fail if we're already at max
|
if (node instanceof HacknetNode && node.ram >= HacknetNodeConstants.MaxRam) {
|
||||||
if (node.ram >= (isServer ? HacknetServerConstants.MaxRam : HacknetNodeConstants.MaxRam)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the number of specified upgrades would exceed the max RAM, calculate the
|
// If the number of specified upgrades would exceed the max RAM, calculate the
|
||||||
// max possible number of upgrades and use that
|
// max possible number of upgrades and use that
|
||||||
if (isServer) {
|
if (node instanceof HacknetServer) {
|
||||||
if (node.maxRam * Math.pow(2, sanitizedLevels) > HacknetServerConstants.MaxRam) {
|
if (node.maxRam * Math.pow(2, sanitizedLevels) > HacknetServerConstants.MaxRam) {
|
||||||
const diff = Math.max(0, Math.log2(Math.round(HacknetServerConstants.MaxRam / node.maxRam)));
|
const diff = Math.max(0, Math.log2(Math.round(HacknetServerConstants.MaxRam / node.maxRam)));
|
||||||
return purchaseRamUpgrade(node, diff);
|
return purchaseRamUpgrade(player, node, diff);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (node instanceof HacknetNode) {
|
||||||
if (node.ram * Math.pow(2, sanitizedLevels) > HacknetNodeConstants.MaxRam) {
|
if (node.ram * Math.pow(2, sanitizedLevels) > HacknetNodeConstants.MaxRam) {
|
||||||
const diff = Math.max(0, Math.log2(Math.round(HacknetNodeConstants.MaxRam / node.ram)));
|
const diff = Math.max(0, Math.log2(Math.round(HacknetNodeConstants.MaxRam / node.ram)));
|
||||||
return purchaseRamUpgrade(node, diff);
|
return purchaseRamUpgrade(player, node, diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(cost)) {
|
if (!player.canAfford(cost)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
player.loseMoney(cost);
|
||||||
node.upgradeRam(sanitizedLevels, Player.hacknet_node_money_mult);
|
node.upgradeRam(sanitizedLevels, player.hacknet_node_money_mult);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseCoreUpgrade(node, levels = 1) {
|
export function purchaseCoreUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
|
||||||
const sanitizedLevels = Math.round(levels);
|
const sanitizedLevels = Math.round(levels);
|
||||||
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, Player.hacknet_node_core_cost_mult);
|
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, player.hacknet_node_core_cost_mult);
|
||||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -329,20 +330,20 @@ export function purchaseCoreUpgrade(node, levels = 1) {
|
|||||||
// the max possible number of upgrades and use that
|
// the max possible number of upgrades and use that
|
||||||
if (node.cores + sanitizedLevels > (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores)) {
|
if (node.cores + sanitizedLevels > (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores)) {
|
||||||
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores) - node.cores);
|
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores) - node.cores);
|
||||||
return purchaseCoreUpgrade(node, diff);
|
return purchaseCoreUpgrade(player, node, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(cost)) {
|
if (!player.canAfford(cost)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
player.loseMoney(cost);
|
||||||
node.upgradeCore(sanitizedLevels, Player.hacknet_node_money_mult);
|
node.upgradeCore(sanitizedLevels, player.hacknet_node_money_mult);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseCacheUpgrade(node, levels = 1) {
|
export function purchaseCacheUpgrade(player: IPlayer, node: HacknetServer, levels = 1): boolean {
|
||||||
const sanitizedLevels = Math.round(levels);
|
const sanitizedLevels = Math.round(levels);
|
||||||
const cost = node.calculateCacheUpgradeCost(sanitizedLevels);
|
const cost = node.calculateCacheUpgradeCost(sanitizedLevels);
|
||||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||||
@ -357,143 +358,132 @@ export function purchaseCacheUpgrade(node, levels = 1) {
|
|||||||
// Fail if we're already at max
|
// Fail if we're already at max
|
||||||
if (node.cache + sanitizedLevels > HacknetServerConstants.MaxCache) {
|
if (node.cache + sanitizedLevels > HacknetServerConstants.MaxCache) {
|
||||||
const diff = Math.max(0, HacknetServerConstants.MaxCache - node.cache);
|
const diff = Math.max(0, HacknetServerConstants.MaxCache - node.cache);
|
||||||
return purchaseCacheUpgrade(node, diff);
|
return purchaseCacheUpgrade(player, node, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Player.canAfford(cost)) {
|
if (!player.canAfford(cost)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
player.loseMoney(cost);
|
||||||
node.upgradeCache(sanitizedLevels);
|
node.upgradeCache(sanitizedLevels);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create/Refresh Hacknet Nodes UI
|
export function processHacknetEarnings(player: IPlayer, numCycles: number): number {
|
||||||
export function renderHacknetNodesUI() {
|
|
||||||
if (!routing.isOn(Page.HacknetNodes)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReactDOM.render(<HacknetRoot />, hacknetNodesDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearHacknetNodesUI() {
|
|
||||||
if (hacknetNodesDiv instanceof HTMLElement) {
|
|
||||||
ReactDOM.unmountComponentAtNode(hacknetNodesDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
hacknetNodesDiv.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function processHacknetEarnings(numCycles) {
|
|
||||||
// Determine if player has Hacknet Nodes or Hacknet Servers, then
|
// Determine if player has Hacknet Nodes or Hacknet Servers, then
|
||||||
// call the appropriate function
|
// call the appropriate function
|
||||||
if (Player.hacknetNodes.length === 0) {
|
if (player.hacknetNodes.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(player)) {
|
||||||
return processAllHacknetServerEarnings(numCycles);
|
return processAllHacknetServerEarnings(player, numCycles);
|
||||||
} else if (Player.hacknetNodes[0] instanceof HacknetNode) {
|
} else if (player.hacknetNodes[0] instanceof HacknetNode) {
|
||||||
return processAllHacknetNodeEarnings(numCycles);
|
return processAllHacknetNodeEarnings(player, numCycles);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processAllHacknetNodeEarnings(numCycles) {
|
function processAllHacknetNodeEarnings(player: IPlayer, numCycles: number): number {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
for (let i = 0; i < player.hacknetNodes.length; ++i) {
|
||||||
total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]);
|
const node = player.hacknetNodes[i];
|
||||||
|
if (typeof node === "string") throw new Error("player node should not be ip string");
|
||||||
|
total += processSingleHacknetNodeEarnings(player, numCycles, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
function processSingleHacknetNodeEarnings(numCycles, nodeObj) {
|
function processSingleHacknetNodeEarnings(player: IPlayer, numCycles: number, nodeObj: HacknetNode): number {
|
||||||
const totalEarnings = nodeObj.process(numCycles);
|
const totalEarnings = nodeObj.process(numCycles);
|
||||||
Player.gainMoney(totalEarnings);
|
player.gainMoney(totalEarnings);
|
||||||
Player.recordMoneySource(totalEarnings, "hacknetnode");
|
player.recordMoneySource(totalEarnings, "hacknetnode");
|
||||||
|
|
||||||
return totalEarnings;
|
return totalEarnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
function processAllHacknetServerEarnings(numCycles) {
|
function processAllHacknetServerEarnings(player: IPlayer, numCycles: number): number {
|
||||||
if (!(Player.hashManager instanceof HashManager)) {
|
if (!(player.hashManager instanceof HashManager)) {
|
||||||
throw new Error(`Player does not have a HashManager (should be in 'hashManager' prop)`);
|
throw new Error(`Player does not have a HashManager (should be in 'hashManager' prop)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hashes = 0;
|
let hashes = 0;
|
||||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
for (let i = 0; i < player.hacknetNodes.length; ++i) {
|
||||||
// hacknetNodes array only contains the IP addresses of the servers.
|
// hacknetNodes array only contains the IP addresses of the servers.
|
||||||
// Also, update the hash rate before processing
|
// Also, update the hash rate before processing
|
||||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
const ip = player.hacknetNodes[i];
|
||||||
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
if (ip instanceof HacknetNode) throw new Error(`player nodes should not be HacketNode`);
|
||||||
|
const hserver = AllServers[ip];
|
||||||
|
if (hserver instanceof Server) throw new Error(`player nodes shoud not be Server`);
|
||||||
|
hserver.updateHashRate(player.hacknet_node_money_mult);
|
||||||
const h = hserver.process(numCycles);
|
const h = hserver.process(numCycles);
|
||||||
hserver.totalHashesGenerated += h;
|
hserver.totalHashesGenerated += h;
|
||||||
hashes += h;
|
hashes += h;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.hashManager.storeHashes(hashes);
|
player.hashManager.storeHashes(hashes);
|
||||||
|
|
||||||
return hashes;
|
return hashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateHashManagerCapacity() {
|
export function updateHashManagerCapacity(player: IPlayer): void {
|
||||||
if (!(Player.hashManager instanceof HashManager)) {
|
if (!(player.hashManager instanceof HashManager)) {
|
||||||
console.error(`Player does not have a HashManager`);
|
console.error(`Player does not have a HashManager`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes = Player.hacknetNodes;
|
const nodes = player.hacknetNodes;
|
||||||
if (nodes.length === 0) {
|
if (nodes.length === 0) {
|
||||||
Player.hashManager.updateCapacity(0);
|
player.hashManager.updateCapacity(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
for (let i = 0; i < nodes.length; ++i) {
|
for (let i = 0; i < nodes.length; ++i) {
|
||||||
if (typeof nodes[i] !== "string") {
|
if (typeof nodes[i] !== "string") {
|
||||||
Player.hashManager.updateCapacity(0);
|
player.hashManager.updateCapacity(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const ip = nodes[i];
|
||||||
const h = AllServers[nodes[i]];
|
if (ip instanceof HacknetNode) throw new Error(`player nodes should be string but isn't`);
|
||||||
|
const h = AllServers[ip];
|
||||||
if (!(h instanceof HacknetServer)) {
|
if (!(h instanceof HacknetServer)) {
|
||||||
Player.hashManager.updateCapacity(0);
|
player.hashManager.updateCapacity(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
total += h.hashCapacity;
|
total += h.hashCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.hashManager.updateCapacity(total);
|
player.hashManager.updateCapacity(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseHashUpgrade(upgName, upgTarget) {
|
export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget: string): boolean {
|
||||||
if (!(Player.hashManager instanceof HashManager)) {
|
if (!(player.hashManager instanceof HashManager)) {
|
||||||
console.error(`Player does not have a HashManager`);
|
console.error(`Player does not have a HashManager`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashManager handles the transaction. This just needs to actually implement
|
// HashManager handles the transaction. This just needs to actually implement
|
||||||
// the effects of the upgrade
|
// the effects of the upgrade
|
||||||
if (Player.hashManager.upgrade(upgName)) {
|
if (player.hashManager.upgrade(upgName)) {
|
||||||
const upg = HashUpgrades[upgName];
|
const upg = HashUpgrades[upgName];
|
||||||
|
|
||||||
switch (upgName) {
|
switch (upgName) {
|
||||||
case "Sell for Money": {
|
case "Sell for Money": {
|
||||||
Player.gainMoney(upg.value);
|
player.gainMoney(upg.value);
|
||||||
Player.recordMoneySource(upg.value, "hacknetnode");
|
player.recordMoneySource(upg.value, "hacknetnode");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Sell for Corporation Funds": {
|
case "Sell for Corporation Funds": {
|
||||||
// This will throw if player doesn't have a corporation
|
// This will throw if player doesn't have a corporation
|
||||||
try {
|
try {
|
||||||
Player.corporation.funds = Player.corporation.funds.plus(upg.value);
|
player.corporation.funds = player.corporation.funds.plus(upg.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -505,10 +495,11 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!(target instanceof Server)) throw new Error(`'${upgTarget}' is not a normal server.`);
|
||||||
|
|
||||||
target.changeMinimumSecurity(upg.value, true);
|
target.changeMinimumSecurity(upg.value, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -520,10 +511,11 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!(target instanceof Server)) throw new Error(`'${upgTarget}' is not a normal server.`);
|
||||||
|
|
||||||
target.changeMaximumMoney(upg.value, true);
|
target.changeMaximumMoney(upg.value, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -539,11 +531,11 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
case "Exchange for Corporation Research": {
|
case "Exchange for Corporation Research": {
|
||||||
// This will throw if player doesn't have a corporation
|
// This will throw if player doesn't have a corporation
|
||||||
try {
|
try {
|
||||||
for (const division of Player.corporation.divisions) {
|
for (const division of player.corporation.divisions) {
|
||||||
division.sciResearch.qty += upg.value;
|
division.sciResearch.qty += upg.value;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -551,9 +543,9 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
case "Exchange for Bladeburner Rank": {
|
case "Exchange for Bladeburner Rank": {
|
||||||
// This will throw if player isnt in Bladeburner
|
// This will throw if player isnt in Bladeburner
|
||||||
try {
|
try {
|
||||||
Player.bladeburner.changeRank(Player, upg.value);
|
player.bladeburner.changeRank(player, upg.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -563,9 +555,9 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
try {
|
try {
|
||||||
// As long as we don't change `Bladeburner.totalSkillPoints`, this
|
// As long as we don't change `Bladeburner.totalSkillPoints`, this
|
||||||
// shouldn't affect anything else
|
// shouldn't affect anything else
|
||||||
Player.bladeburner.skillPoints += upg.value;
|
player.bladeburner.skillPoints += upg.value;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -576,7 +568,7 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`);
|
console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`);
|
||||||
Player.hashManager.refundUpgrade(upgName);
|
player.hashManager.refundUpgrade(upgName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +35,19 @@ export const HacknetNodeConstants: {
|
|||||||
MaxCores: 16,
|
MaxCores: 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PurchaseMultipliers: {
|
||||||
|
[key: string]: number | string | undefined;
|
||||||
|
x1: number;
|
||||||
|
x5: number;
|
||||||
|
x10: number;
|
||||||
|
MAX: string;
|
||||||
|
} = {
|
||||||
|
x1: 1,
|
||||||
|
x5: 5,
|
||||||
|
x10: 10,
|
||||||
|
MAX: "MAX",
|
||||||
|
};
|
||||||
|
|
||||||
export const HacknetServerConstants: {
|
export const HacknetServerConstants: {
|
||||||
// Constants for Hacknet Server stats/production
|
// Constants for Hacknet Server stats/production
|
||||||
HashesPerLevel: number;
|
HashesPerLevel: number;
|
||||||
|
@ -54,7 +54,7 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
|
|||||||
"Use hashes to improve the experience earned when studying at a university by 20%. " +
|
"Use hashes to improve the experience earned when studying at a university by 20%. " +
|
||||||
"This effect persists until you install Augmentations",
|
"This effect persists until you install Augmentations",
|
||||||
name: "Improve Studying",
|
name: "Improve Studying",
|
||||||
//effectText: (level: number) => JSX.Element | null = <>Improves studying by ${level*20}%</>,
|
effectText: (level: number): JSX.Element | null => <>Improves studying by {level * 20}%</>,
|
||||||
value: 20, // Improves studying by value%
|
value: 20, // Improves studying by value%
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -63,7 +63,7 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
|
|||||||
"Use hashes to improve the experience earned when training at the gym by 20%. This effect " +
|
"Use hashes to improve the experience earned when training at the gym by 20%. This effect " +
|
||||||
"persists until you install Augmentations",
|
"persists until you install Augmentations",
|
||||||
name: "Improve Gym Training",
|
name: "Improve Gym Training",
|
||||||
effectText: (level: number): JSX.Element | null => <>Improves training by ${level * 20}%</>,
|
effectText: (level: number): JSX.Element | null => <>Improves training by {level * 20}%</>,
|
||||||
value: 20, // Improves training by value%
|
value: 20, // Improves training by value%
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* React Component for the Hacknet Node UI
|
|
||||||
*
|
|
||||||
* Displays general information about Hacknet Nodes
|
|
||||||
*/
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { hasHacknetServers } from "../HacknetHelpers";
|
|
||||||
|
|
||||||
export class GeneralInfo extends React.Component {
|
|
||||||
getSecondParagraph() {
|
|
||||||
if (hasHacknetServers()) {
|
|
||||||
return (
|
|
||||||
`Here, you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. ` +
|
|
||||||
`Hacknet Servers will perform computations and operations on the network, earning ` +
|
|
||||||
`you hashes. Hashes can be spent on a variety of different upgrades.`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
`Here, you can purchase a Hacknet Node, a specialized machine that can connect ` +
|
|
||||||
`and contribute its resources to the Hacknet network. This allows you to take ` +
|
|
||||||
`a small percentage of profits from hacks performed on the network. Essentially, ` +
|
|
||||||
`you are renting out your Node's computing power.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getThirdParagraph() {
|
|
||||||
if (hasHacknetServers()) {
|
|
||||||
return (
|
|
||||||
`Hacknet Servers can also be used as servers to run scripts. However, running scripts ` +
|
|
||||||
`on a server will reduce its hash rate (hashes generated per second). A Hacknet Server's hash ` +
|
|
||||||
`rate will be reduced by the percentage of RAM that is being used by that Server to run ` +
|
|
||||||
`scripts.`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
`Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node ` +
|
|
||||||
`can be upgraded in order to increase its computing power and thereby increase ` +
|
|
||||||
`the profit you earn from it.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p className={"hacknet-general-info"}>
|
|
||||||
The Hacknet is a global, decentralized network of machines. It is used by hackers all around the world to
|
|
||||||
anonymously share computing power and perform distributed cyberattacks without the fear of being traced.
|
|
||||||
</p>
|
|
||||||
<p className={"hacknet-general-info"}>{this.getSecondParagraph()}</p>
|
|
||||||
<p className={"hacknet-general-info"}>{this.getThirdParagraph()}</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
50
src/Hacknet/ui/GeneralInfo.tsx
Normal file
50
src/Hacknet/ui/GeneralInfo.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* React Component for the Hacknet Node UI
|
||||||
|
*
|
||||||
|
* Displays general information about Hacknet Nodes
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
hasHacknetServers: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GeneralInfo(props: IProps): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p className={"hacknet-general-info"}>
|
||||||
|
The Hacknet is a global, decentralized network of machines. It is used by hackers all around the world to
|
||||||
|
anonymously share computing power and perform distributed cyberattacks without the fear of being traced.
|
||||||
|
</p>
|
||||||
|
{!props.hasHacknetServers ? (
|
||||||
|
<>
|
||||||
|
<p className={"hacknet-general-info"}>
|
||||||
|
{`Here, you can purchase a Hacknet Node, a specialized machine that can connect ` +
|
||||||
|
`and contribute its resources to the Hacknet network. This allows you to take ` +
|
||||||
|
`a small percentage of profits from hacks performed on the network. Essentially, ` +
|
||||||
|
`you are renting out your Node's computing power.`}
|
||||||
|
</p>
|
||||||
|
<p className={"hacknet-general-info"}>
|
||||||
|
{`Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node ` +
|
||||||
|
`can be upgraded in order to increase its computing power and thereby increase ` +
|
||||||
|
`the profit you earn from it.`}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p className={"hacknet-general-info"}>
|
||||||
|
{`Here, you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. ` +
|
||||||
|
`Hacknet Servers will perform computations and operations on the network, earning ` +
|
||||||
|
`you hashes. Hashes can be spent on a variety of different upgrades.`}
|
||||||
|
</p>
|
||||||
|
<p className={"hacknet-general-info"}>
|
||||||
|
{`Hacknet Servers can also be used as servers to run scripts. However, running scripts ` +
|
||||||
|
`on a server will reduce its hash rate (hashes generated per second). A Hacknet Server's hash ` +
|
||||||
|
`rate will be reduced by the percentage of RAM that is being used by that Server to run ` +
|
||||||
|
`scripts.`}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,171 +0,0 @@
|
|||||||
/**
|
|
||||||
* React Component for the Hacknet Node UI.
|
|
||||||
* This Component displays the panel for a single Hacknet Node
|
|
||||||
*/
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { HacknetNodeConstants } from "../data/Constants";
|
|
||||||
import {
|
|
||||||
getMaxNumberLevelUpgrades,
|
|
||||||
getMaxNumberRamUpgrades,
|
|
||||||
getMaxNumberCoreUpgrades,
|
|
||||||
purchaseLevelUpgrade,
|
|
||||||
purchaseRamUpgrade,
|
|
||||||
purchaseCoreUpgrade,
|
|
||||||
} from "../HacknetHelpers";
|
|
||||||
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
|
|
||||||
import { Money } from "../../ui/React/Money";
|
|
||||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
|
||||||
|
|
||||||
export class HacknetNode extends React.Component {
|
|
||||||
render() {
|
|
||||||
const node = this.props.node;
|
|
||||||
const purchaseMult = this.props.purchaseMultiplier;
|
|
||||||
const recalculate = this.props.recalculate;
|
|
||||||
|
|
||||||
// Upgrade Level Button
|
|
||||||
let upgradeLevelContent, upgradeLevelClass;
|
|
||||||
if (node.level >= HacknetNodeConstants.MaxLevel) {
|
|
||||||
upgradeLevelContent = <>MAX LEVEL</>;
|
|
||||||
upgradeLevelClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberLevelUpgrades(node, HacknetNodeConstants.MaxLevel);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.hacknet_node_level_cost_mult);
|
|
||||||
upgradeLevelContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeLevelCost)) {
|
|
||||||
upgradeLevelClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeLevelClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeLevelOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetNodeConstants.MaxLevel);
|
|
||||||
}
|
|
||||||
purchaseLevelUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let upgradeRamContent, upgradeRamClass;
|
|
||||||
if (node.ram >= HacknetNodeConstants.MaxRam) {
|
|
||||||
upgradeRamContent = <>MAX RAM</>;
|
|
||||||
upgradeRamClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram));
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.hacknet_node_ram_cost_mult);
|
|
||||||
upgradeRamContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeRamCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeRamCost)) {
|
|
||||||
upgradeRamClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeRamClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeRamOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam);
|
|
||||||
}
|
|
||||||
purchaseRamUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let upgradeCoresContent, upgradeCoresClass;
|
|
||||||
if (node.cores >= HacknetNodeConstants.MaxCores) {
|
|
||||||
upgradeCoresContent = <>MAX CORES</>;
|
|
||||||
upgradeCoresClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberCoreUpgrades(node, HacknetNodeConstants.MaxCores);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.hacknet_node_core_cost_mult);
|
|
||||||
upgradeCoresContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeCoreCost)) {
|
|
||||||
upgradeCoresClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeCoresClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeCoresOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetNodeConstants.MaxCores);
|
|
||||||
}
|
|
||||||
purchaseCoreUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className={"hacknet-node"}>
|
|
||||||
<div className={"hacknet-node-container"}>
|
|
||||||
<div className={"row"}>
|
|
||||||
<h1 style={{ fontSize: "1em" }}>{node.name}</h1>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Production:</p>
|
|
||||||
<span className={"text money-gold"}>
|
|
||||||
<Money money={node.totalMoneyGenerated} player={Player} /> ({MoneyRate(node.moneyGainRatePerSecond)})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Level:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.level}</span>
|
|
||||||
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
|
|
||||||
{upgradeLevelContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>RAM:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.ram}GB</span>
|
|
||||||
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
|
|
||||||
{upgradeRamContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Cores:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.cores}</span>
|
|
||||||
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
|
|
||||||
{upgradeCoresContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
174
src/Hacknet/ui/HacknetNodeElem.tsx
Normal file
174
src/Hacknet/ui/HacknetNodeElem.tsx
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* React Component for the Hacknet Node UI.
|
||||||
|
* This Component displays the panel for a single Hacknet Node
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { HacknetNodeConstants } from "../data/Constants";
|
||||||
|
import {
|
||||||
|
getMaxNumberLevelUpgrades,
|
||||||
|
getMaxNumberRamUpgrades,
|
||||||
|
getMaxNumberCoreUpgrades,
|
||||||
|
purchaseLevelUpgrade,
|
||||||
|
purchaseRamUpgrade,
|
||||||
|
purchaseCoreUpgrade,
|
||||||
|
} from "../HacknetHelpers";
|
||||||
|
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { HacknetNode } from "../HacknetNode";
|
||||||
|
|
||||||
|
import { Money } from "../../ui/React/Money";
|
||||||
|
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
node: HacknetNode;
|
||||||
|
purchaseMultiplier: number | string;
|
||||||
|
rerender: () => void;
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HacknetNodeElem(props: IProps): React.ReactElement {
|
||||||
|
const node = props.node;
|
||||||
|
const purchaseMult = props.purchaseMultiplier;
|
||||||
|
const rerender = props.rerender;
|
||||||
|
|
||||||
|
// Upgrade Level Button
|
||||||
|
let upgradeLevelContent, upgradeLevelClass;
|
||||||
|
if (node.level >= HacknetNodeConstants.MaxLevel) {
|
||||||
|
upgradeLevelContent = <>MAX LEVEL</>;
|
||||||
|
upgradeLevelClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
|
||||||
|
upgradeLevelContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeLevelCost)) {
|
||||||
|
upgradeLevelClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeLevelClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeLevelOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel);
|
||||||
|
}
|
||||||
|
purchaseLevelUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
let upgradeRamContent, upgradeRamClass;
|
||||||
|
if (node.ram >= HacknetNodeConstants.MaxRam) {
|
||||||
|
upgradeRamContent = <>MAX RAM</>;
|
||||||
|
upgradeRamClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram));
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
|
||||||
|
upgradeRamContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeRamCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeRamCost)) {
|
||||||
|
upgradeRamClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeRamClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeRamOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam);
|
||||||
|
}
|
||||||
|
purchaseRamUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
let upgradeCoresContent, upgradeCoresClass;
|
||||||
|
if (node.cores >= HacknetNodeConstants.MaxCores) {
|
||||||
|
upgradeCoresContent = <>MAX CORES</>;
|
||||||
|
upgradeCoresClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
|
||||||
|
upgradeCoresContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeCoreCost)) {
|
||||||
|
upgradeCoresClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeCoresClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeCoresOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores);
|
||||||
|
}
|
||||||
|
purchaseCoreUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className={"hacknet-node"}>
|
||||||
|
<div className={"hacknet-node-container"}>
|
||||||
|
<div className={"row"}>
|
||||||
|
<h1 style={{ fontSize: "1em" }}>{node.name}</h1>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Production:</p>
|
||||||
|
<span className={"text money-gold"}>
|
||||||
|
<Money money={node.totalMoneyGenerated} player={props.player} /> ({MoneyRate(node.moneyGainRatePerSecond)})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Level:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.level}</span>
|
||||||
|
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
|
||||||
|
{upgradeLevelContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>RAM:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.ram}GB</span>
|
||||||
|
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
|
||||||
|
{upgradeRamContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Cores:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.cores}</span>
|
||||||
|
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
|
||||||
|
{upgradeCoresContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
145
src/Hacknet/ui/HacknetRoot.tsx
Normal file
145
src/Hacknet/ui/HacknetRoot.tsx
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* Root React Component for the Hacknet Node UI
|
||||||
|
*/
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
import { GeneralInfo } from "./GeneralInfo";
|
||||||
|
import { HacknetNodeElem } from "./HacknetNodeElem";
|
||||||
|
import { HacknetServerElem } from "./HacknetServerElem";
|
||||||
|
import { HacknetNode } from "../HacknetNode";
|
||||||
|
import { HashUpgradePopup } from "./HashUpgradePopup";
|
||||||
|
import { MultiplierButtons } from "./MultiplierButtons";
|
||||||
|
import { PlayerInfo } from "./PlayerInfo";
|
||||||
|
import { PurchaseButton } from "./PurchaseButton";
|
||||||
|
import { PurchaseMultipliers } from "../data/Constants";
|
||||||
|
|
||||||
|
import {
|
||||||
|
getCostOfNextHacknetNode,
|
||||||
|
getCostOfNextHacknetServer,
|
||||||
|
hasHacknetServers,
|
||||||
|
purchaseHacknet,
|
||||||
|
} from "../HacknetHelpers";
|
||||||
|
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { AllServers } from "../../Server/AllServers";
|
||||||
|
import { Server } from "../../Server/Server";
|
||||||
|
|
||||||
|
import { createPopup } from "../../ui/React/createPopup";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HacknetRoot(props: IProps): React.ReactElement {
|
||||||
|
const setRerender = useState(false)[1];
|
||||||
|
function rerender(): void {
|
||||||
|
setRerender((old) => !old);
|
||||||
|
}
|
||||||
|
const [purchaseMultiplier, setPurchaseMultiplier] = useState<number | string>(PurchaseMultipliers.x1);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const id = setInterval(rerender, 1000);
|
||||||
|
return () => clearInterval(id);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function createHashUpgradesPopup(): void {
|
||||||
|
const id = "hacknet-server-hash-upgrades-popup";
|
||||||
|
createPopup(id, HashUpgradePopup, {
|
||||||
|
player: props.player,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let totalProduction = 0;
|
||||||
|
for (let i = 0; i < props.player.hacknetNodes.length; ++i) {
|
||||||
|
const node = props.player.hacknetNodes[i];
|
||||||
|
if (hasHacknetServers(props.player)) {
|
||||||
|
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
|
||||||
|
const hserver = AllServers[node];
|
||||||
|
if (hserver instanceof Server) throw new Error("node was a normal server"); // should never happen
|
||||||
|
if (hserver) {
|
||||||
|
totalProduction += hserver.hashRate;
|
||||||
|
} else {
|
||||||
|
console.warn(`Could not find Hacknet Server object in AllServers map (i=${i})`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof node === "string") throw new Error("node was ip string"); // should never happen
|
||||||
|
totalProduction += node.moneyGainRatePerSecond;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePurchaseButtonClick(): void {
|
||||||
|
purchaseHacknet(props.player);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cost to purchase a new Hacknet Node
|
||||||
|
let purchaseCost;
|
||||||
|
if (hasHacknetServers(props.player)) {
|
||||||
|
purchaseCost = getCostOfNextHacknetServer(props.player);
|
||||||
|
} else {
|
||||||
|
purchaseCost = getCostOfNextHacknetNode(props.player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// onClick event handlers for purchase multiplier buttons
|
||||||
|
const purchaseMultiplierOnClicks = [
|
||||||
|
() => setPurchaseMultiplier(PurchaseMultipliers.x1),
|
||||||
|
() => setPurchaseMultiplier(PurchaseMultipliers.x5),
|
||||||
|
() => setPurchaseMultiplier(PurchaseMultipliers.x10),
|
||||||
|
() => setPurchaseMultiplier(PurchaseMultipliers.MAX),
|
||||||
|
];
|
||||||
|
|
||||||
|
// HacknetNode components
|
||||||
|
const nodes = props.player.hacknetNodes.map((node: string | HacknetNode) => {
|
||||||
|
if (hasHacknetServers(props.player)) {
|
||||||
|
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
|
||||||
|
const hserver = AllServers[node];
|
||||||
|
if (hserver == null) {
|
||||||
|
throw new Error(`Could not find Hacknet Server object in AllServers map for IP: ${node}`);
|
||||||
|
}
|
||||||
|
if (hserver instanceof Server) throw new Error("node was normal server"); // should never happen
|
||||||
|
return (
|
||||||
|
<HacknetServerElem
|
||||||
|
player={props.player}
|
||||||
|
key={hserver.hostname}
|
||||||
|
node={hserver}
|
||||||
|
purchaseMultiplier={purchaseMultiplier}
|
||||||
|
rerender={rerender}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (typeof node === "string") throw new Error("node was ip string"); // should never happen
|
||||||
|
return (
|
||||||
|
<HacknetNodeElem
|
||||||
|
player={props.player}
|
||||||
|
key={node.name}
|
||||||
|
node={node}
|
||||||
|
purchaseMultiplier={purchaseMultiplier}
|
||||||
|
rerender={rerender}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Hacknet {hasHacknetServers(props.player) ? "Servers" : "Nodes"}</h1>
|
||||||
|
<GeneralInfo hasHacknetServers={hasHacknetServers(props.player)} />
|
||||||
|
|
||||||
|
<PurchaseButton cost={purchaseCost} multiplier={purchaseMultiplier} onClick={handlePurchaseButtonClick} />
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div id={"hacknet-nodes-money-multipliers-div"}>
|
||||||
|
<PlayerInfo totalProduction={totalProduction} player={props.player} />
|
||||||
|
<MultiplierButtons onClicks={purchaseMultiplierOnClicks} purchaseMultiplier={purchaseMultiplier} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{hasHacknetServers(props.player) && (
|
||||||
|
<button className={"std-button"} onClick={createHashUpgradesPopup} style={{ display: "block" }}>
|
||||||
|
{"Spend Hashes on Upgrades"}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ul id={"hacknet-nodes-list"}>{nodes}</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,225 +0,0 @@
|
|||||||
/**
|
|
||||||
* React Component for the Hacknet Node UI.
|
|
||||||
* This Component displays the panel for a single Hacknet Node
|
|
||||||
*/
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { HacknetServerConstants } from "../data/Constants";
|
|
||||||
import {
|
|
||||||
getMaxNumberLevelUpgrades,
|
|
||||||
getMaxNumberRamUpgrades,
|
|
||||||
getMaxNumberCoreUpgrades,
|
|
||||||
getMaxNumberCacheUpgrades,
|
|
||||||
purchaseLevelUpgrade,
|
|
||||||
purchaseRamUpgrade,
|
|
||||||
purchaseCoreUpgrade,
|
|
||||||
purchaseCacheUpgrade,
|
|
||||||
updateHashManagerCapacity,
|
|
||||||
} from "../HacknetHelpers";
|
|
||||||
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
|
|
||||||
import { Money } from "../../ui/React/Money";
|
|
||||||
import { Hashes } from "../../ui/React/Hashes";
|
|
||||||
import { HashRate } from "../../ui/React/HashRate";
|
|
||||||
|
|
||||||
export class HacknetServer extends React.Component {
|
|
||||||
render() {
|
|
||||||
const node = this.props.node;
|
|
||||||
const purchaseMult = this.props.purchaseMultiplier;
|
|
||||||
const recalculate = this.props.recalculate;
|
|
||||||
|
|
||||||
// Upgrade Level Button
|
|
||||||
let upgradeLevelContent, upgradeLevelClass;
|
|
||||||
if (node.level >= HacknetServerConstants.MaxLevel) {
|
|
||||||
upgradeLevelContent = <>MAX LEVEL</>;
|
|
||||||
upgradeLevelClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberLevelUpgrades(node, HacknetServerConstants.MaxLevel);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = HacknetServerConstants.MaxLevel - node.level;
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.hacknet_node_level_cost_mult);
|
|
||||||
upgradeLevelContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeLevelCost)) {
|
|
||||||
upgradeLevelClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeLevelClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeLevelOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetServerConstants.MaxLevel);
|
|
||||||
}
|
|
||||||
purchaseLevelUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Upgrade RAM Button
|
|
||||||
let upgradeRamContent, upgradeRamClass;
|
|
||||||
if (node.maxRam >= HacknetServerConstants.MaxRam) {
|
|
||||||
upgradeRamContent = <>MAX RAM</>;
|
|
||||||
upgradeRamClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberRamUpgrades(node, HacknetServerConstants.MaxRam);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = Math.round(Math.log2(HacknetServerConstants.MaxRam / node.maxRam));
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.hacknet_node_ram_cost_mult);
|
|
||||||
upgradeRamContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeRamCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeRamCost)) {
|
|
||||||
upgradeRamClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeRamClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeRamOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberRamUpgrades(node, HacknetServerConstants.MaxRam);
|
|
||||||
}
|
|
||||||
purchaseRamUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Upgrade Cores Button
|
|
||||||
let upgradeCoresContent, upgradeCoresClass;
|
|
||||||
if (node.cores >= HacknetServerConstants.MaxCores) {
|
|
||||||
upgradeCoresContent = <>MAX CORES</>;
|
|
||||||
upgradeCoresClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberCoreUpgrades(node, HacknetServerConstants.MaxCores);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = HacknetServerConstants.MaxCores - node.cores;
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.hacknet_node_core_cost_mult);
|
|
||||||
upgradeCoresContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeCoreCost)) {
|
|
||||||
upgradeCoresClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeCoresClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeCoresOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetServerConstants.MaxCores);
|
|
||||||
}
|
|
||||||
purchaseCoreUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Upgrade Cache button
|
|
||||||
let upgradeCacheContent, upgradeCacheClass;
|
|
||||||
if (node.cache >= HacknetServerConstants.MaxCache) {
|
|
||||||
upgradeCacheContent = <>MAX CACHE</>;
|
|
||||||
upgradeCacheClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
let multiplier = 0;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
multiplier = getMaxNumberCacheUpgrades(node, HacknetServerConstants.MaxCache);
|
|
||||||
} else {
|
|
||||||
const levelsToMax = HacknetServerConstants.MaxCache - node.cache;
|
|
||||||
multiplier = Math.min(levelsToMax, purchaseMult);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier);
|
|
||||||
upgradeCacheContent = (
|
|
||||||
<>
|
|
||||||
Upgrade x{multiplier} - <Money money={upgradeCacheCost} player={Player} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
if (Player.money.lt(upgradeCacheCost)) {
|
|
||||||
upgradeCacheClass = "std-button-disabled";
|
|
||||||
} else {
|
|
||||||
upgradeCacheClass = "std-button";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const upgradeCacheOnClick = () => {
|
|
||||||
let numUpgrades = purchaseMult;
|
|
||||||
if (purchaseMult === "MAX") {
|
|
||||||
numUpgrades = getMaxNumberCacheUpgrades(node, HacknetServerConstants.MaxCache);
|
|
||||||
}
|
|
||||||
purchaseCacheUpgrade(node, numUpgrades);
|
|
||||||
recalculate();
|
|
||||||
updateHashManagerCapacity();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className={"hacknet-node"}>
|
|
||||||
<div className={"hacknet-node-container"}>
|
|
||||||
<div className={"row"}>
|
|
||||||
<h1 style={{ fontSize: "1em" }}>{node.hostname}</h1>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Production:</p>
|
|
||||||
<span className={"text money-gold"}>
|
|
||||||
{Hashes(node.totalHashesGenerated)} ({HashRate(node.hashRate)})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Hash Capacity:</p>
|
|
||||||
<span className={"text"}>{Hashes(node.hashCapacity)}</span>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Level:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.level}</span>
|
|
||||||
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
|
|
||||||
{upgradeLevelContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>RAM:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.maxRam}GB</span>
|
|
||||||
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
|
|
||||||
{upgradeRamContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Cores:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.cores}</span>
|
|
||||||
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
|
|
||||||
{upgradeCoresContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className={"row"}>
|
|
||||||
<p>Cache Level:</p>
|
|
||||||
<span className={"text upgradable-info"}>{node.cache}</span>
|
|
||||||
<button className={upgradeCacheClass} onClick={upgradeCacheOnClick}>
|
|
||||||
{upgradeCacheContent}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
227
src/Hacknet/ui/HacknetServerElem.tsx
Normal file
227
src/Hacknet/ui/HacknetServerElem.tsx
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/**
|
||||||
|
* React Component for the Hacknet Node UI.
|
||||||
|
* This Component displays the panel for a single Hacknet Node
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { HacknetServerConstants } from "../data/Constants";
|
||||||
|
import {
|
||||||
|
getMaxNumberLevelUpgrades,
|
||||||
|
getMaxNumberRamUpgrades,
|
||||||
|
getMaxNumberCoreUpgrades,
|
||||||
|
getMaxNumberCacheUpgrades,
|
||||||
|
purchaseLevelUpgrade,
|
||||||
|
purchaseRamUpgrade,
|
||||||
|
purchaseCoreUpgrade,
|
||||||
|
purchaseCacheUpgrade,
|
||||||
|
updateHashManagerCapacity,
|
||||||
|
} from "../HacknetHelpers";
|
||||||
|
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { HacknetServer } from "../HacknetServer";
|
||||||
|
|
||||||
|
import { Money } from "../../ui/React/Money";
|
||||||
|
import { Hashes } from "../../ui/React/Hashes";
|
||||||
|
import { HashRate } from "../../ui/React/HashRate";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
node: HacknetServer;
|
||||||
|
purchaseMultiplier: number | string;
|
||||||
|
rerender: () => void;
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HacknetServerElem(props: IProps): React.ReactElement {
|
||||||
|
const node = props.node;
|
||||||
|
const purchaseMult = props.purchaseMultiplier;
|
||||||
|
const rerender = props.rerender;
|
||||||
|
|
||||||
|
// Upgrade Level Button
|
||||||
|
let upgradeLevelContent, upgradeLevelClass;
|
||||||
|
if (node.level >= HacknetServerConstants.MaxLevel) {
|
||||||
|
upgradeLevelContent = <>MAX LEVEL</>;
|
||||||
|
upgradeLevelClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberLevelUpgrades(props.player, node, HacknetServerConstants.MaxLevel);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = HacknetServerConstants.MaxLevel - node.level;
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
|
||||||
|
upgradeLevelContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeLevelCost)) {
|
||||||
|
upgradeLevelClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeLevelClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeLevelOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberLevelUpgrades(props.player, node, HacknetServerConstants.MaxLevel);
|
||||||
|
}
|
||||||
|
purchaseLevelUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade RAM Button
|
||||||
|
let upgradeRamContent, upgradeRamClass;
|
||||||
|
if (node.maxRam >= HacknetServerConstants.MaxRam) {
|
||||||
|
upgradeRamContent = <>MAX RAM</>;
|
||||||
|
upgradeRamClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetServerConstants.MaxRam);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = Math.round(Math.log2(HacknetServerConstants.MaxRam / node.maxRam));
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
|
||||||
|
upgradeRamContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeRamCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeRamCost)) {
|
||||||
|
upgradeRamClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeRamClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeRamOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberRamUpgrades(props.player, node, HacknetServerConstants.MaxRam);
|
||||||
|
}
|
||||||
|
purchaseRamUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade Cores Button
|
||||||
|
let upgradeCoresContent, upgradeCoresClass;
|
||||||
|
if (node.cores >= HacknetServerConstants.MaxCores) {
|
||||||
|
upgradeCoresContent = <>MAX CORES</>;
|
||||||
|
upgradeCoresClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetServerConstants.MaxCores);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = HacknetServerConstants.MaxCores - node.cores;
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
|
||||||
|
upgradeCoresContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeCoreCost)) {
|
||||||
|
upgradeCoresClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeCoresClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeCoresOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberCoreUpgrades(props.player, node, HacknetServerConstants.MaxCores);
|
||||||
|
}
|
||||||
|
purchaseCoreUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade Cache button
|
||||||
|
let upgradeCacheContent, upgradeCacheClass;
|
||||||
|
if (node.cache >= HacknetServerConstants.MaxCache) {
|
||||||
|
upgradeCacheContent = <>MAX CACHE</>;
|
||||||
|
upgradeCacheClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
let multiplier = 0;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
multiplier = getMaxNumberCacheUpgrades(props.player, node, HacknetServerConstants.MaxCache);
|
||||||
|
} else {
|
||||||
|
const levelsToMax = HacknetServerConstants.MaxCache - node.cache;
|
||||||
|
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier);
|
||||||
|
upgradeCacheContent = (
|
||||||
|
<>
|
||||||
|
Upgrade x{multiplier} - <Money money={upgradeCacheCost} player={props.player} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (props.player.money.lt(upgradeCacheCost)) {
|
||||||
|
upgradeCacheClass = "std-button-disabled";
|
||||||
|
} else {
|
||||||
|
upgradeCacheClass = "std-button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function upgradeCacheOnClick(): void {
|
||||||
|
let numUpgrades = purchaseMult;
|
||||||
|
if (purchaseMult === "MAX") {
|
||||||
|
numUpgrades = getMaxNumberCacheUpgrades(props.player, node, HacknetServerConstants.MaxCache);
|
||||||
|
}
|
||||||
|
purchaseCacheUpgrade(props.player, node, numUpgrades as number);
|
||||||
|
rerender();
|
||||||
|
updateHashManagerCapacity(props.player);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className={"hacknet-node"}>
|
||||||
|
<div className={"hacknet-node-container"}>
|
||||||
|
<div className={"row"}>
|
||||||
|
<h1 style={{ fontSize: "1em" }}>{node.hostname}</h1>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Production:</p>
|
||||||
|
<span className={"text money-gold"}>
|
||||||
|
{Hashes(node.totalHashesGenerated)} ({HashRate(node.hashRate)})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Hash Capacity:</p>
|
||||||
|
<span className={"text"}>{Hashes(node.hashCapacity)}</span>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Level:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.level}</span>
|
||||||
|
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
|
||||||
|
{upgradeLevelContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>RAM:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.maxRam}GB</span>
|
||||||
|
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
|
||||||
|
{upgradeRamContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Cores:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.cores}</span>
|
||||||
|
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
|
||||||
|
{upgradeCoresContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={"row"}>
|
||||||
|
<p>Cache Level:</p>
|
||||||
|
<span className={"text upgradable-info"}>{node.cache}</span>
|
||||||
|
<button className={upgradeCacheClass} onClick={upgradeCacheOnClick}>
|
||||||
|
{upgradeCacheContent}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
70
src/Hacknet/ui/HacknetUpgradeElem.tsx
Normal file
70
src/Hacknet/ui/HacknetUpgradeElem.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
import { purchaseHashUpgrade } from "../HacknetHelpers";
|
||||||
|
import { HashManager } from "../HashManager";
|
||||||
|
import { HashUpgrade } from "../HashUpgrade";
|
||||||
|
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown";
|
||||||
|
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { CopyableText } from "../../ui/React/CopyableText";
|
||||||
|
import { Hashes } from "../../ui/React/Hashes";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
player: IPlayer;
|
||||||
|
hashManager: HashManager;
|
||||||
|
upg: HashUpgrade;
|
||||||
|
rerender: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HacknetUpgradeElem(props: IProps): React.ReactElement {
|
||||||
|
const [selectedServer, setSelectedServer] = useState("ecorp");
|
||||||
|
function changeTargetServer(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
setSelectedServer(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function purchase(): void {
|
||||||
|
const canPurchase = props.hashManager.hashes >= props.hashManager.getUpgradeCost(props.upg.name);
|
||||||
|
if (canPurchase) {
|
||||||
|
const res = purchaseHashUpgrade(props.player, props.upg.name, selectedServer);
|
||||||
|
if (!res) {
|
||||||
|
dialogBoxCreate(
|
||||||
|
"Failed to purchase upgrade. This may be because you do not have enough hashes, " +
|
||||||
|
"or because you do not have access to the feature upgrade affects.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
props.rerender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashManager = props.hashManager;
|
||||||
|
const upg = props.upg;
|
||||||
|
const cost = hashManager.getUpgradeCost(upg.name);
|
||||||
|
const level = hashManager.upgrades[upg.name];
|
||||||
|
const effect = upg.effectText(level);
|
||||||
|
|
||||||
|
// Purchase button
|
||||||
|
const canPurchase = hashManager.hashes >= cost;
|
||||||
|
const btnClass = canPurchase ? "std-button" : "std-button-disabled";
|
||||||
|
|
||||||
|
// We'll reuse a Bladeburner css class
|
||||||
|
return (
|
||||||
|
<div className={"bladeburner-action"}>
|
||||||
|
<CopyableText value={upg.name} />
|
||||||
|
<p>
|
||||||
|
Cost: {Hashes(cost)}, Bought: {level} times
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>{upg.desc}</p>
|
||||||
|
<button className={btnClass} onClick={purchase}>
|
||||||
|
Purchase
|
||||||
|
</button>
|
||||||
|
{level > 0 && effect && <p>{effect}</p>}
|
||||||
|
{upg.hasTargetServer && (
|
||||||
|
<ServerDropdown serverType={ServerType.Foreign} onChange={changeTargetServer} style={{ margin: "5px" }} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,133 +0,0 @@
|
|||||||
/**
|
|
||||||
* Create the pop-up for purchasing upgrades with hashes
|
|
||||||
*/
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { purchaseHashUpgrade } from "../HacknetHelpers";
|
|
||||||
import { HashManager } from "../HashManager";
|
|
||||||
import { HashUpgrades } from "../HashUpgrades";
|
|
||||||
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
|
||||||
|
|
||||||
import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown";
|
|
||||||
|
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
|
||||||
import { CopyableText } from "../../ui/React/CopyableText";
|
|
||||||
import { Hashes } from "../../ui/React/Hashes";
|
|
||||||
|
|
||||||
class HashUpgrade extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
selectedServer: "ecorp",
|
|
||||||
};
|
|
||||||
|
|
||||||
this.changeTargetServer = this.changeTargetServer.bind(this);
|
|
||||||
this.purchase = this.purchase.bind(this, this.props.hashManager, this.props.upg);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeTargetServer(e) {
|
|
||||||
this.setState({
|
|
||||||
selectedServer: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
purchase(hashManager, upg) {
|
|
||||||
const canPurchase = hashManager.hashes >= hashManager.getUpgradeCost(upg.name);
|
|
||||||
if (canPurchase) {
|
|
||||||
const res = purchaseHashUpgrade(upg.name, this.state.selectedServer);
|
|
||||||
if (res) {
|
|
||||||
this.props.rerender();
|
|
||||||
} else {
|
|
||||||
dialogBoxCreate(
|
|
||||||
"Failed to purchase upgrade. This may be because you do not have enough hashes, " +
|
|
||||||
"or because you do not have access to the feature this upgrade affects.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const hashManager = this.props.hashManager;
|
|
||||||
const upg = this.props.upg;
|
|
||||||
const cost = hashManager.getUpgradeCost(upg.name);
|
|
||||||
const level = hashManager.upgrades[upg.name];
|
|
||||||
const effect = upg.effectText(level);
|
|
||||||
|
|
||||||
// Purchase button
|
|
||||||
const canPurchase = hashManager.hashes >= cost;
|
|
||||||
const btnClass = canPurchase ? "std-button" : "std-button-disabled";
|
|
||||||
|
|
||||||
// We'll reuse a Bladeburner css class
|
|
||||||
return (
|
|
||||||
<div className={"bladeburner-action"}>
|
|
||||||
<CopyableText value={upg.name} />
|
|
||||||
<p>
|
|
||||||
Cost: {Hashes(cost)}, Bought: {level} times
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>{upg.desc}</p>
|
|
||||||
<button className={btnClass} onClick={this.purchase}>
|
|
||||||
Purchase
|
|
||||||
</button>
|
|
||||||
{level > 0 && effect && <p>{effect}</p>}
|
|
||||||
{upg.hasTargetServer && (
|
|
||||||
<ServerDropdown
|
|
||||||
serverType={ServerType.Foreign}
|
|
||||||
onChange={this.changeTargetServer}
|
|
||||||
style={{ margin: "5px" }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HashUpgradePopup extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
totalHashes: Player.hashManager.hashes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.interval = setInterval(() => this.tick(), 1e3);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
clearInterval(this.interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
tick() {
|
|
||||||
this.setState({
|
|
||||||
totalHashes: Player.hashManager.hashes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const rerender = this.props.rerender;
|
|
||||||
|
|
||||||
const hashManager = Player.hashManager;
|
|
||||||
if (!(hashManager instanceof HashManager)) {
|
|
||||||
throw new Error(`Player does not have a HashManager)`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgradeElems = Object.keys(HashUpgrades).map((upgName) => {
|
|
||||||
const upg = HashUpgrades[upgName];
|
|
||||||
return <HashUpgrade upg={upg} hashManager={hashManager} key={upg.name} rerender={rerender} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p>Spend your hashes on a variety of different upgrades</p>
|
|
||||||
<p>Hashes: {numeralWrapper.formatHashes(this.state.totalHashes)}</p>
|
|
||||||
{upgradeElems}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
54
src/Hacknet/ui/HashUpgradePopup.tsx
Normal file
54
src/Hacknet/ui/HashUpgradePopup.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Create the pop-up for purchasing upgrades with hashes
|
||||||
|
*/
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
import { HashManager } from "../HashManager";
|
||||||
|
import { HashUpgrades } from "../HashUpgrades";
|
||||||
|
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
import { Hashes } from "../../ui/React/Hashes";
|
||||||
|
import { HacknetUpgradeElem } from "./HacknetUpgradeElem";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HashUpgradePopup(props: IProps): React.ReactElement {
|
||||||
|
const setRerender = useState(false)[1];
|
||||||
|
function rerender(): void {
|
||||||
|
setRerender((old) => !old);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const id = setInterval(() => setRerender((old) => !old), 1000);
|
||||||
|
return () => clearInterval(id);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const hashManager = props.player.hashManager;
|
||||||
|
if (!(hashManager instanceof HashManager)) {
|
||||||
|
throw new Error(`Player does not have a HashManager)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgradeElems = Object.keys(HashUpgrades).map((upgName) => {
|
||||||
|
const upg = HashUpgrades[upgName];
|
||||||
|
return (
|
||||||
|
<HacknetUpgradeElem
|
||||||
|
player={props.player}
|
||||||
|
upg={upg}
|
||||||
|
hashManager={hashManager}
|
||||||
|
key={upg.name}
|
||||||
|
rerender={rerender}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Spend your hashes on a variety of different upgrades</p>
|
||||||
|
<p>Hashes: {Hashes(props.player.hashManager.hashes)}</p>
|
||||||
|
{upgradeElems}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -5,9 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { PurchaseMultipliers } from "./Root";
|
import { PurchaseMultipliers } from "../data/Constants";
|
||||||
|
|
||||||
function MultiplierButton(props) {
|
interface IMultiplierProps {
|
||||||
|
className: string;
|
||||||
|
key: string;
|
||||||
|
onClick: () => void;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MultiplierButton(props: IMultiplierProps): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<button className={props.className} onClick={props.onClick}>
|
<button className={props.className} onClick={props.onClick}>
|
||||||
{props.text}
|
{props.text}
|
||||||
@ -15,7 +22,12 @@ function MultiplierButton(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MultiplierButtons(props) {
|
interface IProps {
|
||||||
|
purchaseMultiplier: number | string;
|
||||||
|
onClicks: (() => void)[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MultiplierButtons(props: IProps): React.ReactElement {
|
||||||
if (props.purchaseMultiplier == null) {
|
if (props.purchaseMultiplier == null) {
|
||||||
throw new Error(`MultiplierButtons constructed without required props`);
|
throw new Error(`MultiplierButtons constructed without required props`);
|
||||||
}
|
}
|
@ -7,14 +7,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { hasHacknetServers } from "../HacknetHelpers";
|
import { hasHacknetServers } from "../HacknetHelpers";
|
||||||
import { Player } from "../../Player";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||||
import { HashRate } from "../../ui/React/HashRate";
|
import { HashRate } from "../../ui/React/HashRate";
|
||||||
import { Hashes } from "../../ui/React/Hashes";
|
import { Hashes } from "../../ui/React/Hashes";
|
||||||
|
|
||||||
export function PlayerInfo(props) {
|
interface IProps {
|
||||||
const hasServers = hasHacknetServers();
|
totalProduction: number;
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlayerInfo(props: IProps): React.ReactElement {
|
||||||
|
const hasServers = hasHacknetServers(props.player);
|
||||||
|
|
||||||
let prod;
|
let prod;
|
||||||
if (hasServers) {
|
if (hasServers) {
|
||||||
@ -26,13 +31,13 @@ export function PlayerInfo(props) {
|
|||||||
return (
|
return (
|
||||||
<p id={"hacknet-nodes-money"}>
|
<p id={"hacknet-nodes-money"}>
|
||||||
<span>Money: </span>
|
<span>Money: </span>
|
||||||
<Money money={Player.money.toNumber()} />
|
<Money money={props.player.money.toNumber()} />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{hasServers && (
|
{hasServers && (
|
||||||
<>
|
<>
|
||||||
<span>
|
<span>
|
||||||
Hashes: {Hashes(Player.hashManager.hashes)} / {Hashes(Player.hashManager.capacity)}
|
Hashes: {Hashes(props.player.hashManager.hashes)} / {Hashes(props.player.hashManager.capacity)}
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
</>
|
</>
|
@ -7,17 +7,19 @@ import { hasHacknetServers, hasMaxNumberHacknetServers } from "../HacknetHelpers
|
|||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
|
|
||||||
export function PurchaseButton(props) {
|
interface IProps {
|
||||||
if (props.multiplier == null || props.onClick == null) {
|
multiplier: number | string;
|
||||||
throw new Error(`PurchaseButton constructed without required props`);
|
onClick: () => void;
|
||||||
}
|
cost: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PurchaseButton(props: IProps): React.ReactElement {
|
||||||
const cost = props.cost;
|
const cost = props.cost;
|
||||||
let className = Player.canAfford(cost) ? "std-button" : "std-button-disabled";
|
let className = Player.canAfford(cost) ? "std-button" : "std-button-disabled";
|
||||||
let text;
|
let text;
|
||||||
let style = null;
|
let style = {};
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(Player)) {
|
||||||
if (hasMaxNumberHacknetServers()) {
|
if (hasMaxNumberHacknetServers(Player)) {
|
||||||
className = "std-button-disabled";
|
className = "std-button-disabled";
|
||||||
text = <>Hacknet Server limit reached</>;
|
text = <>Hacknet Server limit reached</>;
|
||||||
style = { color: "red" };
|
style = { color: "red" };
|
@ -1,162 +0,0 @@
|
|||||||
/**
|
|
||||||
* Root React Component for the Hacknet Node UI
|
|
||||||
*/
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { GeneralInfo } from "./GeneralInfo";
|
|
||||||
import { HacknetNode } from "./HacknetNode";
|
|
||||||
import { HacknetServer } from "./HacknetServer";
|
|
||||||
import { HashUpgradePopup } from "./HashUpgradePopup";
|
|
||||||
import { MultiplierButtons } from "./MultiplierButtons";
|
|
||||||
import { PlayerInfo } from "./PlayerInfo";
|
|
||||||
import { PurchaseButton } from "./PurchaseButton";
|
|
||||||
|
|
||||||
import {
|
|
||||||
getCostOfNextHacknetNode,
|
|
||||||
getCostOfNextHacknetServer,
|
|
||||||
hasHacknetServers,
|
|
||||||
purchaseHacknet,
|
|
||||||
} from "../HacknetHelpers";
|
|
||||||
|
|
||||||
import { Player } from "../../Player";
|
|
||||||
import { AllServers } from "../../Server/AllServers";
|
|
||||||
|
|
||||||
import { createPopup } from "../../ui/React/createPopup";
|
|
||||||
|
|
||||||
export const PurchaseMultipliers = Object.freeze({
|
|
||||||
x1: 1,
|
|
||||||
x5: 5,
|
|
||||||
x10: 10,
|
|
||||||
MAX: "MAX",
|
|
||||||
});
|
|
||||||
|
|
||||||
export class HacknetRoot extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
purchaseMultiplier: PurchaseMultipliers.x1,
|
|
||||||
totalProduction: 0, // Total production ($ / s) of Hacknet Nodes
|
|
||||||
};
|
|
||||||
|
|
||||||
this.createHashUpgradesPopup = this.createHashUpgradesPopup.bind(this);
|
|
||||||
this.handlePurchaseButtonClick = this.handlePurchaseButtonClick.bind(this);
|
|
||||||
this.recalculateTotalProduction = this.recalculateTotalProduction.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.recalculateTotalProduction();
|
|
||||||
}
|
|
||||||
|
|
||||||
createHashUpgradesPopup() {
|
|
||||||
const id = "hacknet-server-hash-upgrades-popup";
|
|
||||||
createPopup(id, HashUpgradePopup, {
|
|
||||||
popupId: id,
|
|
||||||
rerender: this.createHashUpgradesPopup,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePurchaseButtonClick() {
|
|
||||||
if (purchaseHacknet() >= 0) {
|
|
||||||
this.recalculateTotalProduction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
recalculateTotalProduction() {
|
|
||||||
let total = 0;
|
|
||||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
|
||||||
if (hasHacknetServers()) {
|
|
||||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
|
||||||
if (hserver) {
|
|
||||||
total += hserver.hashRate;
|
|
||||||
} else {
|
|
||||||
console.warn(`Could not find Hacknet Server object in AllServers map (i=${i})`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
total += Player.hacknetNodes[i].moneyGainRatePerSecond;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
totalProduction: total,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setPurchaseMultiplier(mult) {
|
|
||||||
this.setState({
|
|
||||||
purchaseMultiplier: mult,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
// Cost to purchase a new Hacknet Node
|
|
||||||
let purchaseCost;
|
|
||||||
if (hasHacknetServers()) {
|
|
||||||
purchaseCost = getCostOfNextHacknetServer();
|
|
||||||
} else {
|
|
||||||
purchaseCost = getCostOfNextHacknetNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
// onClick event handlers for purchase multiplier buttons
|
|
||||||
const purchaseMultiplierOnClicks = [
|
|
||||||
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x1),
|
|
||||||
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x5),
|
|
||||||
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x10),
|
|
||||||
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.MAX),
|
|
||||||
];
|
|
||||||
|
|
||||||
// HacknetNode components
|
|
||||||
const nodes = Player.hacknetNodes.map((node) => {
|
|
||||||
if (hasHacknetServers()) {
|
|
||||||
const hserver = AllServers[node];
|
|
||||||
if (hserver == null) {
|
|
||||||
throw new Error(`Could not find Hacknet Server object in AllServers map for IP: ${node}`);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<HacknetServer
|
|
||||||
key={hserver.hostname}
|
|
||||||
node={hserver}
|
|
||||||
purchaseMultiplier={this.state.purchaseMultiplier}
|
|
||||||
recalculate={this.recalculateTotalProduction}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<HacknetNode
|
|
||||||
key={node.name}
|
|
||||||
node={node}
|
|
||||||
purchaseMultiplier={this.state.purchaseMultiplier}
|
|
||||||
recalculate={this.recalculateTotalProduction}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Hacknet {hasHacknetServers() ? "Servers" : "Nodes"}</h1>
|
|
||||||
<GeneralInfo />
|
|
||||||
|
|
||||||
<PurchaseButton
|
|
||||||
cost={purchaseCost}
|
|
||||||
multiplier={this.state.purchaseMultiplier}
|
|
||||||
onClick={this.handlePurchaseButtonClick}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<div id={"hacknet-nodes-money-multipliers-div"}>
|
|
||||||
<PlayerInfo totalProduction={this.state.totalProduction} />
|
|
||||||
<MultiplierButtons onClicks={purchaseMultiplierOnClicks} purchaseMultiplier={this.state.purchaseMultiplier} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{hasHacknetServers() && (
|
|
||||||
<button className={"std-button"} onClick={this.createHashUpgradesPopup} style={{ display: "block" }}>
|
|
||||||
{"Spend Hashes on Upgrades"}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ul id={"hacknet-nodes-list"}>{nodes}</ul>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
@ -24,7 +24,7 @@ type IProps = {
|
|||||||
|
|
||||||
export function TechVendorLocation(props: IProps): React.ReactElement {
|
export function TechVendorLocation(props: IProps): React.ReactElement {
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
function rerender() {
|
function rerender(): void {
|
||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
}
|
}
|
||||||
const btnStyle = { display: "block" };
|
const btnStyle = { display: "block" };
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { purchaseTorRouter } from "../LocationsHelpers";
|
import { purchaseTorRouter } from "../LocationsHelpers";
|
||||||
|
|
||||||
|
@ -351,7 +351,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
throw makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
throw makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(Player)) {
|
||||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
const hserver = AllServers[Player.hacknetNodes[i]];
|
||||||
if (hserver == null) {
|
if (hserver == null) {
|
||||||
throw makeRuntimeErrorMsg(
|
throw makeRuntimeErrorMsg(
|
||||||
@ -719,24 +719,24 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return Player.hacknetNodes.length;
|
return Player.hacknetNodes.length;
|
||||||
},
|
},
|
||||||
maxNumNodes: function () {
|
maxNumNodes: function () {
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(Player)) {
|
||||||
return HacknetServerConstants.MaxServers;
|
return HacknetServerConstants.MaxServers;
|
||||||
}
|
}
|
||||||
return Infinity;
|
return Infinity;
|
||||||
},
|
},
|
||||||
purchaseNode: function () {
|
purchaseNode: function () {
|
||||||
return purchaseHacknet();
|
return purchaseHacknet(Player);
|
||||||
},
|
},
|
||||||
getPurchaseNodeCost: function () {
|
getPurchaseNodeCost: function () {
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(Player)) {
|
||||||
return getCostOfNextHacknetServer();
|
return getCostOfNextHacknetServer(Player);
|
||||||
} else {
|
} else {
|
||||||
return getCostOfNextHacknetNode();
|
return getCostOfNextHacknetNode(Player);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getNodeStats: function (i) {
|
getNodeStats: function (i) {
|
||||||
const node = getHacknetNode(i, "getNodeStats");
|
const node = getHacknetNode(i, "getNodeStats");
|
||||||
const hasUpgraded = hasHacknetServers();
|
const hasUpgraded = hasHacknetServers(Player);
|
||||||
const res = {
|
const res = {
|
||||||
name: hasUpgraded ? node.hostname : node.name,
|
name: hasUpgraded ? node.hostname : node.name,
|
||||||
level: node.level,
|
level: node.level,
|
||||||
@ -756,24 +756,24 @@ function NetscriptFunctions(workerScript) {
|
|||||||
},
|
},
|
||||||
upgradeLevel: function (i, n) {
|
upgradeLevel: function (i, n) {
|
||||||
const node = getHacknetNode(i, "upgradeLevel");
|
const node = getHacknetNode(i, "upgradeLevel");
|
||||||
return purchaseLevelUpgrade(node, n);
|
return purchaseLevelUpgrade(Player, node, n);
|
||||||
},
|
},
|
||||||
upgradeRam: function (i, n) {
|
upgradeRam: function (i, n) {
|
||||||
const node = getHacknetNode(i, "upgradeRam");
|
const node = getHacknetNode(i, "upgradeRam");
|
||||||
return purchaseRamUpgrade(node, n);
|
return purchaseRamUpgrade(Player, node, n);
|
||||||
},
|
},
|
||||||
upgradeCore: function (i, n) {
|
upgradeCore: function (i, n) {
|
||||||
const node = getHacknetNode(i, "upgradeCore");
|
const node = getHacknetNode(i, "upgradeCore");
|
||||||
return purchaseCoreUpgrade(node, n);
|
return purchaseCoreUpgrade(Player, node, n);
|
||||||
},
|
},
|
||||||
upgradeCache: function (i, n) {
|
upgradeCache: function (i, n) {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const node = getHacknetNode(i, "upgradeCache");
|
const node = getHacknetNode(i, "upgradeCache");
|
||||||
const res = purchaseCacheUpgrade(node, n);
|
const res = purchaseCacheUpgrade(Player, node, n);
|
||||||
if (res) {
|
if (res) {
|
||||||
updateHashManagerCapacity();
|
updateHashManagerCapacity(Player);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
@ -790,36 +790,36 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return node.calculateCoreUpgradeCost(n, Player.hacknet_node_core_cost_mult);
|
return node.calculateCoreUpgradeCost(n, Player.hacknet_node_core_cost_mult);
|
||||||
},
|
},
|
||||||
getCacheUpgradeCost: function (i, n) {
|
getCacheUpgradeCost: function (i, n) {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
const node = getHacknetNode(i, "upgradeCache");
|
const node = getHacknetNode(i, "upgradeCache");
|
||||||
return node.calculateCacheUpgradeCost(n);
|
return node.calculateCacheUpgradeCost(n);
|
||||||
},
|
},
|
||||||
numHashes: function () {
|
numHashes: function () {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return Player.hashManager.hashes;
|
return Player.hashManager.hashes;
|
||||||
},
|
},
|
||||||
hashCapacity: function () {
|
hashCapacity: function () {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return Player.hashManager.capacity;
|
return Player.hashManager.capacity;
|
||||||
},
|
},
|
||||||
hashCost: function (upgName) {
|
hashCost: function (upgName) {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Player.hashManager.getUpgradeCost(upgName);
|
return Player.hashManager.getUpgradeCost(upgName);
|
||||||
},
|
},
|
||||||
spendHashes: function (upgName, upgTarget) {
|
spendHashes: function (upgName, upgTarget) {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return purchaseHashUpgrade(upgName, upgTarget);
|
return purchaseHashUpgrade(Player, upgName, upgTarget);
|
||||||
},
|
},
|
||||||
getHashUpgradeLevel: function (upgName) {
|
getHashUpgradeLevel: function (upgName) {
|
||||||
const level = Player.hashManager.upgrades[upgName];
|
const level = Player.hashManager.upgrades[upgName];
|
||||||
@ -829,13 +829,13 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return level;
|
return level;
|
||||||
},
|
},
|
||||||
getStudyMult: function () {
|
getStudyMult: function () {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Player.hashManager.getStudyMult();
|
return Player.hashManager.getStudyMult();
|
||||||
},
|
},
|
||||||
getTrainingMult: function () {
|
getTrainingMult: function () {
|
||||||
if (!hasHacknetServers()) {
|
if (!hasHacknetServers(Player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Player.hashManager.getTrainingMult();
|
return Player.hashManager.getTrainingMult();
|
||||||
|
@ -191,4 +191,5 @@ export interface IPlayer {
|
|||||||
getIntelligenceBonus(weight: number): number;
|
getIntelligenceBonus(weight: number): number;
|
||||||
getCasinoWinnings(): number;
|
getCasinoWinnings(): number;
|
||||||
quitJob(company: string): void;
|
quitJob(company: string): void;
|
||||||
|
createHacknetServer(): void;
|
||||||
}
|
}
|
||||||
|
@ -2518,7 +2518,6 @@ export function checkForFactionInvitations() {
|
|||||||
|
|
||||||
//BitRunners
|
//BitRunners
|
||||||
var bitrunnersFac = Factions["BitRunners"];
|
var bitrunnersFac = Factions["BitRunners"];
|
||||||
var homeComp = this.getHomeComputer();
|
|
||||||
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
|
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
|
||||||
if (bitrunnersServer == null) {
|
if (bitrunnersServer == null) {
|
||||||
console.error("Could not find BitRunners Server");
|
console.error("Could not find BitRunners Server");
|
||||||
@ -2743,7 +2742,7 @@ export function checkForFactionInvitations() {
|
|||||||
var totalHacknetCores = 0;
|
var totalHacknetCores = 0;
|
||||||
var totalHacknetLevels = 0;
|
var totalHacknetLevels = 0;
|
||||||
for (let i = 0; i < this.hacknetNodes.length; ++i) {
|
for (let i = 0; i < this.hacknetNodes.length; ++i) {
|
||||||
if (hasHacknetServers()) {
|
if (hasHacknetServers(this)) {
|
||||||
const hserver = AllServers[this.hacknetNodes[i]];
|
const hserver = AllServers[this.hacknetNodes[i]];
|
||||||
if (hserver) {
|
if (hserver) {
|
||||||
totalHacknetLevels += hserver.level;
|
totalHacknetLevels += hserver.level;
|
||||||
|
@ -339,7 +339,7 @@ function prestigeSourceFile(flume) {
|
|||||||
hserver.cache = 5;
|
hserver.cache = 5;
|
||||||
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
||||||
hserver.updateHashCapacity();
|
hserver.updateHashCapacity();
|
||||||
updateHashManagerCapacity();
|
updateHashManagerCapacity(Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh Main Menu (the 'World' menu, specifically)
|
// Refresh Main Menu (the 'World' menu, specifically)
|
||||||
|
@ -157,8 +157,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
d += " [\n";
|
d += " [\n";
|
||||||
d += n
|
d += n
|
||||||
.map(
|
.map(
|
||||||
(line: number[]) =>
|
(line: number[]) => " [" +
|
||||||
" [" +
|
|
||||||
line.map((x: number) => `${x}`.padStart(2, " ")).join(",") +
|
line.map((x: number) => `${x}`.padStart(2, " ")).join(",") +
|
||||||
"]",
|
"]",
|
||||||
)
|
)
|
||||||
|
@ -28,12 +28,8 @@ import {
|
|||||||
getFactionFieldWorkRepGain,
|
getFactionFieldWorkRepGain,
|
||||||
} from "./PersonObjects/formulas/reputation";
|
} from "./PersonObjects/formulas/reputation";
|
||||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||||
import {
|
import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers";
|
||||||
hasHacknetServers,
|
import { HacknetRoot } from "./Hacknet/ui/HacknetRoot";
|
||||||
renderHacknetNodesUI,
|
|
||||||
clearHacknetNodesUI,
|
|
||||||
processHacknetEarnings,
|
|
||||||
} from "./Hacknet/HacknetHelpers";
|
|
||||||
import { iTutorialStart } from "./InteractiveTutorial";
|
import { iTutorialStart } from "./InteractiveTutorial";
|
||||||
import { LocationName } from "./Locations/data/LocationNames";
|
import { LocationName } from "./Locations/data/LocationNames";
|
||||||
import { LocationRoot } from "./Locations/ui/Root";
|
import { LocationRoot } from "./Locations/ui/Root";
|
||||||
@ -251,7 +247,7 @@ const Engine = {
|
|||||||
Engine.hideAllContent();
|
Engine.hideAllContent();
|
||||||
Engine.Display.hacknetNodesContent.style.display = "block";
|
Engine.Display.hacknetNodesContent.style.display = "block";
|
||||||
routing.navigateTo(Page.HacknetNodes);
|
routing.navigateTo(Page.HacknetNodes);
|
||||||
renderHacknetNodesUI();
|
ReactDOM.render(<HacknetRoot player={Player} />, Engine.Display.hacknetNodesContent);
|
||||||
MainMenuLinks.HacknetNodes.classList.add("active");
|
MainMenuLinks.HacknetNodes.classList.add("active");
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -462,7 +458,9 @@ const Engine = {
|
|||||||
Engine.Display.infiltrationContent.style.display = "none";
|
Engine.Display.infiltrationContent.style.display = "none";
|
||||||
ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent);
|
ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent);
|
||||||
|
|
||||||
clearHacknetNodesUI();
|
Engine.Display.hacknetNodesContent.style.display = "none";
|
||||||
|
ReactDOM.unmountComponentAtNode(Engine.Display.hacknetNodesContent);
|
||||||
|
|
||||||
Engine.Display.createProgramContent.style.display = "none";
|
Engine.Display.createProgramContent.style.display = "none";
|
||||||
|
|
||||||
Engine.Display.factionsContent.style.display = "none";
|
Engine.Display.factionsContent.style.display = "none";
|
||||||
@ -670,7 +668,7 @@ const Engine = {
|
|||||||
updateOnlineScriptTimes(numCycles);
|
updateOnlineScriptTimes(numCycles);
|
||||||
|
|
||||||
// Hacknet Nodes
|
// Hacknet Nodes
|
||||||
processHacknetEarnings(numCycles);
|
processHacknetEarnings(Player, numCycles);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -737,9 +735,7 @@ const Engine = {
|
|||||||
|
|
||||||
if (Engine.Counters.updateDisplays <= 0) {
|
if (Engine.Counters.updateDisplays <= 0) {
|
||||||
Engine.displayCharacterOverviewInfo();
|
Engine.displayCharacterOverviewInfo();
|
||||||
if (routing.isOn(Page.HacknetNodes)) {
|
if (routing.isOn(Page.CreateProgram)) {
|
||||||
renderHacknetNodesUI();
|
|
||||||
} else if (routing.isOn(Page.CreateProgram)) {
|
|
||||||
displayCreateProgramContent();
|
displayCreateProgramContent();
|
||||||
} else if (routing.isOn(Page.Sleeves)) {
|
} else if (routing.isOn(Page.Sleeves)) {
|
||||||
updateSleevesPage();
|
updateSleevesPage();
|
||||||
@ -1020,8 +1016,8 @@ const Engine = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hacknet Nodes offline progress
|
// Hacknet Nodes offline progress
|
||||||
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
var offlineProductionFromHacknetNodes = processHacknetEarnings(Player, numCyclesOffline);
|
||||||
const hacknetProdInfo = hasHacknetServers() ? (
|
const hacknetProdInfo = hasHacknetServers(Player) ? (
|
||||||
<>{Hashes(offlineProductionFromHacknetNodes)} hashes</>
|
<>{Hashes(offlineProductionFromHacknetNodes)} hashes</>
|
||||||
) : (
|
) : (
|
||||||
<Money money={offlineProductionFromHacknetNodes} />
|
<Money money={offlineProductionFromHacknetNodes} />
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { AllServers } from "../../Server/AllServers";
|
import { AllServers } from "../../Server/AllServers";
|
||||||
|
import { Server } from "../../Server/Server";
|
||||||
|
|
||||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||||
|
|
||||||
@ -16,52 +17,50 @@ export const ServerType = {
|
|||||||
Purchased: 3, // Everything from Owned except home computer
|
Purchased: 3, // Everything from Owned except home computer
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ServerDropdown extends React.Component {
|
interface IProps {
|
||||||
|
serverType: number;
|
||||||
|
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
|
||||||
|
style: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ServerDropdown(props: IProps): React.ReactElement {
|
||||||
/**
|
/**
|
||||||
* Checks if the server should be shown in the dropdown menu, based on the
|
* Checks if the server should be shown in the dropdown menu, based on the
|
||||||
* 'serverType' property
|
* 'serverType' property
|
||||||
*/
|
*/
|
||||||
isValidServer(s) {
|
function isValidServer(s: Server | HacknetServer): boolean {
|
||||||
const type = this.props.serverType;
|
const purchased = s instanceof Server && s.purchasedByPlayer;
|
||||||
|
const type = props.serverType;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ServerType.All:
|
case ServerType.All:
|
||||||
return true;
|
return true;
|
||||||
case ServerType.Foreign:
|
case ServerType.Foreign:
|
||||||
return s.hostname !== "home" && !s.purchasedByPlayer;
|
return s.hostname !== "home" && !purchased;
|
||||||
case ServerType.Owned:
|
case ServerType.Owned:
|
||||||
return s.purchasedByPlayer || s instanceof HacknetServer || s.hostname === "home";
|
return purchased || s instanceof HacknetServer || s.hostname === "home";
|
||||||
case ServerType.Purchased:
|
case ServerType.Purchased:
|
||||||
return s.purchasedByPlayer || s instanceof HacknetServer;
|
return purchased || s instanceof HacknetServer;
|
||||||
default:
|
default:
|
||||||
console.warn(`Invalid ServerType specified for ServerDropdown component: ${type}`);
|
console.warn(`Invalid ServerType specified for ServerDropdown component: ${type}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const servers = [];
|
||||||
* Given a Server object, creates a Option element
|
for (const serverName in AllServers) {
|
||||||
*/
|
const server = AllServers[serverName];
|
||||||
renderOption(s) {
|
if (isValidServer(server)) {
|
||||||
return (
|
servers.push(
|
||||||
<option key={s.hostname} value={s.hostname}>
|
<option key={server.hostname} value={server.hostname}>
|
||||||
{s.hostname}
|
{server.hostname}
|
||||||
</option>
|
</option>,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const servers = [];
|
|
||||||
for (const serverName in AllServers) {
|
|
||||||
const server = AllServers[serverName];
|
|
||||||
if (this.isValidServer(server)) {
|
|
||||||
servers.push(this.renderOption(server));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<select className={"dropdown"} onChange={this.props.onChange} style={this.props.style}>
|
|
||||||
{servers}
|
|
||||||
</select>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select className={"dropdown"} onChange={props.onChange} style={props.style}>
|
||||||
|
{servers}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user