mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 20:55:44 +01:00
fix mc
This commit is contained in:
commit
7eb4494ac1
2
.github/PULL_REQUEST_TEMPLATE
vendored
2
.github/PULL_REQUEST_TEMPLATE
vendored
@ -1,5 +1,7 @@
|
||||
# DELETE THIS AFTER READING
|
||||
|
||||
# READ CONTRIBUTING.md
|
||||
|
||||
# PR title
|
||||
|
||||
Formatted as such:
|
||||
|
4
dist/main.bundle.js
vendored
4
dist/main.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/main.bundle.js.map
vendored
2
dist/main.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
42
dist/vendor.bundle.js
vendored
42
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/vendor.bundle.js.map
vendored
2
dist/vendor.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
11
doc/NEW_BN_GUIDELINE.md
Normal file
11
doc/NEW_BN_GUIDELINE.md
Normal file
@ -0,0 +1,11 @@
|
||||
Promote:
|
||||
|
||||
- New mechanic
|
||||
- Coding problems based on NP problems. This makes solution that are easy to implement inefficient and solutions that are hard to implement efficent. (eg. Stanek)
|
||||
- inter-mechanic synergy
|
||||
- Simplicity (eg. Stanek, Hashnet. bad example: Corp)
|
||||
|
||||
Avoid:
|
||||
|
||||
- Failure conditions, it's very frustrating to revert several days worth of progress.
|
||||
- Making existing mechanic harder. This makes it hard to port the content to other BNs.
|
1
doc/POTENTIAL_BN_1.md
Normal file
1
doc/POTENTIAL_BN_1.md
Normal file
@ -0,0 +1 @@
|
||||
Sleeves meet Screeps (That's all I got)
|
3
doc/POTENTIAL_BN_2.md
Normal file
3
doc/POTENTIAL_BN_2.md
Normal file
@ -0,0 +1,3 @@
|
||||
A game of risk from the point of view of a politician.
|
||||
|
||||
You allocate resources on a world map, trying to win elections.
|
@ -1 +0,0 @@
|
||||
I want the wiki here https://bitburner.fandom.com/wiki/Bitburner_Wiki taken down please.
|
465
package-lock.json
generated
465
package-lock.json
generated
@ -56,6 +56,10 @@
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/escodegen": "^0.0.7",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
"@types/jest": "^27.4.1",
|
||||
>>>>>>> dev
|
||||
"@types/jquery": "^3.5.14",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/numeral": "^2.0.2",
|
||||
@ -2068,19 +2072,33 @@
|
||||
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
<<<<<<< HEAD
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz",
|
||||
"integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==",
|
||||
=======
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
|
||||
"integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
|
||||
>>>>>>> dev
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
<<<<<<< HEAD
|
||||
"espree": "^9.3.1",
|
||||
=======
|
||||
"espree": "^9.3.2",
|
||||
>>>>>>> dev
|
||||
"globals": "^13.9.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
<<<<<<< HEAD
|
||||
"minimatch": "^3.0.4",
|
||||
=======
|
||||
"minimatch": "^3.1.2",
|
||||
>>>>>>> dev
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -2094,9 +2112,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||
<<<<<<< HEAD
|
||||
"version": "13.13.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
|
||||
"integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==",
|
||||
=======
|
||||
"version": "13.15.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
|
||||
"integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
|
||||
>>>>>>> dev
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"type-fest": "^0.20.2"
|
||||
@ -4062,6 +4086,19 @@
|
||||
"@types/istanbul-lib-report": "*"
|
||||
}
|
||||
},
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
"node_modules/@types/jest": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.1.tgz",
|
||||
"integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"jest-matcher-utils": "^27.0.0",
|
||||
"pretty-format": "^27.0.0"
|
||||
}
|
||||
},
|
||||
>>>>>>> dev
|
||||
"node_modules/@types/jquery": {
|
||||
"version": "3.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz",
|
||||
@ -4230,6 +4267,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.21.0.tgz",
|
||||
"integrity": "sha512-fTU85q8v5ZLpoZEyn/u1S2qrFOhi33Edo2CZ0+q1gDaWWm0JuPh3bgOyU8lM0edIEYgKLDkPFiZX2MOupgjlyg==",
|
||||
@ -4243,6 +4281,21 @@
|
||||
"ignore": "^5.1.8",
|
||||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.5",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.25.0.tgz",
|
||||
"integrity": "sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.25.0",
|
||||
"@typescript-eslint/type-utils": "5.25.0",
|
||||
"@typescript-eslint/utils": "5.25.0",
|
||||
"debug": "^4.3.4",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"ignore": "^5.2.0",
|
||||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.7",
|
||||
>>>>>>> dev
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -4262,10 +4315,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
@ -4278,6 +4348,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.21.0.tgz",
|
||||
"integrity": "sha512-8RUwTO77hstXUr3pZoWZbRQUxXcSXafZ8/5gpnQCfXvgmP9gpNlRGlWzvfbEQ14TLjmtU8eGnONkff8U2ui2Eg==",
|
||||
@ -4287,6 +4358,17 @@
|
||||
"@typescript-eslint/types": "5.21.0",
|
||||
"@typescript-eslint/typescript-estree": "5.21.0",
|
||||
"debug": "^4.3.2"
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.25.0.tgz",
|
||||
"integrity": "sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.25.0",
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/typescript-estree": "5.25.0",
|
||||
"debug": "^4.3.4"
|
||||
>>>>>>> dev
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@ -4304,6 +4386,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
<<<<<<< HEAD
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.21.0.tgz",
|
||||
@ -4314,6 +4397,34 @@
|
||||
"@typescript-eslint/visitor-keys": "5.21.0"
|
||||
},
|
||||
"engines": {
|
||||
=======
|
||||
"node_modules/@typescript-eslint/parser/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.25.0.tgz",
|
||||
"integrity": "sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/visitor-keys": "5.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
@ -4321,6 +4432,26 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.25.0.tgz",
|
||||
"integrity": "sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "5.25.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
>>>>>>> dev
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.21.0.tgz",
|
||||
@ -4343,14 +4474,45 @@
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
=======
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
>>>>>>> dev
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.21.0.tgz",
|
||||
"integrity": "sha512-XnOOo5Wc2cBlq8Lh5WNvAgHzpjnEzxn4CJBwGkcau7b/tZ556qrWXQz4DJyChYg8JZAD06kczrdgFPpEQZfDsA==",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.25.0.tgz",
|
||||
"integrity": "sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==",
|
||||
>>>>>>> dev
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@ -4361,6 +4523,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.21.0.tgz",
|
||||
"integrity": "sha512-Y8Y2T2FNvm08qlcoSMoNchh9y2Uj3QmjtwNMdRQkcFG7Muz//wfJBGBxh8R7HAGQFpgYpdHqUpEoPQk+q9Kjfg==",
|
||||
@ -4372,6 +4535,19 @@
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.25.0.tgz",
|
||||
"integrity": "sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/visitor-keys": "5.25.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
>>>>>>> dev
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -4387,6 +4563,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
@ -4403,6 +4596,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.21.0.tgz",
|
||||
"integrity": "sha512-q/emogbND9wry7zxy7VYri+7ydawo2HDZhRZ5k6yggIvXa7PvBbAAZ4PFH/oZLem72ezC4Pr63rJvDK/sTlL8Q==",
|
||||
@ -4412,6 +4606,17 @@
|
||||
"@typescript-eslint/scope-manager": "5.21.0",
|
||||
"@typescript-eslint/types": "5.21.0",
|
||||
"@typescript-eslint/typescript-estree": "5.21.0",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.25.0.tgz",
|
||||
"integrity": "sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.25.0",
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/typescript-estree": "5.25.0",
|
||||
>>>>>>> dev
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
@ -4427,6 +4632,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.21.0.tgz",
|
||||
"integrity": "sha512-SX8jNN+iHqAF0riZQMkm7e8+POXa/fXw5cxL+gjpyP+FI+JVNhii53EmQgDAfDcBpFekYSlO0fGytMQwRiMQCA==",
|
||||
@ -4434,6 +4640,15 @@
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.21.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.25.0.tgz",
|
||||
"integrity": "sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
>>>>>>> dev
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@ -4650,9 +4865,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
<<<<<<< HEAD
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
|
||||
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
|
||||
=======
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
|
||||
"integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
|
||||
>>>>>>> dev
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@ -8244,12 +8465,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
<<<<<<< HEAD
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz",
|
||||
"integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint/eslintrc": "^1.2.2",
|
||||
=======
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
|
||||
"integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint/eslintrc": "^1.2.3",
|
||||
>>>>>>> dev
|
||||
"@humanwhocodes/config-array": "^0.9.2",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
@ -8260,7 +8490,11 @@
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
<<<<<<< HEAD
|
||||
"espree": "^9.3.1",
|
||||
=======
|
||||
"espree": "^9.3.2",
|
||||
>>>>>>> dev
|
||||
"esquery": "^1.4.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@ -8276,7 +8510,7 @@
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
@ -8519,6 +8753,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
<<<<<<< HEAD
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
|
||||
"integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
|
||||
@ -8526,6 +8761,15 @@
|
||||
"dependencies": {
|
||||
"acorn": "^8.7.0",
|
||||
"acorn-jsx": "^5.3.1",
|
||||
=======
|
||||
"version": "9.3.2",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
|
||||
"integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
>>>>>>> dev
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -15103,9 +15347,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
@ -23764,19 +24008,33 @@
|
||||
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
<<<<<<< HEAD
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz",
|
||||
"integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==",
|
||||
=======
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
|
||||
"integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
|
||||
>>>>>>> dev
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
<<<<<<< HEAD
|
||||
"espree": "^9.3.1",
|
||||
=======
|
||||
"espree": "^9.3.2",
|
||||
>>>>>>> dev
|
||||
"globals": "^13.9.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
<<<<<<< HEAD
|
||||
"minimatch": "^3.0.4",
|
||||
=======
|
||||
"minimatch": "^3.1.2",
|
||||
>>>>>>> dev
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -23787,9 +24045,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"globals": {
|
||||
<<<<<<< HEAD
|
||||
"version": "13.13.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
|
||||
"integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==",
|
||||
=======
|
||||
"version": "13.15.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
|
||||
"integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
|
||||
>>>>>>> dev
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-fest": "^0.20.2"
|
||||
@ -25205,6 +25469,19 @@
|
||||
"@types/istanbul-lib-report": "*"
|
||||
}
|
||||
},
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
"@types/jest": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.1.tgz",
|
||||
"integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jest-matcher-utils": "^27.0.0",
|
||||
"pretty-format": "^27.0.0"
|
||||
}
|
||||
},
|
||||
>>>>>>> dev
|
||||
"@types/jquery": {
|
||||
"version": "3.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz",
|
||||
@ -25373,6 +25650,7 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.21.0.tgz",
|
||||
"integrity": "sha512-fTU85q8v5ZLpoZEyn/u1S2qrFOhi33Edo2CZ0+q1gDaWWm0JuPh3bgOyU8lM0edIEYgKLDkPFiZX2MOupgjlyg==",
|
||||
@ -25386,13 +25664,37 @@
|
||||
"ignore": "^5.1.8",
|
||||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.5",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.25.0.tgz",
|
||||
"integrity": "sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.25.0",
|
||||
"@typescript-eslint/type-utils": "5.25.0",
|
||||
"@typescript-eslint/utils": "5.25.0",
|
||||
"debug": "^4.3.4",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"ignore": "^5.2.0",
|
||||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.7",
|
||||
>>>>>>> dev
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
@ -25401,6 +25703,7 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.21.0.tgz",
|
||||
"integrity": "sha512-8RUwTO77hstXUr3pZoWZbRQUxXcSXafZ8/5gpnQCfXvgmP9gpNlRGlWzvfbEQ14TLjmtU8eGnONkff8U2ui2Eg==",
|
||||
@ -25451,9 +25754,92 @@
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.25.0.tgz",
|
||||
"integrity": "sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.25.0",
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/typescript-estree": "5.25.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.25.0.tgz",
|
||||
"integrity": "sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/visitor-keys": "5.25.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.25.0.tgz",
|
||||
"integrity": "sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "5.25.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.25.0.tgz",
|
||||
"integrity": "sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.25.0.tgz",
|
||||
"integrity": "sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/visitor-keys": "5.25.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
>>>>>>> dev
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
@ -25466,6 +25852,7 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.21.0.tgz",
|
||||
"integrity": "sha512-q/emogbND9wry7zxy7VYri+7ydawo2HDZhRZ5k6yggIvXa7PvBbAAZ4PFH/oZLem72ezC4Pr63rJvDK/sTlL8Q==",
|
||||
@ -25475,11 +25862,23 @@
|
||||
"@typescript-eslint/scope-manager": "5.21.0",
|
||||
"@typescript-eslint/types": "5.21.0",
|
||||
"@typescript-eslint/typescript-estree": "5.21.0",
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.25.0.tgz",
|
||||
"integrity": "sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.25.0",
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"@typescript-eslint/typescript-estree": "5.25.0",
|
||||
>>>>>>> dev
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
<<<<<<< HEAD
|
||||
"version": "5.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.21.0.tgz",
|
||||
"integrity": "sha512-SX8jNN+iHqAF0riZQMkm7e8+POXa/fXw5cxL+gjpyP+FI+JVNhii53EmQgDAfDcBpFekYSlO0fGytMQwRiMQCA==",
|
||||
@ -25487,6 +25886,15 @@
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.21.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
=======
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.25.0.tgz",
|
||||
"integrity": "sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.25.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
>>>>>>> dev
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
@ -25693,9 +26101,15 @@
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
<<<<<<< HEAD
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
|
||||
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
|
||||
=======
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
|
||||
"integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A=="
|
||||
>>>>>>> dev
|
||||
},
|
||||
"acorn-globals": {
|
||||
"version": "4.3.4",
|
||||
@ -28606,12 +29020,21 @@
|
||||
}
|
||||
},
|
||||
"eslint": {
|
||||
<<<<<<< HEAD
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz",
|
||||
"integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.2.2",
|
||||
=======
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
|
||||
"integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.2.3",
|
||||
>>>>>>> dev
|
||||
"@humanwhocodes/config-array": "^0.9.2",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
@ -28622,7 +29045,11 @@
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
<<<<<<< HEAD
|
||||
"espree": "^9.3.1",
|
||||
=======
|
||||
"espree": "^9.3.2",
|
||||
>>>>>>> dev
|
||||
"esquery": "^1.4.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@ -28638,7 +29065,7 @@
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
@ -28807,6 +29234,7 @@
|
||||
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
|
||||
},
|
||||
"espree": {
|
||||
<<<<<<< HEAD
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
|
||||
"integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
|
||||
@ -28814,6 +29242,15 @@
|
||||
"requires": {
|
||||
"acorn": "^8.7.0",
|
||||
"acorn-jsx": "^5.3.1",
|
||||
=======
|
||||
"version": "9.3.2",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
|
||||
"integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
>>>>>>> dev
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
@ -33925,9 +34362,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"version": "1.6.4",
|
||||
"version": "1.7.0",
|
||||
"main": "electron-main.js",
|
||||
"author": {
|
||||
"name": "Daniel Xie & Olivier Gagnon"
|
||||
@ -57,6 +57,7 @@
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/escodegen": "^0.0.7",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/jquery": "^3.5.14",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/numeral": "^2.0.2",
|
||||
|
@ -631,6 +631,7 @@ export class Augmentation {
|
||||
augmentationReference.baseCost *
|
||||
getGenericAugmentationPriceMultiplier() *
|
||||
BitNodeMultipliers.AugmentationMoneyCost;
|
||||
repCost = augmentationReference.baseRepRequirement * BitNodeMultipliers.AugmentationRepCost;
|
||||
}
|
||||
return { moneyCost, repCost };
|
||||
}
|
||||
|
@ -45,13 +45,13 @@ function BitNodeModifiedStats(props: IBitNodeModifiedStatsProps): React.ReactEle
|
||||
);
|
||||
}
|
||||
|
||||
type MultiplierListItemData = [
|
||||
multiplier: string,
|
||||
currentValue: number,
|
||||
augmentedValue: number,
|
||||
bitNodeMultiplier: number,
|
||||
color: string,
|
||||
];
|
||||
interface MultiplierListItemData {
|
||||
mult: string;
|
||||
current: number;
|
||||
augmented: number;
|
||||
bnMult?: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface IMultiplierListProps {
|
||||
rows: MultiplierListItemData[];
|
||||
@ -60,23 +60,23 @@ interface IMultiplierListProps {
|
||||
function MultiplierList(props: IMultiplierListProps): React.ReactElement {
|
||||
const listItems = props.rows
|
||||
.map((data) => {
|
||||
const [multiplier, currentValue, augmentedValue, bitNodeMultiplier, color] = data;
|
||||
const { mult, current, augmented, bnMult = 1, color = Settings.theme.primary } = data;
|
||||
|
||||
if (!isNaN(augmentedValue)) {
|
||||
if (!isNaN(augmented)) {
|
||||
return (
|
||||
<ListItem key={multiplier} disableGutters sx={{ py: 0 }}>
|
||||
<ListItem key={mult} disableGutters sx={{ py: 0 }}>
|
||||
<ListItemText
|
||||
sx={{ my: 0.1 }}
|
||||
primary={
|
||||
<Typography color={color}>
|
||||
<b>{multiplier}</b>
|
||||
<b>{mult}</b>
|
||||
</Typography>
|
||||
}
|
||||
secondary={
|
||||
<span style={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
<BitNodeModifiedStats base={currentValue} mult={bitNodeMultiplier} color={color} />
|
||||
<BitNodeModifiedStats base={current} mult={bnMult} color={color} />
|
||||
<DoubleArrow fontSize="small" color="success" sx={{ mb: 0.5, mx: 1 }} />
|
||||
<BitNodeModifiedStats base={augmentedValue} mult={bitNodeMultiplier} color={Settings.theme.success} />
|
||||
<BitNodeModifiedStats base={augmented} mult={bnMult} color={Settings.theme.success} />
|
||||
</span>
|
||||
}
|
||||
disableTypography
|
||||
@ -94,177 +94,205 @@ function MultiplierList(props: IMultiplierListProps): React.ReactElement {
|
||||
export function PlayerMultipliers(): React.ReactElement {
|
||||
const mults = calculateAugmentedStats();
|
||||
|
||||
// Column data is a bit janky, so it's set up here to allow for
|
||||
// easier logic in setting up the layout
|
||||
const leftColData: MultiplierListItemData[] = [
|
||||
...[
|
||||
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
|
||||
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
|
||||
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
|
||||
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
|
||||
[
|
||||
"Hacking Level ",
|
||||
Player.hacking_mult,
|
||||
Player.hacking_mult * mults.hacking_mult,
|
||||
BitNodeMultipliers.HackingLevelMultiplier,
|
||||
],
|
||||
[
|
||||
"Hacking Experience ",
|
||||
Player.hacking_exp_mult,
|
||||
Player.hacking_exp_mult * mults.hacking_exp_mult,
|
||||
BitNodeMultipliers.HackExpGain,
|
||||
],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.hack])),
|
||||
{
|
||||
mult: "Hacking Chance",
|
||||
current: Player.hacking_chance_mult,
|
||||
augmented: Player.hacking_chance_mult * mults.hacking_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Speed",
|
||||
current: Player.hacking_speed_mult,
|
||||
augmented: Player.hacking_speed_mult * mults.hacking_speed_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Money",
|
||||
current: Player.hacking_money_mult,
|
||||
augmented: Player.hacking_money_mult * mults.hacking_money_mult,
|
||||
bnMult: BitNodeMultipliers.ScriptHackMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Growth",
|
||||
current: Player.hacking_grow_mult,
|
||||
augmented: Player.hacking_grow_mult * mults.hacking_grow_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Level",
|
||||
current: Player.hacking_mult,
|
||||
augmented: Player.hacking_mult * mults.hacking_mult,
|
||||
bnMult: BitNodeMultipliers.HackingLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Experience",
|
||||
current: Player.hacking_exp_mult,
|
||||
augmented: Player.hacking_exp_mult * mults.hacking_exp_mult,
|
||||
bnMult: BitNodeMultipliers.HackExpGain,
|
||||
},
|
||||
].map((data: MultiplierListItemData) =>
|
||||
Object.defineProperty(data, "color", {
|
||||
value: Settings.theme.hack,
|
||||
}),
|
||||
),
|
||||
...[
|
||||
[
|
||||
"Strength Level ",
|
||||
Player.strength_mult,
|
||||
Player.strength_mult * mults.strength_mult,
|
||||
BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
],
|
||||
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
|
||||
[
|
||||
"Defense Level ",
|
||||
Player.defense_mult,
|
||||
Player.defense_mult * mults.defense_mult,
|
||||
BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
],
|
||||
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
|
||||
[
|
||||
"Dexterity Level ",
|
||||
Player.dexterity_mult,
|
||||
Player.dexterity_mult * mults.dexterity_mult,
|
||||
BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
],
|
||||
["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult, 1],
|
||||
[
|
||||
"Agility Level ",
|
||||
Player.agility_mult,
|
||||
Player.agility_mult * mults.agility_mult,
|
||||
BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
],
|
||||
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.combat])),
|
||||
[
|
||||
"Charisma Level ",
|
||||
Player.charisma_mult,
|
||||
Player.charisma_mult * mults.charisma_mult,
|
||||
BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
Settings.theme.cha,
|
||||
],
|
||||
[
|
||||
"Charisma Experience ",
|
||||
Player.charisma_exp_mult,
|
||||
Player.charisma_exp_mult * mults.charisma_exp_mult,
|
||||
1,
|
||||
Settings.theme.cha,
|
||||
],
|
||||
{
|
||||
mult: "Strength Level",
|
||||
current: Player.strength_mult,
|
||||
augmented: Player.strength_mult * mults.strength_mult,
|
||||
bnMult: BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Strength Experience",
|
||||
current: Player.strength_exp_mult,
|
||||
augmented: Player.strength_exp_mult * mults.strength_exp_mult,
|
||||
},
|
||||
{
|
||||
mult: "Defense Level",
|
||||
current: Player.defense_mult,
|
||||
augmented: Player.defense_mult * mults.defense_mult,
|
||||
bnMult: BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Defense Experience",
|
||||
current: Player.defense_exp_mult,
|
||||
augmented: Player.defense_exp_mult * mults.defense_exp_mult,
|
||||
},
|
||||
{
|
||||
mult: "Dexterity Level",
|
||||
current: Player.dexterity_mult,
|
||||
augmented: Player.dexterity_mult * mults.dexterity_mult,
|
||||
bnMult: BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Dexterity Experience",
|
||||
current: Player.dexterity_exp_mult,
|
||||
augmented: Player.dexterity_exp_mult * mults.dexterity_exp_mult,
|
||||
},
|
||||
{
|
||||
mult: "Agility Level",
|
||||
current: Player.agility_mult,
|
||||
augmented: Player.agility_mult * mults.agility_mult,
|
||||
bnMult: BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Agility Experience",
|
||||
current: Player.agility_exp_mult,
|
||||
augmented: Player.agility_exp_mult * mults.agility_exp_mult,
|
||||
},
|
||||
].map((data: MultiplierListItemData) =>
|
||||
Object.defineProperty(data, "color", {
|
||||
value: Settings.theme.combat,
|
||||
}),
|
||||
),
|
||||
{
|
||||
mult: "Charisma Level",
|
||||
current: Player.charisma_mult,
|
||||
augmented: Player.charisma_mult * mults.charisma_mult,
|
||||
bnMult: BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
color: Settings.theme.cha,
|
||||
},
|
||||
{
|
||||
mult: "Charisma Experience",
|
||||
current: Player.charisma_exp_mult,
|
||||
augmented: Player.charisma_exp_mult * mults.charisma_exp_mult,
|
||||
color: Settings.theme.cha,
|
||||
},
|
||||
];
|
||||
const rightColData: MultiplierListItemData[] = [
|
||||
...[
|
||||
[
|
||||
"Hacknet Node production ",
|
||||
Player.hacknet_node_money_mult,
|
||||
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
|
||||
BitNodeMultipliers.HacknetNodeMoney,
|
||||
],
|
||||
[
|
||||
"Hacknet Node purchase cost ",
|
||||
Player.hacknet_node_purchase_cost_mult,
|
||||
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Hacknet Node RAM upgrade cost ",
|
||||
Player.hacknet_node_ram_cost_mult,
|
||||
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Hacknet Node Core purchase cost ",
|
||||
Player.hacknet_node_core_cost_mult,
|
||||
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Hacknet Node level upgrade cost ",
|
||||
Player.hacknet_node_level_cost_mult,
|
||||
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
|
||||
1,
|
||||
],
|
||||
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
|
||||
[
|
||||
"Faction reputation gain ",
|
||||
Player.faction_rep_mult,
|
||||
Player.faction_rep_mult * mults.faction_rep_mult,
|
||||
BitNodeMultipliers.FactionWorkRepGain,
|
||||
],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
|
||||
[
|
||||
"Salary ",
|
||||
Player.work_money_mult,
|
||||
Player.work_money_mult * mults.work_money_mult,
|
||||
BitNodeMultipliers.CompanyWorkMoney,
|
||||
Settings.theme.money,
|
||||
],
|
||||
[
|
||||
"Crime success ",
|
||||
Player.crime_success_mult,
|
||||
Player.crime_success_mult * mults.crime_success_mult,
|
||||
1,
|
||||
Settings.theme.combat,
|
||||
],
|
||||
[
|
||||
"Crime money ",
|
||||
Player.crime_money_mult,
|
||||
Player.crime_money_mult * mults.crime_money_mult,
|
||||
BitNodeMultipliers.CrimeMoney,
|
||||
Settings.theme.money,
|
||||
],
|
||||
{
|
||||
mult: "Hacknet Node Production",
|
||||
current: Player.hacknet_node_money_mult,
|
||||
augmented: Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
|
||||
bnMult: BitNodeMultipliers.HacknetNodeMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Purchase Cost",
|
||||
current: Player.hacknet_node_purchase_cost_mult,
|
||||
augmented: Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node RAM Upgrade Cost",
|
||||
current: Player.hacknet_node_ram_cost_mult,
|
||||
augmented: Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Core Purchase Cost",
|
||||
current: Player.hacknet_node_core_cost_mult,
|
||||
augmented: Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Level Upgrade Cost",
|
||||
current: Player.hacknet_node_level_cost_mult,
|
||||
augmented: Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Company Reputation Gain",
|
||||
current: Player.company_rep_mult,
|
||||
augmented: Player.company_rep_mult * mults.company_rep_mult,
|
||||
},
|
||||
{
|
||||
mult: "Faction Reputation Gain",
|
||||
current: Player.faction_rep_mult,
|
||||
augmented: Player.faction_rep_mult * mults.faction_rep_mult,
|
||||
bnMult: BitNodeMultipliers.FactionWorkRepGain,
|
||||
},
|
||||
{
|
||||
mult: "Salary",
|
||||
current: Player.work_money_mult,
|
||||
augmented: Player.work_money_mult * mults.work_money_mult,
|
||||
bnMult: BitNodeMultipliers.CompanyWorkMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
{
|
||||
mult: "Crime Success Chance",
|
||||
current: Player.crime_success_mult,
|
||||
augmented: Player.crime_success_mult * mults.crime_success_mult,
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
{
|
||||
mult: "Crime Money",
|
||||
current: Player.crime_money_mult,
|
||||
augmented: Player.crime_money_mult * mults.crime_money_mult,
|
||||
bnMult: BitNodeMultipliers.CrimeMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
];
|
||||
|
||||
if (Player.canAccessBladeburner()) {
|
||||
rightColData.push(
|
||||
...[
|
||||
[
|
||||
"Bladeburner Success Chance",
|
||||
Player.bladeburner_success_chance_mult,
|
||||
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Bladeburner Max Stamina",
|
||||
Player.bladeburner_max_stamina_mult,
|
||||
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Bladeburner Stamina Gain",
|
||||
Player.bladeburner_stamina_gain_mult,
|
||||
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
|
||||
1,
|
||||
],
|
||||
[
|
||||
"Bladeburner Field Analysis",
|
||||
Player.bladeburner_analysis_mult,
|
||||
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
|
||||
1,
|
||||
],
|
||||
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
|
||||
{
|
||||
mult: "Bladeburner Success Chance",
|
||||
current: Player.bladeburner_success_chance_mult,
|
||||
augmented: Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Max Stamina",
|
||||
current: Player.bladeburner_max_stamina_mult,
|
||||
augmented: Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Stamina Gain",
|
||||
current: Player.bladeburner_stamina_gain_mult,
|
||||
augmented: Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Field Analysis",
|
||||
current: Player.bladeburner_analysis_mult,
|
||||
augmented: Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const hasLeftImprovements = +!!(leftColData.filter((item) => item[2] !== 0).length > 0),
|
||||
hasRightImprovements = +!!(rightColData.filter((item) => item[2] !== 0).length > 0);
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
p: 1,
|
||||
maxHeight: 400,
|
||||
overflowY: "scroll",
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${hasLeftImprovements + hasRightImprovements}, 1fr)`,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flexWrap: "wrap",
|
||||
gap: 1,
|
||||
}}
|
||||
>
|
||||
<MultiplierList rows={leftColData} />
|
||||
|
@ -83,7 +83,7 @@ const Exclusive = (props: IExclusiveProps): React.ReactElement => {
|
||||
<li>
|
||||
<b>{props.aug.factions[0]}</b> faction
|
||||
</li>
|
||||
{props.player.canAccessGang() && !props.aug.isSpecial && (
|
||||
{props.player.isAwareOfGang() && !props.aug.isSpecial && (
|
||||
<li>
|
||||
Certain <b>gangs</b>
|
||||
</li>
|
||||
|
@ -488,7 +488,7 @@ export const defaultMultipliers: IBitNodeMultipliers = {
|
||||
FourSigmaMarketDataApiCost: 1,
|
||||
|
||||
CorporationValuation: 1,
|
||||
CorporationSoftCap: 1,
|
||||
CorporationSoftcap: 1,
|
||||
|
||||
BladeburnerRank: 1,
|
||||
BladeburnerSkillCost: 1,
|
||||
@ -504,6 +504,8 @@ export const defaultMultipliers: IBitNodeMultipliers = {
|
||||
WorldDaemonDifficulty: 1,
|
||||
};
|
||||
|
||||
Object.freeze(defaultMultipliers);
|
||||
|
||||
export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultipliers {
|
||||
const mults = Object.assign({}, defaultMultipliers);
|
||||
switch (n) {
|
||||
@ -523,7 +525,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 2,
|
||||
StaneksGiftExtraSize: -6,
|
||||
PurchasedServerSoftcap: 1.3,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 5,
|
||||
});
|
||||
}
|
||||
@ -609,7 +611,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 0.5,
|
||||
StaneksGiftExtraSize: 2,
|
||||
GangSoftcap: 0.7,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.2,
|
||||
});
|
||||
@ -637,7 +639,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 0.9,
|
||||
StaneksGiftExtraSize: -1,
|
||||
GangSoftcap: 0.7,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.2,
|
||||
});
|
||||
@ -657,7 +659,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftExtraSize: -99,
|
||||
PurchasedServerSoftcap: 4,
|
||||
GangSoftcap: 0,
|
||||
CorporationSoftCap: 0,
|
||||
CorporationSoftcap: 0,
|
||||
GangUniqueAugs: 0,
|
||||
});
|
||||
}
|
||||
@ -685,7 +687,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 0.5,
|
||||
StaneksGiftExtraSize: 2,
|
||||
GangSoftcap: 0.8,
|
||||
CorporationSoftCap: 0.7,
|
||||
CorporationSoftcap: 0.7,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.25,
|
||||
});
|
||||
@ -717,7 +719,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftExtraSize: -3,
|
||||
PurchasedServerSoftcap: 1.1,
|
||||
GangSoftcap: 0.9,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 2,
|
||||
GangUniqueAugs: 0.25,
|
||||
});
|
||||
@ -741,7 +743,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
FourSigmaMarketDataCost: 4,
|
||||
FourSigmaMarketDataApiCost: 4,
|
||||
PurchasedServerSoftcap: 2,
|
||||
CorporationSoftCap: 0.9,
|
||||
CorporationSoftcap: 0.9,
|
||||
WorldDaemonDifficulty: 1.5,
|
||||
GangUniqueAugs: 0.75,
|
||||
});
|
||||
@ -809,7 +811,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: inc,
|
||||
StaneksGiftExtraSize: inc,
|
||||
GangSoftcap: 0.8,
|
||||
CorporationSoftCap: 0.8,
|
||||
CorporationSoftcap: 0.8,
|
||||
WorldDaemonDifficulty: inc,
|
||||
|
||||
GangUniqueAugs: dec,
|
||||
@ -854,7 +856,7 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
|
||||
StaneksGiftPowerMultiplier: 2,
|
||||
StaneksGiftExtraSize: 1,
|
||||
GangSoftcap: 0.3,
|
||||
CorporationSoftCap: 0.3,
|
||||
CorporationSoftcap: 0.3,
|
||||
WorldDaemonDifficulty: 3,
|
||||
GangUniqueAugs: 0.1,
|
||||
});
|
||||
|
@ -242,7 +242,7 @@ export interface IBitNodeMultipliers {
|
||||
/**
|
||||
* Influences corporation dividends.
|
||||
*/
|
||||
CorporationSoftCap: number;
|
||||
CorporationSoftcap: number;
|
||||
|
||||
// Index signature
|
||||
[key: string]: number;
|
||||
@ -252,4 +252,4 @@ export interface IBitNodeMultipliers {
|
||||
* The multipliers that are influenced by current Bitnode progression.
|
||||
*/
|
||||
// tslint:disable-next-line:variable-name
|
||||
export const BitNodeMultipliers = defaultMultipliers;
|
||||
export const BitNodeMultipliers = Object.assign({}, defaultMultipliers);
|
||||
|
@ -1,554 +1,335 @@
|
||||
import ExpandMore from "@mui/icons-material/ExpandMore";
|
||||
import ExpandLess from "@mui/icons-material/ExpandLess";
|
||||
import { Box, Collapse, ListItemButton, ListItemText, Paper, Typography } from "@mui/material";
|
||||
import ExpandMore from "@mui/icons-material/ExpandMore";
|
||||
import { Box, Collapse, ListItemButton, ListItemText, Paper, Table, TableBody, Typography } from "@mui/material";
|
||||
import { uniqueId } from "lodash";
|
||||
import React from "react";
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { use } from "../../ui/Context";
|
||||
import { StatsRow } from "../../ui/React/StatsRow";
|
||||
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
|
||||
import { IBitNodeMultipliers } from "../BitNodeMultipliers";
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
|
||||
interface IProps {
|
||||
n: number;
|
||||
level?: number;
|
||||
}
|
||||
|
||||
export function BitnodeMultiplierDescription({ n }: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
export function BitnodeMultiplierDescription({ n, level }: IProps): React.ReactElement {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const mults = getBitNodeMultipliers(n, player.sourceFileLvl(n));
|
||||
if (n === 1) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Box component={Paper}>
|
||||
<ListItemButton onClick={() => setOpen((old) => !old)}>
|
||||
<ListItemText primary={<Typography>Bitnode multipliers:</Typography>} />
|
||||
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
|
||||
</ListItemButton>
|
||||
<Box mx={2}>
|
||||
<Collapse in={open}>
|
||||
<GeneralMults n={n} mults={mults} />
|
||||
<FactionMults n={n} mults={mults} />
|
||||
<AugmentationMults n={n} mults={mults} />
|
||||
<StockMults n={n} mults={mults} />
|
||||
<SkillMults n={n} mults={mults} />
|
||||
<HackingMults n={n} mults={mults} />
|
||||
<PurchasedServersMults n={n} mults={mults} />
|
||||
<CrimeMults n={n} mults={mults} />
|
||||
<InfiltrationMults n={n} mults={mults} />
|
||||
<CompanyMults n={n} mults={mults} />
|
||||
<GangMults n={n} mults={mults} />
|
||||
<CorporationMults n={n} mults={mults} />
|
||||
<BladeburnerMults n={n} mults={mults} />
|
||||
<StanekMults n={n} mults={mults} />
|
||||
<br />
|
||||
</Collapse>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
<Box component={Paper} sx={{ mt: 1, p: 1 }}>
|
||||
<ListItemButton disableGutters onClick={() => setOpen((old) => !old)}>
|
||||
<ListItemText primary={<Typography variant="h6">Bitnode Multipliers</Typography>} />
|
||||
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
|
||||
</ListItemButton>
|
||||
<Collapse in={open}>
|
||||
<BitNodeMultipliersDisplay n={n} level={level} />
|
||||
</Collapse>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export const BitNodeMultipliersDisplay = ({ n, level }: IProps): React.ReactElement => {
|
||||
const player = use.Player();
|
||||
// If a level argument has been provided, use that as the multiplier level
|
||||
// If not, then we have to assume that we want the next level up from the
|
||||
// current node's source file, so we get the min of that, the SF's max level,
|
||||
// or if it's BN12, ∞
|
||||
const maxSfLevel = n === 12 ? Infinity : 3;
|
||||
const mults = getBitNodeMultipliers(n, level ?? Math.min(player.sourceFileLvl(n) + 1, maxSfLevel));
|
||||
|
||||
return (
|
||||
<Box sx={{ columnCount: 2, columnGap: 1, mb: -2 }}>
|
||||
<GeneralMults n={n} mults={mults} />
|
||||
<SkillMults n={n} mults={mults} />
|
||||
<FactionMults n={n} mults={mults} />
|
||||
<AugmentationMults n={n} mults={mults} />
|
||||
<HackingMults n={n} mults={mults} />
|
||||
<PurchasedServersMults n={n} mults={mults} />
|
||||
<StockMults n={n} mults={mults} />
|
||||
<CrimeMults n={n} mults={mults} />
|
||||
<InfiltrationMults n={n} mults={mults} />
|
||||
<CompanyMults n={n} mults={mults} />
|
||||
<GangMults n={n} mults={mults} />
|
||||
<CorporationMults n={n} mults={mults} />
|
||||
<BladeburnerMults n={n} mults={mults} />
|
||||
<StanekMults n={n} mults={mults} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
interface IBNMultRows {
|
||||
[mult: string]: {
|
||||
name: string;
|
||||
content?: string;
|
||||
color?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface IBNMultTableProps {
|
||||
sectionName: string;
|
||||
rowData: IBNMultRows;
|
||||
mults: IBitNodeMultipliers;
|
||||
}
|
||||
|
||||
const BNMultTable = (props: IBNMultTableProps): React.ReactElement => {
|
||||
const rowsArray = Object.entries(props.rowData)
|
||||
.filter(([key, _value]) => props.mults[key] !== defaultMultipliers[key])
|
||||
.map(([key, value]) => (
|
||||
<StatsRow
|
||||
key={uniqueId()}
|
||||
name={value.name}
|
||||
data={{ content: value.content ?? `${(props.mults[key] * 100).toFixed(3)}%` }}
|
||||
color={value.color ?? Settings.theme.primary}
|
||||
/>
|
||||
));
|
||||
|
||||
return rowsArray.length > 0 ? (
|
||||
<span style={{ display: "inline-block", width: "100%", marginBottom: "16px" }}>
|
||||
<Typography variant="h6">{props.sectionName}</Typography>
|
||||
<Table>
|
||||
<TableBody>{rowsArray}</TableBody>
|
||||
</Table>
|
||||
</span>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
interface IMultsProps {
|
||||
n: number;
|
||||
mults: IBitNodeMultipliers;
|
||||
}
|
||||
|
||||
function GeneralMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.ClassGymExpGain === defaultMultipliers.ClassGymExpGain &&
|
||||
mults.CodingContractMoney === defaultMultipliers.CodingContractMoney &&
|
||||
mults.DaedalusAugsRequirement === defaultMultipliers.DaedalusAugsRequirement &&
|
||||
mults.WorldDaemonDifficulty === defaultMultipliers.WorldDaemonDifficulty &&
|
||||
mults.HacknetNodeMoney === defaultMultipliers.HacknetNodeMoney
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>General:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.WorldDaemonDifficulty !== defaultMultipliers.WorldDaemonDifficulty ? (
|
||||
<Typography>
|
||||
{SpecialServers.WorldDaemon} difficulty: x{mults.WorldDaemonDifficulty.toFixed(3)}
|
||||
</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.DaedalusAugsRequirement !== defaultMultipliers.DaedalusAugsRequirement ? (
|
||||
<Typography>Daedalus aug req.: {mults.DaedalusAugsRequirement}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.HacknetNodeMoney !== defaultMultipliers.HacknetNodeMoney ? (
|
||||
<Typography>Hacknet production: x{mults.HacknetNodeMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CodingContractMoney !== defaultMultipliers.CodingContractMoney ? (
|
||||
<Typography>Coding contract reward: x{mults.CodingContractMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ClassGymExpGain !== defaultMultipliers.ClassGymExpGain ? (
|
||||
<Typography>Class/Gym exp: x{mults.ClassGymExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
WorldDaemonDifficulty: { name: `${SpecialServers.WorldDaemon} Difficulty` },
|
||||
DaedalusAugsRequirement: {
|
||||
name: "Daedalus Augs Requirement",
|
||||
content: String(mults.DaedalusAugsRequirement),
|
||||
},
|
||||
HacknetNodeMoney: { name: "Hacknet Production" },
|
||||
CodingContractMoney: { name: "Coding Contract Reward" },
|
||||
ClassGymExpGain: { name: "Class/Gym Exp" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="General" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function AugmentationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.AugmentationMoneyCost === defaultMultipliers.AugmentationMoneyCost &&
|
||||
mults.AugmentationRepCost === defaultMultipliers.AugmentationRepCost
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Augmentations:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.AugmentationMoneyCost !== defaultMultipliers.AugmentationMoneyCost ? (
|
||||
<Typography>Cost: x{mults.AugmentationMoneyCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.AugmentationRepCost !== defaultMultipliers.AugmentationRepCost ? (
|
||||
<Typography>Reputation: x{mults.AugmentationRepCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
AugmentationMoneyCost: { name: "Money Cost" },
|
||||
AugmentationRepCost: {
|
||||
name: "Reputation Cost",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Augmentations" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function CompanyMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.CompanyWorkExpGain === defaultMultipliers.CompanyWorkExpGain &&
|
||||
mults.CompanyWorkMoney === defaultMultipliers.CompanyWorkMoney
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Company:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.CompanyWorkMoney !== defaultMultipliers.CompanyWorkMoney ? (
|
||||
<Typography>Money: x{mults.CompanyWorkMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CompanyWorkExpGain !== defaultMultipliers.CompanyWorkExpGain ? (
|
||||
<Typography>Exp: x{mults.CompanyWorkExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
CompanyWorkMoney: {
|
||||
name: "Work Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
CompanyWorkExpGain: { name: "Work Exp" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Company" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function StockMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.FourSigmaMarketDataApiCost === defaultMultipliers.FourSigmaMarketDataApiCost &&
|
||||
mults.FourSigmaMarketDataCost === defaultMultipliers.FourSigmaMarketDataCost
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Stock market:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.FourSigmaMarketDataCost !== defaultMultipliers.FourSigmaMarketDataCost ? (
|
||||
<Typography>Market data cost: x{mults.FourSigmaMarketDataCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FourSigmaMarketDataApiCost !== defaultMultipliers.FourSigmaMarketDataApiCost ? (
|
||||
<Typography>Market data API cost: x{mults.FourSigmaMarketDataApiCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
FourSigmaMarketDataCost: { name: "Market Data Cost" },
|
||||
FourSigmaMarketDataApiCost: { name: "Market Data API Cost" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Stock Market" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function FactionMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.FactionPassiveRepGain === defaultMultipliers.FactionPassiveRepGain &&
|
||||
mults.FactionWorkExpGain === defaultMultipliers.FactionWorkExpGain &&
|
||||
mults.FactionWorkRepGain === defaultMultipliers.FactionWorkRepGain &&
|
||||
mults.RepToDonateToFaction === defaultMultipliers.RepToDonateToFaction
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Faction:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.RepToDonateToFaction !== defaultMultipliers.RepToDonateToFaction ? (
|
||||
<Typography>Favor to donate: x{mults.RepToDonateToFaction.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FactionWorkRepGain !== defaultMultipliers.FactionWorkRepGain ? (
|
||||
<Typography>Work rep: x{mults.FactionWorkRepGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FactionWorkExpGain !== defaultMultipliers.FactionWorkExpGain ? (
|
||||
<Typography>Work exp: x{mults.FactionWorkExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.FactionPassiveRepGain !== defaultMultipliers.FactionPassiveRepGain ? (
|
||||
<Typography>Passive rep: x{mults.FactionPassiveRepGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
RepToDonateToFaction: { name: "Favor to Donate" },
|
||||
FactionWorkRepGain: {
|
||||
name: "Work Reputation",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
FactionWorkExpGain: { name: "Work Exp" },
|
||||
FactionPassiveRepGain: {
|
||||
name: "Passive Rep",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Faction" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function CrimeMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (mults.CrimeExpGain === defaultMultipliers.CrimeExpGain && mults.CrimeMoney === defaultMultipliers.CrimeMoney)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Crime:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.CrimeExpGain !== defaultMultipliers.CrimeExpGain ? (
|
||||
<Typography>Exp: x{mults.CrimeExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CrimeMoney !== defaultMultipliers.CrimeMoney ? (
|
||||
<Typography>Money: x{mults.CrimeMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
CrimeExpGain: {
|
||||
name: "Crime Exp",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
CrimeMoney: {
|
||||
name: "Crime Money",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Crime" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function SkillMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.HackingLevelMultiplier === defaultMultipliers.HackingLevelMultiplier &&
|
||||
mults.AgilityLevelMultiplier === defaultMultipliers.AgilityLevelMultiplier &&
|
||||
mults.DefenseLevelMultiplier === defaultMultipliers.DefenseLevelMultiplier &&
|
||||
mults.DexterityLevelMultiplier === defaultMultipliers.DexterityLevelMultiplier &&
|
||||
mults.StrengthLevelMultiplier === defaultMultipliers.StrengthLevelMultiplier &&
|
||||
mults.CharismaLevelMultiplier === defaultMultipliers.CharismaLevelMultiplier
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Skills:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.HackingLevelMultiplier !== defaultMultipliers.HackingLevelMultiplier ? (
|
||||
<Typography>Hacking: x{mults.HackingLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.AgilityLevelMultiplier !== defaultMultipliers.AgilityLevelMultiplier ? (
|
||||
<Typography>Agility: x{mults.AgilityLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.DefenseLevelMultiplier !== defaultMultipliers.DefenseLevelMultiplier ? (
|
||||
<Typography>Defense: x{mults.DefenseLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.DexterityLevelMultiplier !== defaultMultipliers.DexterityLevelMultiplier ? (
|
||||
<Typography>Dexterity: x{mults.DexterityLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.StrengthLevelMultiplier !== defaultMultipliers.StrengthLevelMultiplier ? (
|
||||
<Typography>Strength: x{mults.StrengthLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CharismaLevelMultiplier !== defaultMultipliers.CharismaLevelMultiplier ? (
|
||||
<Typography>Charisma: x{mults.CharismaLevelMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
HackingLevelMultiplier: {
|
||||
name: "Hacking Level",
|
||||
color: Settings.theme.hack,
|
||||
},
|
||||
StrengthLevelMultiplier: {
|
||||
name: "Strength Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
DefenseLevelMultiplier: {
|
||||
name: "Defense Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
DexterityLevelMultiplier: {
|
||||
name: "Dexterity Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
AgilityLevelMultiplier: {
|
||||
name: "Agility Level",
|
||||
color: Settings.theme.combat,
|
||||
},
|
||||
CharismaLevelMultiplier: {
|
||||
name: "Charisma Level",
|
||||
color: Settings.theme.cha,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Skills" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function HackingMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.ServerGrowthRate === defaultMultipliers.ServerGrowthRate &&
|
||||
mults.ServerMaxMoney === defaultMultipliers.ServerMaxMoney &&
|
||||
mults.ServerStartingMoney === defaultMultipliers.ServerStartingMoney &&
|
||||
mults.ServerStartingSecurity === defaultMultipliers.ServerStartingSecurity &&
|
||||
mults.ServerWeakenRate === defaultMultipliers.ServerWeakenRate &&
|
||||
mults.ManualHackMoney === defaultMultipliers.ManualHackMoney &&
|
||||
mults.ScriptHackMoney === defaultMultipliers.ScriptHackMoney &&
|
||||
mults.ScriptHackMoneyGain === defaultMultipliers.ScriptHackMoneyGain &&
|
||||
mults.HackExpGain === defaultMultipliers.HackExpGain
|
||||
)
|
||||
return <></>;
|
||||
const rows: IBNMultRows = {
|
||||
HackExpGain: {
|
||||
name: "Hacking Exp",
|
||||
color: Settings.theme.hack,
|
||||
},
|
||||
ServerGrowthRate: { name: "Server Growth Rate" },
|
||||
ServerMaxMoney: { name: "Server Max Money" },
|
||||
ServerStartingMoney: { name: "Server Starting Money" },
|
||||
ServerStartingSecurity: { name: "Server Starting Security" },
|
||||
ServerWeakenRate: { name: "Server Weaken Rate" },
|
||||
ManualHackMoney: {
|
||||
name: "Manual Hack Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
ScriptHackMoney: {
|
||||
name: "Script Hack Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
ScriptHackMoneyGain: {
|
||||
name: "Money Gained From Hack",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Hacking:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.HackExpGain !== defaultMultipliers.HackExpGain ? (
|
||||
<Typography>Exp: x{mults.HackExpGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerGrowthRate !== defaultMultipliers.ServerGrowthRate ? (
|
||||
<Typography>Growth rate: x{mults.ServerGrowthRate.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerMaxMoney !== defaultMultipliers.ServerMaxMoney ? (
|
||||
<Typography>Max money: x{mults.ServerMaxMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerStartingMoney !== defaultMultipliers.ServerStartingMoney ? (
|
||||
<Typography>Starting money: x{mults.ServerStartingMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerStartingSecurity !== defaultMultipliers.ServerStartingSecurity ? (
|
||||
<Typography>Starting security: x{mults.ServerStartingSecurity.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ServerWeakenRate !== defaultMultipliers.ServerWeakenRate ? (
|
||||
<Typography>Weaken rate: x{mults.ServerWeakenRate.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ManualHackMoney !== defaultMultipliers.ManualHackMoney ? (
|
||||
<Typography>Manual hack money: x{mults.ManualHackMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ScriptHackMoney !== defaultMultipliers.ScriptHackMoney ? (
|
||||
<Typography>Hack money stolen: x{mults.ScriptHackMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.ScriptHackMoneyGain !== defaultMultipliers.ScriptHackMoneyGain ? (
|
||||
<Typography>Money gained from hack: x{mults.ScriptHackMoneyGain.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
return <BNMultTable sectionName="Hacking" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function PurchasedServersMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.PurchasedServerCost === defaultMultipliers.PurchasedServerCost &&
|
||||
mults.PurchasedServerSoftcap === defaultMultipliers.PurchasedServerSoftcap &&
|
||||
mults.PurchasedServerLimit === defaultMultipliers.PurchasedServerLimit &&
|
||||
mults.PurchasedServerMaxRam === defaultMultipliers.PurchasedServerMaxRam &&
|
||||
mults.HomeComputerRamCost === defaultMultipliers.HomeComputerRamCost
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Purchased servers:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.PurchasedServerCost !== defaultMultipliers.PurchasedServerCost ? (
|
||||
<Typography>Base cost: {mults.PurchasedServerCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.PurchasedServerSoftcap !== defaultMultipliers.PurchasedServerSoftcap ? (
|
||||
<Typography>Softcap cost: {mults.PurchasedServerSoftcap.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.PurchasedServerLimit !== defaultMultipliers.PurchasedServerLimit ? (
|
||||
<Typography>Limit: x{mults.PurchasedServerLimit.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.PurchasedServerMaxRam !== defaultMultipliers.PurchasedServerMaxRam ? (
|
||||
<Typography>Max ram: x{mults.PurchasedServerMaxRam.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.HomeComputerRamCost !== defaultMultipliers.HomeComputerRamCost ? (
|
||||
<Typography>Home ram cost: x{mults.HomeComputerRamCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
PurchasedServerCost: {
|
||||
name: "Base Cost",
|
||||
content: mults.PurchasedServerCost.toFixed(3),
|
||||
},
|
||||
PurchasedServerSoftcap: {
|
||||
name: "Softcap Cost",
|
||||
content: mults.PurchasedServerSoftcap.toFixed(3),
|
||||
},
|
||||
PurchasedServerLimit: { name: "Server Limit" },
|
||||
PurchasedServerMaxRam: { name: "Max RAM" },
|
||||
HomeComputerRamCost: { name: "Home RAM Cost" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Purchased Servers" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function InfiltrationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
// is it empty check
|
||||
if (
|
||||
mults.InfiltrationMoney === defaultMultipliers.InfiltrationMoney &&
|
||||
mults.InfiltrationRep === defaultMultipliers.InfiltrationRep
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Infiltration:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.InfiltrationMoney !== defaultMultipliers.InfiltrationMoney ? (
|
||||
<Typography>Money: {mults.InfiltrationMoney.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.InfiltrationRep !== defaultMultipliers.InfiltrationRep ? (
|
||||
<Typography>Reputation: x{mults.InfiltrationRep.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
InfiltrationMoney: {
|
||||
name: "Infiltration Money",
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
InfiltrationRep: {
|
||||
name: "Infiltration Reputation",
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Infiltration" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function BladeburnerMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 6 && n !== 7 && player.sourceFileLvl(6) === 0) return <></>;
|
||||
//default mults check
|
||||
if (mults.BladeburnerRank === 1 && mults.BladeburnerSkillCost === 1) return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Bladeburner:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.BladeburnerRank !== 1 ? <Typography>Rank gain: x{mults.BladeburnerRank.toFixed(3)}</Typography> : <></>}
|
||||
{mults.BladeburnerSkillCost !== 1 ? (
|
||||
<Typography>Skill cost: x{mults.BladeburnerSkillCost.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
if (!player.canAccessBladeburner()) return <></>;
|
||||
|
||||
const rows: IBNMultRows = {
|
||||
BladeburnerRank: { name: "Rank Gain" },
|
||||
BladeburnerSkillCost: { name: "Skill Cost" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Bladeburner" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function StanekMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function StanekMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 13 && player.sourceFileLvl(13) === 0) return <></>;
|
||||
//default mults check
|
||||
if (
|
||||
mults.StaneksGiftExtraSize === defaultMultipliers.StaneksGiftExtraSize &&
|
||||
mults.StaneksGiftPowerMultiplier === defaultMultipliers.StaneksGiftPowerMultiplier
|
||||
)
|
||||
return <></>;
|
||||
if (!player.canAccessCotMG()) return <></>;
|
||||
|
||||
const s = mults.StaneksGiftExtraSize;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Stanek's Gift:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.StaneksGiftPowerMultiplier !== defaultMultipliers.StaneksGiftPowerMultiplier ? (
|
||||
<Typography>Gift power: x{mults.StaneksGiftPowerMultiplier.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{s !== defaultMultipliers.StaneksGiftExtraSize ? (
|
||||
<Typography>Base size modifier: {s > defaultMultipliers.StaneksGiftExtraSize ? `+${s}` : s}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const extraSize = mults.StaneksGiftExtraSize.toFixed(3);
|
||||
const rows: IBNMultRows = {
|
||||
StnakesGiftPowerMultiplier: { name: "Gift Power" },
|
||||
StaneksGiftExtraSize: {
|
||||
name: "Base Size Modifier",
|
||||
content: `${mults.StaneksGiftExtraSize > defaultMultipliers.StaneksGiftExtraSize ? `+${extraSize}` : extraSize}`,
|
||||
},
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Stanek's Gift" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function GangMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function GangMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 2 && player.sourceFileLvl(2) === 0) return <></>;
|
||||
// is it empty check
|
||||
if (
|
||||
mults.GangSoftcap === defaultMultipliers.GangSoftcap &&
|
||||
mults.GangUniqueAugs === defaultMultipliers.GangUniqueAugs
|
||||
)
|
||||
return <></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Gang:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.GangSoftcap !== defaultMultipliers.GangSoftcap ? (
|
||||
<Typography>Softcap: {mults.GangSoftcap.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.GangUniqueAugs !== defaultMultipliers.GangUniqueAugs ? (
|
||||
<Typography>Unique augs: x{mults.GangUniqueAugs.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
if (player.bitNodeN !== 2 && player.sourceFileLvl(2) <= 0) return <></>;
|
||||
|
||||
const rows: IBNMultRows = {
|
||||
GangSoftcap: {
|
||||
name: "Gang Softcap",
|
||||
content: mults.GangSoftcap.toFixed(3),
|
||||
},
|
||||
GangUniqueAugs: { name: "Unique Augmentations" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Gang" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
||||
function CorporationMults({ n, mults }: IMultsProps): React.ReactElement {
|
||||
function CorporationMults({ mults }: IMultsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// access check
|
||||
if (n !== 3 && player.sourceFileLvl(3) === 0) return <></>;
|
||||
// is it empty check
|
||||
if (
|
||||
mults.CorporationSoftCap === defaultMultipliers.CorporationSoftCap &&
|
||||
mults.CorporationValuation === defaultMultipliers.CorporationValuation
|
||||
)
|
||||
return <></>;
|
||||
if (!player.canAccessCorporation()) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant={"h5"}>Corporation:</Typography>
|
||||
<Box mx={1}>
|
||||
{mults.CorporationSoftCap !== defaultMultipliers.CorporationSoftCap ? (
|
||||
<Typography>Softcap: {mults.CorporationSoftCap.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{mults.CorporationValuation !== defaultMultipliers.CorporationValuation ? (
|
||||
<Typography>Valuation: x{mults.CorporationValuation.toFixed(3)}</Typography>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
const rows: IBNMultRows = {
|
||||
CorporationSoftcap: {
|
||||
name: "Corporation Softcap",
|
||||
content: mults.CorporationSoftcap.toFixed(3),
|
||||
},
|
||||
CorporationValuation: { name: "Valuation" },
|
||||
};
|
||||
|
||||
return <BNMultTable sectionName="Corporation" rowData={rows} mults={mults} />;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export function PortalModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
<Typography>{bitNode.info}</Typography>
|
||||
<BitnodeMultiplierDescription n={props.n} />
|
||||
<BitnodeMultiplierDescription n={props.n} level={newLevel} />
|
||||
<br />
|
||||
<br />
|
||||
<Button
|
||||
|
@ -700,7 +700,7 @@ export class Bladeburner implements IBladeburner {
|
||||
|
||||
// Set variables
|
||||
if (args.length === 4) {
|
||||
const variable = args[1];
|
||||
const variable = args[1].toLowerCase(); // allows Action Type to be with or without capitalisation.
|
||||
const val = args[2];
|
||||
|
||||
let highLow = false; // True for high, false for low
|
||||
@ -1993,7 +1993,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
if (player.hasAugmentation(AugmentationNames.BladesSimulacrum) === false && player.isWorking) {
|
||||
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && player.isWorking) {
|
||||
if (this.action.type !== ActionTypes["Idle"]) {
|
||||
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
|
||||
if (this.automateEnabled) {
|
||||
|
176
src/Constants.ts
176
src/Constants.ts
@ -84,11 +84,12 @@ export const CONSTANTS: {
|
||||
SoARepMult: number;
|
||||
EntropyEffect: number;
|
||||
TotalNumBitNodes: number;
|
||||
InfiniteLoopLimit: number;
|
||||
Donations: number; // number of blood/plasma/palette donation the dev have verified., boosts NFG
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
VersionString: "1.6.4",
|
||||
VersionNumber: 17,
|
||||
VersionString: "1.7.0",
|
||||
VersionNumber: 18,
|
||||
|
||||
// Speed (in ms) at which the main loop is updated
|
||||
_idleSpeed: 200,
|
||||
@ -226,22 +227,173 @@ export const CONSTANTS: {
|
||||
// BitNode/Source-File related stuff
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
InfiniteLoopLimit: 1000,
|
||||
|
||||
Donations: 7,
|
||||
|
||||
LatestUpdate: `
|
||||
v1.6.3 - 2022-04-01 Few stanek fixes
|
||||
----------------------------
|
||||
## [draft] v1.7.0 - 2022-04-13 to 2022-05-20
|
||||
|
||||
Stanek Gift
|
||||
#### Information
|
||||
|
||||
* Has a minimum size of 2x3
|
||||
* Active Fragment property 'avgCharge' renamed to 'highestCharge'
|
||||
* Formula for fragment effect updated to make 561% more sense.
|
||||
Now you can charge to your heart content.
|
||||
* Logs for the 'chargeFragment' function updated.
|
||||
Modifications included between **2022-04-13** and **2022-05-20** 'b5e4d70' to '0fbe4a1').
|
||||
|
||||
Misc.
|
||||
_[See Pull Requests on GitHub](https://github.com/search?q=user%3Adanielyxie%20repo%3Abitburner%20is%3Apr%20is%3Amerged%20merged%3A%222022-04-13T16%3A32%3A26.000Z..2022-05-20T06%3A08%3A51.000Z%22)_
|
||||
|
||||
#### Merged Pull Requests
|
||||
|
||||
- [Feature] Monaco Theme Editor (by @nickofolas) #[3438](https://github.com/danielyxie/bitburner/pull/3438)
|
||||
- [Fix] Dummy Stanek grid width (by @nickofolas) #[3442](https://github.com/danielyxie/bitburner/pull/3442)
|
||||
- [Fix] Theme browser assets not loading (by @nickofolas) #[3446](https://github.com/danielyxie/bitburner/pull/3446)
|
||||
- Accept valid JSON arrays in coding contracts (by @Savlik) #[3247](https://github.com/danielyxie/bitburner/pull/3247)
|
||||
- another dark theme? (by @hydroflame) #[3450](https://github.com/danielyxie/bitburner/pull/3450)
|
||||
- API: Add repFromDonation() to the Formula API (by @Hoekstraa) #[3461](https://github.com/danielyxie/bitburner/pull/3461)
|
||||
- API: Add safeguard to ns.killall(), preventing killing itself by default (by @Hoekstraa) #[3607](https://github.com/danielyxie/bitburner/pull/3607)
|
||||
- API: FIX #2993 sleeve.travel with invalid city names (by @TheMas3212) #[3458](https://github.com/danielyxie/bitburner/pull/3458)
|
||||
- API: Fix inconsistent return value in 'ns.grafting.getAugmentationGraftTime' (by @nickofolas) #[3539](https://github.com/danielyxie/bitburner/pull/3539)
|
||||
- API: Fix leak of real Employee object in hireEmployee (by @TheMas3212) #[3483](https://github.com/danielyxie/bitburner/pull/3483)
|
||||
- API: replace a number of references to workerscript.log with \_ctx.log (by @TheMas3212) #[3470](https://github.com/danielyxie/bitburner/pull/3470)
|
||||
- API: Terminal screen can now be cleared from within scripts with ns.ui.clearTerminal() (by @Hoekstraa) #[3618](https://github.com/danielyxie/bitburner/pull/3618)
|
||||
- AUGMENTATIONS: Fix 'isSpecial' filter in helper (Removes NeuroFlux, Stanek's Gift, etc from gangs) (by @nickofolas) #[3565](https://github.com/danielyxie/bitburner/pull/3565)
|
||||
- AUGMENTATIONS: Fix Augmentation rep req not being properly influenced by BitNode multipliers (by @nickofolas) #[3652](https://github.com/danielyxie/bitburner/pull/3652)
|
||||
- AUGMENTATIONS: Fix NeuroFlux being applied improperly and migrate broken saves (by @nickofolas) #[3613](https://github.com/danielyxie/bitburner/pull/3613)
|
||||
- AUGMENTATIONS: Fix reputation check for faction augs (by @nickofolas) #[3609](https://github.com/danielyxie/bitburner/pull/3609)
|
||||
- AUGMENTATIONS: Tweak a couple small UI elements (by @nickofolas) #[3614](https://github.com/danielyxie/bitburner/pull/3614)
|
||||
- basic doc no longer hacker themed (by @hydroflame) #[3449](https://github.com/danielyxie/bitburner/pull/3449)
|
||||
- BITNODE: FIX #3546 BitVerse now shows proper BN level when accessed via flume (by @nickofolas) #[3550](https://github.com/danielyxie/bitburner/pull/3550)
|
||||
- BLADEBURNER: fixes #3648 : Automate console command capitalisation inconsistent (by @Vic1970) #[3647](https://github.com/danielyxie/bitburner/pull/3647)
|
||||
- BLADEBURNER: Fix #3594 Blade's Simulacrum worked without being installed (by @Undeemiss) #[3639](https://github.com/danielyxie/bitburner/pull/3639)
|
||||
- blood (by @hydroflame) #[3495](https://github.com/danielyxie/bitburner/pull/3495)
|
||||
- BUGFIX: getAugmentationCost response backwards (by @phyzical) #[3617](https://github.com/danielyxie/bitburner/pull/3617)
|
||||
- BUGFIX: Handle edge case in LZ compression code and fix docs (by @stalefishies) #[3581](https://github.com/danielyxie/bitburner/pull/3581)
|
||||
- BUGFIX: make bonustime for gang in miliseconds (by @phyzical) #[3578](https://github.com/danielyxie/bitburner/pull/3578)
|
||||
- BUGFIX: sleeve stale object refence during augmentation (by @phyzical) #[3601](https://github.com/danielyxie/bitburner/pull/3601)
|
||||
- Bugfix/corp updates (by @phyzical) #[3321](https://github.com/danielyxie/bitburner/pull/3321)
|
||||
- Bump async from 2.6.3 to 2.6.4 (by @dependabot[bot]) #[3463](https://github.com/danielyxie/bitburner/pull/3463)
|
||||
- CODINGCONTRACT: Fix #3391 Double contract reward exploit (by @Undeemiss) #[3646](https://github.com/danielyxie/bitburner/pull/3646)
|
||||
- CODINGCONTRACT: FIX #3484 BREAKING Fixed capitalization in contract name (by @Undeemiss) #[3537](https://github.com/danielyxie/bitburner/pull/3537)
|
||||
- CODINGCONTRACT: New "Proper 2-Coloring of a Graph" contract (by @Undeemiss) #[3530](https://github.com/danielyxie/bitburner/pull/3530)
|
||||
- CODINGCONTRACT: Three new compression contracts (by @stalefishies) #[3541](https://github.com/danielyxie/bitburner/pull/3541)
|
||||
- CODINGCONTRACT: Typo & clarity fixes to description of Encoded Binary to Integer contract (by @ActuallyCurtis) #[3469](https://github.com/danielyxie/bitburner/pull/3469)
|
||||
- CODINGCONTRACT: Updated description of 2-coloring contract (by @Undeemiss) #[3531](https://github.com/danielyxie/bitburner/pull/3531)
|
||||
- COMPANY: Fix #3551 Applying for a new job will not change active employer if player is performing company work (by @Snarling) #[3552](https://github.com/danielyxie/bitburner/pull/3552)
|
||||
- CORPORATIONS: Expose makeProducts on NSDivision interface (by @DavidGrinberg) #[3570](https://github.com/danielyxie/bitburner/pull/3570)
|
||||
- CORPORATIONS: Expose sales cost on NSMaterial interface (by @DavidGrinberg) #[3574](https://github.com/danielyxie/bitburner/pull/3574)
|
||||
- Corrected example grids found in Stanek help (by @Undeemiss) #[3441](https://github.com/danielyxie/bitburner/pull/3441)
|
||||
- Create program action no longer creates duplicates (by @Undeemiss) #[3436](https://github.com/danielyxie/bitburner/pull/3436)
|
||||
- DOCUMENTATION: Add descriptions for compression contracts (by @stalefishies) #[3559](https://github.com/danielyxie/bitburner/pull/3559)
|
||||
- DOCUMENTATION: Add new coding contract descriptions (by @stalefishies) #[3542](https://github.com/danielyxie/bitburner/pull/3542)
|
||||
- DOCUMENTATION: Clarify definition for installAugmentations() (by @PSEUDOSTAGE) #[3560](https://github.com/danielyxie/bitburner/pull/3560)
|
||||
- DOCUMENTATION: FIX #3516 "cannot" misspelled as "cannnot" (by @Undeemiss) #[3533](https://github.com/danielyxie/bitburner/pull/3533)
|
||||
- EDITOR: FIX #3502 Editor theme migration crash (by @nickofolas) #[3503](https://github.com/danielyxie/bitburner/pull/3503)
|
||||
- FEATURE: added logic to allow quitJob to be called from singularity (by @phyzical) #[3577](https://github.com/danielyxie/bitburner/pull/3577)
|
||||
- fix #3395 donating to special factions possible via singularity (by @TheMas3212) #[3456](https://github.com/danielyxie/bitburner/pull/3456)
|
||||
- fix b1tflum3 and destroyW0r1dD43m0n singularity functions to check for sf4 (by @TheMas3212) #[3443](https://github.com/danielyxie/bitburner/pull/3443)
|
||||
- Fix inconsistancy with trying to work for gang factions while running a gang (by @TheMas3212) #[3454](https://github.com/danielyxie/bitburner/pull/3454)
|
||||
- Fix infiltration rep BN mult calculation (by @trambelus) #[3632](https://github.com/danielyxie/bitburner/pull/3632)
|
||||
- Fix script editor settings. (by @hydroflame) #[3504](https://github.com/danielyxie/bitburner/pull/3504)
|
||||
- Fix test/jest/Netscript/DynamicRamCalculation.test.js (by @TheMas3212) #[3455](https://github.com/danielyxie/bitburner/pull/3455)
|
||||
- GRAFTING: Fix Grafting not being handled in singularity stop work (by @nickofolas) #[3568](https://github.com/danielyxie/bitburner/pull/3568)
|
||||
- GRAFTING: Implement sorting options (by @nickofolas) #[3654](https://github.com/danielyxie/bitburner/pull/3654)
|
||||
- INFILTRATION: Added new faction called infiltrators that provide infiltration specific augs. (by @phyzical) #[3241](https://github.com/danielyxie/bitburner/pull/3241)
|
||||
- INFILTRATION: Fix minigame cycle (by @nickofolas) #[3549](https://github.com/danielyxie/bitburner/pull/3549)
|
||||
- INFILTRATION: Fix phyzical WKS aug effects being applied before aug is installed (by @nickofolas) #[3555](https://github.com/danielyxie/bitburner/pull/3555)
|
||||
- INFILTRATION: Fix rep reward being substantially higher than intended (by @nickofolas) #[3562](https://github.com/danielyxie/bitburner/pull/3562)
|
||||
- INFILTRATION: New faction, Shadows of Anarchy, provides various augs to help infiltrations. (by @hydroflame) #[3543](https://github.com/danielyxie/bitburner/pull/3543)
|
||||
- INFILTRATION: Update gameplay UI (by @nickofolas) #[3587](https://github.com/danielyxie/bitburner/pull/3587)
|
||||
- keeping up to date (by @hydroflame) #[3432](https://github.com/danielyxie/bitburner/pull/3432)
|
||||
- Keeping up to date. (by @hydroflame) #[3561](https://github.com/danielyxie/bitburner/pull/3561)
|
||||
- Make .lit and .msg files clickable (by @Chris380) #[3453](https://github.com/danielyxie/bitburner/pull/3453)
|
||||
- MESSAGES: Added the name of NiteSec's server to their .msg (by @Undeemiss) #[3466](https://github.com/danielyxie/bitburner/pull/3466)
|
||||
- MISC: add better typing to Electron.tsx (by @taralx) #[3540](https://github.com/danielyxie/bitburner/pull/3540)
|
||||
- MISC: Added NS function closeTail to close tail windows (by @Undeemiss) #[3666](https://github.com/danielyxie/bitburner/pull/3666)
|
||||
- MISC: Adjust deps to current usage (by @taralx) #[3519](https://github.com/danielyxie/bitburner/pull/3519)
|
||||
- MISC: Close some GitHub issues that do not need action (by @Undeemiss) #[3640](https://github.com/danielyxie/bitburner/pull/3640)
|
||||
- MISC: Closing more GitHub issues I missed last time (by @Undeemiss) #[3665](https://github.com/danielyxie/bitburner/pull/3665)
|
||||
- MISC: Correct BB Skill point achievement name (by @Undeemiss) #[3571](https://github.com/danielyxie/bitburner/pull/3571)
|
||||
- MISC: Correct typos in getScriptRam docs. (by @nzdjb) #[3590](https://github.com/danielyxie/bitburner/pull/3590)
|
||||
- MISC: Fix #3125 BREAKING Renamed BN mult CorporationSoftCap to CorporationSoftcap (by @Undeemiss) #[3638](https://github.com/danielyxie/bitburner/pull/3638)
|
||||
- MISC: FIX #3593 Float errors can no longer prevent full usage of a server's available ram. (by @Snarling) #[3619](https://github.com/danielyxie/bitburner/pull/3619)
|
||||
- MISC: fix typing conflict between jest and cypress (by @taralx) #[3518](https://github.com/danielyxie/bitburner/pull/3518)
|
||||
- MISC: fix typing conflict between jest and cypress (by @taralx) #[3644](https://github.com/danielyxie/bitburner/pull/3644)
|
||||
- MISC: Fixed typo in exceptionAlert.ts (by @Undeemiss) #[3572](https://github.com/danielyxie/bitburner/pull/3572)
|
||||
- MISC: Fixed typos in game options (by @notacompsciguy) #[3584](https://github.com/danielyxie/bitburner/pull/3584)
|
||||
- MISC: HammingCodingContracts need rework (by @Hedrauta) #[3479](https://github.com/danielyxie/bitburner/pull/3479)
|
||||
- MISC: Implemented infinite loop safety net. (by @hydroflame) #[3624](https://github.com/danielyxie/bitburner/pull/3624)
|
||||
- MISC: make jQuery use explicit (by @taralx) #[3517](https://github.com/danielyxie/bitburner/pull/3517)
|
||||
- MISC: Make tutorial explain ns1 vs ns2 better (by @hydroflame) #[3586](https://github.com/danielyxie/bitburner/pull/3586)
|
||||
- MISC: Remove comments that describe nonexistent augs (by @Undeemiss) #[3569](https://github.com/danielyxie/bitburner/pull/3569)
|
||||
- MISC: update @types/numeral and fix type errors (by @taralx) #[3521](https://github.com/danielyxie/bitburner/pull/3521)
|
||||
- MISC: Update logic for stats page BitNode level (by @nickofolas) #[3512](https://github.com/danielyxie/bitburner/pull/3512)
|
||||
- MISC: upgrade to eslint v8 (by @taralx) #[3523](https://github.com/danielyxie/bitburner/pull/3523)
|
||||
- MISC: Wrap most of the API in the new api wrapper (by @hydroflame) #[3627](https://github.com/danielyxie/bitburner/pull/3627)
|
||||
- OPTIONS: Fix sliders not sliding correctly (by @nickofolas) #[3642](https://github.com/danielyxie/bitburner/pull/3642)
|
||||
- REFACTOR: augmentation cost, rep cost and level to be calculated in place (by @phyzical) #[3544](https://github.com/danielyxie/bitburner/pull/3544)
|
||||
- REFACTOR: augmentation isSpecial adjustments (by @phyzical) #[3564](https://github.com/danielyxie/bitburner/pull/3564)
|
||||
- Reran npm format and lint to fix formatting (by @Undeemiss) #[3434](https://github.com/danielyxie/bitburner/pull/3434)
|
||||
- Revert "MISC: fix typing conflict between jest and cypress" (by @hydroflame) #[3608](https://github.com/danielyxie/bitburner/pull/3608)
|
||||
- Revert "MISC: HammingCodingContracts need rework" (by @hydroflame) #[3500](https://github.com/danielyxie/bitburner/pull/3500)
|
||||
- revert theme (by @hydroflame) #[3451](https://github.com/danielyxie/bitburner/pull/3451)
|
||||
- Singularity: Fix #3489 Disable checkTixApiAccess for purchase4SMarketData (by @DavidGrinberg) #[3490](https://github.com/danielyxie/bitburner/pull/3490)
|
||||
- SLEEVES: Fix issues with Sleeve UI crashing when Sleeve task faction becomes gang faction (by @nickofolas) #[3557](https://github.com/danielyxie/bitburner/pull/3557)
|
||||
- STANEK: Fix #3196 Charging booster fragments throws an error (by @Undeemiss) #[3637](https://github.com/danielyxie/bitburner/pull/3637)
|
||||
- STANEK: FIX #3277 Can no longer overlap rotated fragments (by @Undeemiss) #[3460](https://github.com/danielyxie/bitburner/pull/3460)
|
||||
- STANEK: FIX #3282 Added NS function stanek.acceptGift (by @Undeemiss) #[3513](https://github.com/danielyxie/bitburner/pull/3513)
|
||||
- STANEK: Properly reapply entropy in Stanek's Gift (by @nickofolas) #[3673](https://github.com/danielyxie/bitburner/pull/3673)
|
||||
- STANEK: Stanek NS functions correctly throw errors when stanek not installed (by @Undeemiss) #[3660](https://github.com/danielyxie/bitburner/pull/3660)
|
||||
- Started collecting lore so that additions to it are simpler (by @Undeemiss) #[3465](https://github.com/danielyxie/bitburner/pull/3465)
|
||||
- TERMINAL: FIX #3492 Allow cd .. even when destination directory is empty (by @Snarling) #[3525](https://github.com/danielyxie/bitburner/pull/3525)
|
||||
- TERMINAL: FIX #3651 Make directory name regex more flexible (by @Dane-Horn) #[3653](https://github.com/danielyxie/bitburner/pull/3653)
|
||||
- TOOLING: Add GitHub action to validate PR titles (by @MartinFournier) #[3471](https://github.com/danielyxie/bitburner/pull/3471)
|
||||
- UI FIX #3485 - Allow bulk purchasing when smart supply is enabled (by @phyzical) #[3486](https://github.com/danielyxie/bitburner/pull/3486)
|
||||
- UI: Change text color of Augmentations page backup button (by @nickofolas) #[3511](https://github.com/danielyxie/bitburner/pull/3511)
|
||||
- UI: FIX #1754 Stanek effect summary & slight tweak. (by @borisflagell) #[3622](https://github.com/danielyxie/bitburner/pull/3622)
|
||||
- UI: FIX #2228,#2958 Fix tab highlights and highlight files not on home. (by @phyzical) #[2989](https://github.com/danielyxie/bitburner/pull/2989)
|
||||
- UI: FIX #2256 Hacknet server's upgrade tooltip were not handling RAM… (by @borisflagell) #[3532](https://github.com/danielyxie/bitburner/pull/3532)
|
||||
- UI: FIX #2741 Allow using modifier keys inside the typing infiltration (by @Dane-Horn) #[3634](https://github.com/danielyxie/bitburner/pull/3634)
|
||||
- UI: FIX #2829 Remove defeated NPC gangs from territory page (by @Dane-Horn) #[3633](https://github.com/danielyxie/bitburner/pull/3633)
|
||||
- UI: FIX #3313 Streamline the GraftingRoot page by making it rerender. (by @borisflagell) #[3558](https://github.com/danielyxie/bitburner/pull/3558)
|
||||
- UI: FIX #3341 Enable touch-clicks in react-draggable (by @Snarling) #[3488](https://github.com/danielyxie/bitburner/pull/3488)
|
||||
- UI: FIX #3415 Tweak Manage Gang button visibility (by @borisflagell) #[3528](https://github.com/danielyxie/bitburner/pull/3528)
|
||||
- UI: FIX #3457 autocomplete suggestions no longer require hovering terminal input (by @Snarling) #[3493](https://github.com/danielyxie/bitburner/pull/3493)
|
||||
- UI: FIX #3473 'mv' now says destination script is running instead of returning an error (by @Hoekstraa) #[3474](https://github.com/danielyxie/bitburner/pull/3474)
|
||||
- UI: FIX #3522 realigned autocomplete popup (by @Snarling) #[3524](https://github.com/danielyxie/bitburner/pull/3524)
|
||||
- UI: FIX #3592 Sidebar and bash shortcuts now work on MacOS with US-like layouts (by @Hoekstraa) #[3605](https://github.com/danielyxie/bitburner/pull/3605)
|
||||
- UI: Fix Agility BitNode multiplier not appearing in UI (by @nickofolas) #[3662](https://github.com/danielyxie/bitburner/pull/3662)
|
||||
- UI: Fix exclusive augs not always showing as purchasable through gangs when they should (by @nickofolas) #[3676](https://github.com/danielyxie/bitburner/pull/3676)
|
||||
- UI: Fix the achievement covenant icon was not shown (by @Risenafis) #[3510](https://github.com/danielyxie/bitburner/pull/3510)
|
||||
- UI: Fix z-index of modals overriding everything (by @nickofolas) #[3620](https://github.com/danielyxie/bitburner/pull/3620)
|
||||
- UI: lightweight description update on "increase maximum money" hash spending option. (by @borisflagell) #[3547](https://github.com/danielyxie/bitburner/pull/3547)
|
||||
- UI: Minor improvements to log boxes (by @nickofolas) #[3641](https://github.com/danielyxie/bitburner/pull/3641)
|
||||
- UI: Overhaul GameOptions UI (by @nickofolas) #[3505](https://github.com/danielyxie/bitburner/pull/3505)
|
||||
- UI: Positioning improved for tail titlebar buttons, and tail window has minimum size constraints. (by @Snarling) #[3548](https://github.com/danielyxie/bitburner/pull/3548)
|
||||
- UI: Redesign purchasable Augmentations (by @nickofolas) #[3545](https://github.com/danielyxie/bitburner/pull/3545)
|
||||
- UI: Refactor and redesign WorkInProgress interface (by @nickofolas) #[3611](https://github.com/danielyxie/bitburner/pull/3611)
|
||||
- UI: Refactors, redesigns, and new section to stats page (by @nickofolas) #[3626](https://github.com/danielyxie/bitburner/pull/3626)
|
||||
- UI: Sort and color Graft Augmentation list (by @jaype87) #[3616](https://github.com/danielyxie/bitburner/pull/3616)
|
||||
- UI: Update Factions list interface (by @nickofolas) #[3675](https://github.com/danielyxie/bitburner/pull/3675)
|
||||
- WORK: FIX #3435 Quitting the active job now sets first remaining job as active (by @Snarling) #[3507](https://github.com/danielyxie/bitburner/pull/3507)
|
||||
- WORK: Refactor work types to use 'enum's instead of constants (by @nickofolas) #[3612](https://github.com/danielyxie/bitburner/pull/3612)
|
||||
|
||||
#### Other Changes
|
||||
|
||||
- increase donation counter (by @hydroflame) - [8456410](https://github.com/danielyxie/bitburner/commit/84564100e90c46ae4b816853c2cdea0bc309af4d)
|
||||
- allbuild commit 7f9e3775 (by @hydroflame) - [791c19c](https://github.com/danielyxie/bitburner/commit/791c19c4fe447c9231bfb423b9fc48114e783b43)
|
||||
- allbuild commit bcbda22a (by @hydroflame) - [032c440](https://github.com/danielyxie/bitburner/commit/032c440eaeb069eecd720ec2f8e069f705a0c1b4)
|
||||
- fix documentation for getDarkwebPrograms (by @hydroflame) - [4056956](https://github.com/danielyxie/bitburner/commit/4056956c2ada37946333bdad44cb0b6eb3909bf8)
|
||||
- support ASNI (by @hydroflame) - [36c7ef1](https://github.com/danielyxie/bitburner/commit/36c7ef1ad7ea8bb69fca23bce5883a3c2e23f1e0)
|
||||
- allbuild commit 22b6d0d5 (by @hydroflame) - [b46718d](https://github.com/danielyxie/bitburner/commit/b46718d188880ecf716ae045861d81d61e00af4b)
|
||||
- allbuild commit 36c7ef1a (by @hydroflame) - [d0ebf5e](https://github.com/danielyxie/bitburner/commit/d0ebf5e14e0498cb063fde35d63c9f59f2c01e35)
|
||||
- Update documentation for employee (by @hydroflame) - [100e81c](https://github.com/danielyxie/bitburner/commit/100e81c8ab4a408f74cc9bd9ffe2b8bad3d03462)
|
||||
- allbuild commit c799b291 (by @hydroflame) - [f5f5879](https://github.com/danielyxie/bitburner/commit/f5f5879fc380678d978e2b0a29ba7b6f0b4c9ec0)
|
||||
- ideas (by @hydroflame) - [0121fee](https://github.com/danielyxie/bitburner/commit/0121fee6e4c690d01650d1e68a80ea363bb48bce)
|
||||
- allbuild commit 0121fee6 (by @hydroflame) - [5c417e9](https://github.com/danielyxie/bitburner/commit/5c417e9b4df236df8bf3e2f8262b7bce87c934df)
|
||||
- Update codebase for stanek (by @hydroflame) - [c2b4a5b](https://github.com/danielyxie/bitburner/commit/c2b4a5b52a2162d2e49c7317b0a60a349984eb47)
|
||||
- fix lint (by @hydroflame) - [4cc518f](https://github.com/danielyxie/bitburner/commit/4cc518f37723aafb3168b64cd689408afdb74877)
|
||||
- Fix (by @hydroflame) - [9af553f](https://github.com/danielyxie/bitburner/commit/9af553f63cb1380795550648b0134b608564fab8)
|
||||
- Fix stanek leaking classes (by @hydroflame) - [fda3f02](https://github.com/danielyxie/bitburner/commit/fda3f02d73dba27034128c9be5e810a51e475e38)
|
||||
- fix conflicts (by @hydroflame) - [ca1a2aa](https://github.com/danielyxie/bitburner/commit/ca1a2aad333fa838b6d0e57f89e1cedba086a4a0)
|
||||
- Nerf noodle bar.
|
||||
|
||||
* Nerf noodle bar.
|
||||
`,
|
||||
};
|
||||
|
@ -159,7 +159,7 @@ export class Corporation {
|
||||
if (this.unlockUpgrades[6] === 1) {
|
||||
upgrades += 0.1;
|
||||
}
|
||||
return Math.pow(dividends, BitNodeMultipliers.CorporationSoftCap + upgrades);
|
||||
return Math.pow(dividends, BitNodeMultipliers.CorporationSoftcap + upgrades);
|
||||
}
|
||||
|
||||
determineValuation(): number {
|
||||
|
@ -68,13 +68,7 @@ export class ActiveFragment {
|
||||
}
|
||||
|
||||
copy(): ActiveFragment {
|
||||
// We have to do a round trip because the constructor.
|
||||
const fragment = FragmentById(this.id);
|
||||
if (fragment === null) throw new Error("ActiveFragment id refers to unknown Fragment.");
|
||||
const c = new ActiveFragment({ x: this.x, y: this.y, rotation: this.rotation, fragment: fragment });
|
||||
c.highestCharge = this.highestCharge;
|
||||
c.numCharge = this.numCharge;
|
||||
return c;
|
||||
return Object.assign({}, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,13 +76,7 @@ export class Fragment {
|
||||
}
|
||||
|
||||
copy(): Fragment {
|
||||
return new Fragment(
|
||||
this.id,
|
||||
this.shape.map((a) => a.slice()),
|
||||
this.type,
|
||||
this.power,
|
||||
this.limit,
|
||||
);
|
||||
return Object.assign({}, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,8 +136,9 @@ export class StaneksGift implements IStaneksGift {
|
||||
}
|
||||
|
||||
updateMults(p: IPlayer): void {
|
||||
p.reapplyAllAugmentations(true);
|
||||
p.reapplyAllSourceFiles();
|
||||
// applyEntropy also reapplies all augmentations and source files
|
||||
// This wraps up the reset nicely
|
||||
p.applyEntropy(p.entropy);
|
||||
|
||||
for (const aFrag of this.fragments) {
|
||||
const fragment = aFrag.fragment();
|
||||
|
@ -1,5 +0,0 @@
|
||||
import { StanekConstants } from "../data/Constants";
|
||||
|
||||
export function CalculateCharge(ram: number): number {
|
||||
return ram * Math.pow(1 + Math.log2(ram) * StanekConstants.RAMBonus, 0.7);
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
|
||||
export function CalculateEffect(avgCharge: number, numCharge: number, power: number, boost: number): number {
|
||||
export function CalculateEffect(highestCharge: number, numCharge: number, power: number, boost: number): number {
|
||||
return (
|
||||
1 +
|
||||
(Math.log(avgCharge + 1) / (Math.log(1.8) * 100)) *
|
||||
(Math.log(highestCharge + 1) / 60) *
|
||||
Math.pow((numCharge + 1) / 5, 0.07) *
|
||||
power *
|
||||
boost *
|
||||
|
88
src/CotMG/ui/ActiveFragmentSummary.tsx
Normal file
88
src/CotMG/ui/ActiveFragmentSummary.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import { ActiveFragment } from "../ActiveFragment";
|
||||
import { IStaneksGift } from "../IStaneksGift";
|
||||
import { FragmentType, Effect } from "../FragmentType";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Table from "@mui/material/Table";
|
||||
import { TableBody, TableCell, TableRow } from "@mui/material";
|
||||
|
||||
type IProps = {
|
||||
gift: IStaneksGift;
|
||||
};
|
||||
|
||||
function formatEffect(effect: number, type: FragmentType): string {
|
||||
if (Effect(type).includes("+x%")) {
|
||||
return Effect(type).replace(/-*x%/, numeralWrapper.formatPercentage(effect - 1));
|
||||
} else if (Effect(type).includes("-x%")) {
|
||||
const perc = numeralWrapper.formatPercentage(1 - 1 / effect);
|
||||
return Effect(type).replace(/-x%/, perc);
|
||||
} else {
|
||||
return Effect(type);
|
||||
}
|
||||
}
|
||||
|
||||
export function ActiveFragmentSummary(props: IProps): React.ReactElement {
|
||||
const summary: { coordinate: { x: number; y: number }[]; effect: number; type: FragmentType }[] = [];
|
||||
// Iterate through Active Fragment
|
||||
props.gift.fragments.forEach((fragment: ActiveFragment) => {
|
||||
const f = fragment.fragment();
|
||||
// Discard ToolBrush and Booster.
|
||||
if (![FragmentType.Booster, FragmentType.None, FragmentType.Delete].includes(f.type)) {
|
||||
// Check for an existing entry in summary for this fragment's type
|
||||
const entry = summary.find((e) => {
|
||||
return e.type === f.type;
|
||||
});
|
||||
if (entry) {
|
||||
// If there's one, update the existing entry
|
||||
entry.effect *= props.gift.effect(fragment);
|
||||
entry.coordinate.push({ x: fragment.x, y: fragment.y });
|
||||
} else {
|
||||
// If there's none, create a new entry
|
||||
summary.push({
|
||||
coordinate: [{ x: fragment.x, y: fragment.y }],
|
||||
effect: props.gift.effect(fragment),
|
||||
type: f.type,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Paper sx={{ mb: 1 }}>
|
||||
<Typography variant="h5">Summary of active fragments:</Typography>
|
||||
<Table sx={{ display: "table", width: "100%" }}>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell sx={{ borderBottom: "none", p: 0, m: 0 }}>
|
||||
<Typography>Coordinate</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell sx={{ borderBottom: "none", p: 0, m: 0 }}>
|
||||
<Typography>Effect</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{summary.map((entry) => {
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell sx={{ borderBottom: "none", p: 0, m: 0 }}>
|
||||
<Typography>
|
||||
{entry.coordinate.map((coord) => {
|
||||
return "[" + coord.x + "," + coord.y + "]";
|
||||
})}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell sx={{ borderBottom: "none", p: 0, m: 0 }}>
|
||||
<Typography>{formatEffect(entry.effect, entry.type)}</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
);
|
||||
}
|
@ -25,23 +25,21 @@ export function FragmentInspector(props: IProps): React.ReactElement {
|
||||
|
||||
if (props.fragment === undefined) {
|
||||
return (
|
||||
<Paper>
|
||||
<Paper sx={{ flexGrow: 1 }}>
|
||||
<Typography>
|
||||
[X, Y] {props.x}, {props.y}
|
||||
<br />
|
||||
<br />
|
||||
ID: N/A
|
||||
<br />
|
||||
Effect: N/A
|
||||
<br />
|
||||
Magnitude: N/A
|
||||
Base Power: N/A
|
||||
<br />
|
||||
Charge: N/A
|
||||
<br />
|
||||
Heat: N/A
|
||||
root [X, Y] N/A
|
||||
<br />
|
||||
Effect: N/A
|
||||
<br />
|
||||
[X, Y] N/A
|
||||
<br />
|
||||
[X, Y] {props.x}, {props.y}
|
||||
</Typography>
|
||||
</Paper>
|
||||
);
|
||||
@ -63,8 +61,11 @@ export function FragmentInspector(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<Paper sx={{ flexGrow: 1 }}>
|
||||
<Typography>
|
||||
[X, Y] {props.x}, {props.y}
|
||||
<br />
|
||||
<br />
|
||||
ID: {props.fragment.id}
|
||||
<br />
|
||||
Effect: {effect}
|
||||
@ -73,10 +74,8 @@ export function FragmentInspector(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
Charge: {charge}
|
||||
<br />
|
||||
<br />
|
||||
root [X, Y] {props.fragment.x}, {props.fragment.y}
|
||||
<br />
|
||||
[X, Y] {props.x}, {props.y}
|
||||
</Typography>
|
||||
</Paper>
|
||||
);
|
||||
|
@ -9,6 +9,9 @@ import Button from "@mui/material/Button";
|
||||
import { Table } from "../../ui/React/Table";
|
||||
import { Grid } from "./Grid";
|
||||
import { zeros, calculateGrid } from "../Helper";
|
||||
import { ActiveFragmentSummary } from "./ActiveFragmentSummary";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
interface IProps {
|
||||
gift: IStaneksGift;
|
||||
@ -84,9 +87,8 @@ export function MainBoard(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={clear}>Clear</Button>
|
||||
<Box display="flex">
|
||||
<Table>
|
||||
<Box display="flex" sx={{ mb: 1 }}>
|
||||
<Table sx={{ mr: 1 }}>
|
||||
<Grid
|
||||
width={props.gift.width()}
|
||||
height={props.gift.height()}
|
||||
@ -99,7 +101,22 @@ export function MainBoard(props: IProps): React.ReactElement {
|
||||
</Table>
|
||||
<FragmentInspector gift={props.gift} x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} />
|
||||
</Box>
|
||||
<FragmentSelector gift={props.gift} selectFragment={updateSelectedFragment} />
|
||||
<Box display="flex" sx={{ mb: 1 }}>
|
||||
<FragmentSelector gift={props.gift} selectFragment={updateSelectedFragment} />
|
||||
</Box>
|
||||
|
||||
<ActiveFragmentSummary gift={props.gift} />
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
WARNING : This will remove all active fragment from the grid. <br />
|
||||
All cumulated charges will be lost.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Button onClick={clear}>Clear grid</Button>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import Typography from "@mui/material/Typography";
|
||||
import { ActiveFragment } from "../ActiveFragment";
|
||||
import { Fragments } from "../Fragment";
|
||||
import { DummyGrid } from "./DummyGrid";
|
||||
import Container from "@mui/material/Container";
|
||||
|
||||
type IProps = {
|
||||
staneksGift: IStaneksGift;
|
||||
@ -22,7 +23,7 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
}
|
||||
useEffect(() => StaneksGiftEvents.subscribe(rerender), []);
|
||||
return (
|
||||
<>
|
||||
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
|
||||
<Typography variant="h4">
|
||||
Stanek's Gift
|
||||
<Info
|
||||
@ -184,18 +185,18 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
/>
|
||||
</Typography>
|
||||
|
||||
<Typography>
|
||||
<Typography sx={{ mb: 1 }}>
|
||||
The gift is a grid on which you can place upgrades called fragments. The main type of fragment increases a stat,
|
||||
like your hacking skill or agility exp. Once a stat fragment is placed it then needs to be charged via scripts
|
||||
in order to become useful. The other kind of fragments are called booster fragments. They increase the
|
||||
efficiency of the neighboring fragments (not diagonally). Use Q/E to rotate fragments.
|
||||
</Typography>
|
||||
{staneksGift.storedCycles > 5 && (
|
||||
<Typography>
|
||||
<Typography sx={{ mb: 1 }}>
|
||||
Bonus time: {convertTimeMsToTimeElapsedString(CONSTANTS._idleSpeed * staneksGift.storedCycles)}
|
||||
</Typography>
|
||||
)}
|
||||
<MainBoard gift={staneksGift} />
|
||||
</>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -1,24 +1,194 @@
|
||||
import { Explore, Info, LastPage, LocalPolice, NewReleases, Report, SportsMma } from "@mui/icons-material";
|
||||
import { Box, Button, Container, Paper, Tooltip, Typography, useTheme } from "@mui/material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { Box, Button, Container, Paper, TableBody, TableRow, Typography } from "@mui/material";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Table, TableCell } from "../../ui/React/Table";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
import { Faction } from "../Faction";
|
||||
import { joinFaction, getFactionAugmentationsFiltered } from "../FactionHelpers";
|
||||
import { Factions } from "../Factions";
|
||||
import { FactionNames } from "../data/FactionNames";
|
||||
import { Faction } from "../Faction";
|
||||
import { getFactionAugmentationsFiltered, joinFaction } from "../FactionHelpers";
|
||||
import { Factions } from "../Factions";
|
||||
|
||||
export const InvitationsSeen: string[] = [];
|
||||
|
||||
const getAugsLeft = (faction: Faction, player: IPlayer): number => {
|
||||
const augs = getFactionAugmentationsFiltered(player, faction);
|
||||
|
||||
return augs.filter((augmentation: string) => !player.hasAugmentation(augmentation)).length;
|
||||
};
|
||||
|
||||
interface IWorkTypeProps {
|
||||
faction: Faction;
|
||||
}
|
||||
|
||||
const fontSize = "small";
|
||||
const marginRight = 0.5;
|
||||
|
||||
const WorkTypesOffered = (props: IWorkTypeProps): React.ReactElement => {
|
||||
const info = props.faction.getInfo();
|
||||
|
||||
return (
|
||||
<>
|
||||
{info.offerFieldWork && (
|
||||
<Tooltip title="This Faction offers field work">
|
||||
<Explore sx={{ color: Settings.theme.info, mr: marginRight }} fontSize={fontSize} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{info.offerHackingWork && (
|
||||
<Tooltip title="This Faction offers hacking work">
|
||||
<LastPage sx={{ color: Settings.theme.hack, mr: marginRight }} fontSize={fontSize} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{info.offerSecurityWork && (
|
||||
<Tooltip title="This Faction offers security work">
|
||||
<LocalPolice sx={{ color: Settings.theme.combat, mr: marginRight }} fontSize={fontSize} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface IFactionProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
faction: Faction;
|
||||
|
||||
joined: boolean;
|
||||
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
const FactionElement = (props: IFactionProps): React.ReactElement => {
|
||||
const facInfo = props.faction.getInfo();
|
||||
|
||||
function openFaction(faction: Faction): void {
|
||||
props.router.toFaction(faction);
|
||||
}
|
||||
|
||||
function openFactionAugPage(faction: Faction): void {
|
||||
props.router.toFaction(faction, true);
|
||||
}
|
||||
|
||||
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, faction: string): void {
|
||||
if (!event.isTrusted) return;
|
||||
joinFaction(Factions[faction]);
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
display: "grid",
|
||||
p: 1,
|
||||
alignItems: "center",
|
||||
gridTemplateColumns: "minmax(0, 4fr)" + (props.joined ? " 1fr" : ""),
|
||||
}}
|
||||
>
|
||||
<Box display="flex" sx={{ alignItems: "center" }}>
|
||||
{props.joined ? (
|
||||
<Box
|
||||
display="grid"
|
||||
sx={{
|
||||
mr: 1,
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
minWidth: "fit-content",
|
||||
gap: 0.5,
|
||||
"& .MuiButton-root": { height: "48px" },
|
||||
}}
|
||||
>
|
||||
<Button onClick={() => openFaction(props.faction)}>Details</Button>
|
||||
<Button onClick={() => openFactionAugPage(props.faction)}>Augments</Button>
|
||||
</Box>
|
||||
) : (
|
||||
<Button sx={{ height: "48px", mr: 1 }} onClick={(e) => acceptInvitation(e, props.faction.name)}>
|
||||
Join!
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<span style={{ maxWidth: props.joined ? "70%" : "95%" }}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
mr: 1,
|
||||
display: "grid",
|
||||
gridTemplateColumns: "fit-content(100vw) max-content",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}
|
||||
title={props.faction.name}
|
||||
>
|
||||
{props.faction.name}
|
||||
</span>
|
||||
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
{props.player.hasGangWith(props.faction.name) && (
|
||||
<Tooltip title="You have a gang with this Faction">
|
||||
<SportsMma sx={{ color: Settings.theme.hp, ml: 1 }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{facInfo.special && (
|
||||
<Tooltip title="This is a special Faction">
|
||||
<NewReleases sx={{ ml: 1, color: Settings.theme.money, transform: "rotate(180deg)" }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{!props.joined && facInfo.enemies.length > 0 && (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
This Faction is enemies with:
|
||||
<ul>
|
||||
{facInfo.enemies.map((enemy) => (
|
||||
<li key={enemy}>{enemy}</li>
|
||||
))}
|
||||
</ul>
|
||||
Joining this Faction will prevent you from joining its enemies
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Report sx={{ ml: 1, color: Settings.theme.error }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</span>
|
||||
</Typography>
|
||||
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
{!props.player.hasGangWith(props.faction.name) && <WorkTypesOffered faction={props.faction} />}
|
||||
|
||||
{props.joined && (
|
||||
<Typography variant="body2" sx={{ display: "flex" }}>
|
||||
{getAugsLeft(props.faction, props.player)} Augmentations left
|
||||
</Typography>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
</Box>
|
||||
|
||||
{props.joined && (
|
||||
<Box display="grid" sx={{ alignItems: "center", justifyItems: "left", gridAutoFlow: "row" }}>
|
||||
<Typography sx={{ color: Settings.theme.rep }}>
|
||||
{numeralWrapper.formatFavor(props.faction.favor)} favor
|
||||
</Typography>
|
||||
<Typography sx={{ color: Settings.theme.rep }}>
|
||||
{numeralWrapper.formatReputation(props.faction.playerReputation)} rep
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
const theme = useTheme();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
@ -35,99 +205,90 @@ export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
});
|
||||
}, []);
|
||||
|
||||
function openFaction(faction: Faction): void {
|
||||
props.router.toFaction(faction);
|
||||
}
|
||||
|
||||
function openFactionAugPage(faction: Faction): void {
|
||||
props.router.toFaction(faction, true);
|
||||
}
|
||||
|
||||
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, faction: string): void {
|
||||
if (!event.isTrusted) return;
|
||||
joinFaction(Factions[faction]);
|
||||
setRerender((x) => !x);
|
||||
}
|
||||
|
||||
const getAugsLeft = (faction: Faction, player: IPlayer): number => {
|
||||
const augs = getFactionAugmentationsFiltered(player, faction);
|
||||
|
||||
return augs.filter((augmentation: string) => !player.hasAugmentation(augmentation)).length;
|
||||
};
|
||||
|
||||
const allFactions = Object.values(FactionNames).map((faction) => faction as string);
|
||||
const allJoinedFactions = props.player.factions.slice(0);
|
||||
const allJoinedFactions = [...props.player.factions];
|
||||
allJoinedFactions.sort((a, b) => allFactions.indexOf(a) - allFactions.indexOf(b));
|
||||
const invitations = props.player.factionInvitations;
|
||||
|
||||
return (
|
||||
<Container disableGutters maxWidth="md" sx={{ mx: 0, mb: 10 }}>
|
||||
<Typography variant="h4">Factions</Typography>
|
||||
<Typography mb={4}>
|
||||
Throughout the game you may receive invitations from factions. There are many different factions, and each
|
||||
faction has different criteria for determining its potential members. Joining a faction and furthering its cause
|
||||
is crucial to progressing in the game and unlocking endgame content.
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
|
||||
<Typography variant="h4">
|
||||
Factions
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Throughout the game you may receive invitations from factions. There are many different factions, and each
|
||||
faction has different criteria for determining its potential members. Joining a faction and furthering its
|
||||
cause is crucial to progressing in the game and unlocking endgame content.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Info sx={{ ml: 1, mb: 0 }} color="info" />
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h5" color="primary" mt={2} mb={1}>
|
||||
Factions you have joined:
|
||||
</Typography>
|
||||
{(allJoinedFactions.length > 0 && (
|
||||
<Paper sx={{ my: 1, p: 1, pb: 0, display: "inline-block" }}>
|
||||
<Table padding="none" style={{ width: "fit-content" }}>
|
||||
<TableBody>
|
||||
{allJoinedFactions.map((faction: string) => (
|
||||
<TableRow key={faction}>
|
||||
<TableCell>
|
||||
<Typography noWrap mb={1}>
|
||||
{faction}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Box ml={1} mb={1}>
|
||||
<Button onClick={() => openFaction(Factions[faction])}>Details</Button>
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Box ml={1} mb={1}>
|
||||
<Button sx={{ width: "100%" }} onClick={() => openFactionAugPage(Factions[faction])}>
|
||||
Augmentations Left: {getAugsLeft(Factions[faction], props.player)}
|
||||
</Button>
|
||||
</Box>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
)) || <Typography>You haven't joined any factions.</Typography>}
|
||||
<Typography variant="h5" color="primary" mt={4} mb={1}>
|
||||
Outstanding Faction Invitations
|
||||
</Typography>
|
||||
<Typography mb={1}>
|
||||
Factions you have been invited to. You can accept these faction invitations at any time:
|
||||
</Typography>
|
||||
{(props.player.factionInvitations.length > 0 && (
|
||||
<Paper sx={{ my: 1, mb: 4, p: 1, pb: 0, display: "inline-block" }}>
|
||||
<Table padding="none">
|
||||
<TableBody>
|
||||
{props.player.factionInvitations.map((faction: string) => (
|
||||
<TableRow key={faction}>
|
||||
<TableCell>
|
||||
<Typography noWrap mb={1}>
|
||||
{faction}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Box ml={1} mb={1}>
|
||||
<Button onClick={(e) => acceptInvitation(e, faction)}>Join!</Button>
|
||||
</Box>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
)) || <Typography>You have no outstanding faction invites.</Typography>}
|
||||
<Box
|
||||
display="grid"
|
||||
sx={{
|
||||
gap: 1,
|
||||
gridTemplateColumns: (invitations.length > 0 ? "1fr " : "") + "2fr",
|
||||
[theme.breakpoints.down("lg")]: { gridTemplateColumns: "1fr", "& > span:nth-child(1)": { order: 1 } },
|
||||
gridTemplateRows: "minmax(0, 1fr)",
|
||||
"& > span > .MuiBox-root": {
|
||||
display: "grid",
|
||||
gridAutoRows: "70px",
|
||||
gap: 1,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{invitations.length > 0 && (
|
||||
<span>
|
||||
<Typography variant="h5" color="primary">
|
||||
Faction Invitations
|
||||
</Typography>
|
||||
<Box>
|
||||
{invitations.map((facName) => {
|
||||
if (!Factions.hasOwnProperty(facName)) return null;
|
||||
return (
|
||||
<FactionElement
|
||||
key={facName}
|
||||
faction={Factions[facName]}
|
||||
player={props.player}
|
||||
router={props.router}
|
||||
joined={false}
|
||||
rerender={rerender}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</span>
|
||||
)}
|
||||
|
||||
<span>
|
||||
<Typography variant="h5" color="primary">
|
||||
Your Factions
|
||||
</Typography>
|
||||
<Box>
|
||||
{allJoinedFactions.length > 0 ? (
|
||||
allJoinedFactions.map((facName) => {
|
||||
if (!Factions.hasOwnProperty(facName)) return null;
|
||||
return (
|
||||
<FactionElement
|
||||
key={facName}
|
||||
faction={Factions[facName]}
|
||||
player={props.player}
|
||||
router={props.router}
|
||||
joined={true}
|
||||
rerender={rerender}
|
||||
/>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Typography>You have not yet joined any Factions.</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</span>
|
||||
</Box>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
<>
|
||||
<OptionsSlider
|
||||
label=".script exec time (ms)"
|
||||
value={execTime}
|
||||
initialValue={execTime}
|
||||
callback={handleExecTimeChange}
|
||||
step={1}
|
||||
min={5}
|
||||
@ -84,7 +84,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Recently killed scripts size"
|
||||
value={recentScriptsSize}
|
||||
initialValue={recentScriptsSize}
|
||||
callback={handleRecentScriptsSizeChange}
|
||||
step={25}
|
||||
min={0}
|
||||
@ -98,7 +98,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Netscript log size"
|
||||
value={logSize}
|
||||
initialValue={logSize}
|
||||
callback={handleLogSizeChange}
|
||||
step={20}
|
||||
min={20}
|
||||
@ -112,7 +112,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Netscript port size"
|
||||
value={portSize}
|
||||
initialValue={portSize}
|
||||
callback={handlePortSizeChange}
|
||||
step={1}
|
||||
min={20}
|
||||
@ -126,7 +126,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Terminal capacity"
|
||||
value={terminalSize}
|
||||
initialValue={terminalSize}
|
||||
callback={handleTerminalSizeChange}
|
||||
step={50}
|
||||
min={50}
|
||||
@ -141,7 +141,7 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
/>
|
||||
<OptionsSlider
|
||||
label="Autosave interval (s)"
|
||||
value={autosaveInterval}
|
||||
initialValue={autosaveInterval}
|
||||
callback={handleAutosaveIntervalChange}
|
||||
step={30}
|
||||
min={0}
|
||||
@ -179,6 +179,12 @@ export const CurrentOptionsPage = (props: IProps): React.ReactElement => {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<OptionSwitch
|
||||
checked={Settings.InfinityLoopSafety}
|
||||
onChange={(newValue) => (Settings.InfinityLoopSafety = newValue)}
|
||||
text="Script infinite loop safety net"
|
||||
tooltip={<>If this is set the game will attempt to automatically kill scripts stuck in infinite loops.</>}
|
||||
/>
|
||||
</GameOptionsPage>
|
||||
),
|
||||
[GameOptionsTab.INTERFACE]: (
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Slider, Tooltip, Typography, Box } from "@mui/material";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
interface IProps {
|
||||
value: any;
|
||||
initialValue: any;
|
||||
callback: (event: any, newValue: number | number[]) => void;
|
||||
step: number;
|
||||
min: number;
|
||||
@ -13,14 +13,21 @@ interface IProps {
|
||||
}
|
||||
|
||||
export const OptionsSlider = (props: IProps): React.ReactElement => {
|
||||
const [value, setValue] = useState(props.initialValue);
|
||||
|
||||
const onChange = (_evt: Event, newValue: number | Array<number>): void => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Tooltip title={<Typography>{props.tooltip}</Typography>}>
|
||||
<Typography>{props.label}</Typography>
|
||||
</Tooltip>
|
||||
<Slider
|
||||
value={props.value}
|
||||
onChange={props.callback}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onChangeCommitted={props.callback}
|
||||
step={props.step}
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
|
@ -85,9 +85,15 @@ export function TerritorySubpage(): React.ReactElement {
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)" }}>
|
||||
{gangNames.map((name) => (
|
||||
<OtherGangTerritory key={name} name={name} />
|
||||
))}
|
||||
{gangNames
|
||||
.sort((a, b) => {
|
||||
if (AllGangs[a].territory <= 0 && AllGangs[b].territory > 0) return 1;
|
||||
if (AllGangs[a].territory > 0 && AllGangs[b].territory <= 0) return -1;
|
||||
return 0;
|
||||
})
|
||||
.map((name) => (
|
||||
<OtherGangTerritory key={name} name={name} />
|
||||
))}
|
||||
</Box>
|
||||
<TerritoryInfoModal open={infoOpen} onClose={() => setInfoOpen(false)} />
|
||||
</Container>
|
||||
@ -114,14 +120,16 @@ function OtherGangTerritory(props: ITerritoryProps): React.ReactElement {
|
||||
const playerPower = AllGangs[gang.facName].power;
|
||||
const power = AllGangs[props.name].power;
|
||||
const clashVictoryChance = playerPower / (power + playerPower);
|
||||
const territory = AllGangs[props.name].territory;
|
||||
const opacity = territory ? 1 : 0.75;
|
||||
return (
|
||||
<Box component={Paper} sx={{ p: 1 }}>
|
||||
<Box component={Paper} sx={{ p: 1, opacity }}>
|
||||
<Typography variant="h6" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
{props.name}
|
||||
</Typography>
|
||||
<Typography>
|
||||
<b>Power:</b> {formatNumber(power, 3)} <br />
|
||||
<b>Territory:</b> {formatTerritory(AllGangs[props.name].territory)}% <br />
|
||||
<b>Territory:</b> {formatTerritory(territory)}% <br />
|
||||
<b>Clash Win Chance:</b> {numeralWrapper.formatPercentage(clashVictoryChance, 3)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
@ -36,7 +36,7 @@ export function calculateTradeInformationRepReward(
|
||||
30 *
|
||||
levelBonus *
|
||||
(player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 1.5 : 1) *
|
||||
BitNodeMultipliers.InfiltrationMoney
|
||||
BitNodeMultipliers.InfiltrationRep
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,13 @@ export function BackwardGame(props: IMinigameProps): React.ReactElement {
|
||||
const [guess, setGuess] = useState("");
|
||||
const hasAugment = Player.hasAugmentation(AugmentationNames.ChaosOfDionysus, true);
|
||||
|
||||
function ignorableKeyboardEvent(event: KeyboardEvent): boolean {
|
||||
return event.key === KEY.BACKSPACE || (event.shiftKey && event.key === "Shift") || event.ctrlKey || event.altKey;
|
||||
}
|
||||
|
||||
function press(this: Document, event: KeyboardEvent): void {
|
||||
event.preventDefault();
|
||||
if (event.key === KEY.BACKSPACE) return;
|
||||
if (ignorableKeyboardEvent(event)) return;
|
||||
const nextGuess = guess + event.key.toUpperCase();
|
||||
if (!answer.startsWith(nextGuess)) props.onFailure();
|
||||
else if (answer === nextGuess) props.onSuccess();
|
||||
|
@ -2,11 +2,11 @@
|
||||
* Location and traveling-related helper functions.
|
||||
* Mostly used for UI
|
||||
*/
|
||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { AddToAllServers, createUniqueRandomIp } from "../Server/AllServers";
|
||||
import { safetlyCreateUniqueServer } from "../Server/ServerHelpers";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
|
||||
@ -25,19 +25,14 @@ export function purchaseTorRouter(p: IPlayer): void {
|
||||
}
|
||||
p.loseMoney(CONSTANTS.TorRouterCost, "other");
|
||||
|
||||
const darkweb = safetlyCreateUniqueServer({
|
||||
ip: createUniqueRandomIp(),
|
||||
hostname: "darkweb",
|
||||
organizationName: "",
|
||||
isConnectedTo: false,
|
||||
adminRights: false,
|
||||
purchasedByPlayer: false,
|
||||
maxRam: 1,
|
||||
});
|
||||
AddToAllServers(darkweb);
|
||||
const darkweb = GetServer(SpecialServers.DarkWeb);
|
||||
if (!darkweb) {
|
||||
throw new Error("Dark web is not a server.");
|
||||
}
|
||||
|
||||
p.getHomeComputer().serversOnNetwork.push(darkweb.hostname);
|
||||
darkweb.serversOnNetwork.push(p.getHomeComputer().hostname);
|
||||
console.log(darkweb);
|
||||
dialogBoxCreate(
|
||||
"You have purchased a TOR router!<br>" +
|
||||
"You now have access to the dark web from your home computer.<br>" +
|
||||
|
@ -32,7 +32,7 @@ export function RamButton(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
const bnMult = BitNodeMultipliers.HomeComputerRamCost === 1 ? "" : `\\cdot ${BitNodeMultipliers.HomeComputerRamCost}`;
|
||||
console.log(BitNodeMultipliers.HomeComputerRamCost);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
|
@ -317,7 +317,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return renderGrafting();
|
||||
}
|
||||
case LocationName.Sector12CityHall: {
|
||||
return (BitNodeMultipliers.CorporationSoftCap < 0.15 && <></>) || <CreateCorporation />;
|
||||
return (BitNodeMultipliers.CorporationSoftcap < 0.15 && <></>) || <CreateCorporation />;
|
||||
}
|
||||
case LocationName.Sector12NSA: {
|
||||
return renderBladeburner();
|
||||
|
@ -5,6 +5,8 @@ import type { WorkerScript } from "./WorkerScript";
|
||||
import { makeRuntimeRejectMsg } from "../NetscriptEvaluator";
|
||||
import { Player } from "../Player";
|
||||
import { CityName } from "src/Locations/data/CityNames";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
|
||||
type ExternalFunction = (...args: any[]) => any;
|
||||
type ExternalAPI = {
|
||||
@ -91,8 +93,14 @@ function wrapFunction(
|
||||
getValidPort: (port: any) => helpers.getValidPort(functionPath, port),
|
||||
},
|
||||
};
|
||||
const safetyEnabled = Settings.InfinityLoopSafety;
|
||||
function wrappedFunction(...args: unknown[]): unknown {
|
||||
helpers.updateDynamicRam(ctx.function, getRamCost(Player, ...tree, ctx.function));
|
||||
if (safetyEnabled) workerScript.infiniteLoopSafetyCounter++;
|
||||
if (workerScript.infiniteLoopSafetyCounter > CONSTANTS.InfiniteLoopLimit)
|
||||
throw new Error(
|
||||
`Infinite loop without sleep detected. ${CONSTANTS.InfiniteLoopLimit} ns functions were called without sleep. This will cause your UI to hang.`,
|
||||
);
|
||||
return func(ctx)(...args);
|
||||
}
|
||||
const parent = getNestedProperty(wrappedAPI, ...tree);
|
||||
|
@ -51,6 +51,7 @@ export const RamCostConstants: IMap<number> = {
|
||||
ScriptCodingContractBaseRamCost: 10,
|
||||
ScriptSleeveBaseRamCost: 4,
|
||||
ScriptGetOwnedSourceFiles: 5,
|
||||
ScriptClearTerminalCost: 0.2,
|
||||
|
||||
ScriptSingularityFn1RamCost: 2,
|
||||
ScriptSingularityFn2RamCost: 3,
|
||||
@ -359,6 +360,7 @@ export const RamCosts: IMap<any> = {
|
||||
enableLog: 0,
|
||||
isLogEnabled: 0,
|
||||
getScriptLogs: 0,
|
||||
clearTerminal: RamCostConstants.ScriptClearTerminalCost,
|
||||
nuke: RamCostConstants.ScriptPortProgramRamCost,
|
||||
brutessh: RamCostConstants.ScriptPortProgramRamCost,
|
||||
ftpcrack: RamCostConstants.ScriptPortProgramRamCost,
|
||||
|
@ -111,6 +111,11 @@ export class WorkerScript {
|
||||
*/
|
||||
atExit: any;
|
||||
|
||||
/**
|
||||
* Once this counter reaches it's limit the script crashes. It is reset when a promise completes.
|
||||
*/
|
||||
infiniteLoopSafetyCounter = 0;
|
||||
|
||||
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => any) {
|
||||
this.name = runningScriptObj.filename;
|
||||
this.hostname = runningScriptObj.server;
|
||||
|
@ -14,6 +14,7 @@ export function netscriptDelay(time: number, workerScript: WorkerScript): Promis
|
||||
workerScript.delay = null;
|
||||
workerScript.delayReject = undefined;
|
||||
|
||||
workerScript.infiniteLoopSafetyCounter = 0;
|
||||
if (workerScript.env.stopFlag) reject(new ScriptDeath(workerScript));
|
||||
else resolve();
|
||||
}, time);
|
||||
|
@ -55,7 +55,7 @@ import { makeRuntimeRejectMsg, netscriptDelay, resolveNetscriptRequestedThreads
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { convertTimeMsToTimeElapsedString } from "./utils/StringHelperFunctions";
|
||||
|
||||
import { LogBoxEvents } from "./ui/React/LogBoxManager";
|
||||
import { LogBoxEvents, LogBoxCloserEvents } from "./ui/React/LogBoxManager";
|
||||
import { arrayToString } from "./utils/helpers/arrayToString";
|
||||
import { isString } from "./utils/helpers/isString";
|
||||
|
||||
@ -82,6 +82,7 @@ import {
|
||||
Gang as IGang,
|
||||
Bladeburner as IBladeburner,
|
||||
Stanek as IStanek,
|
||||
Sleeve as ISleeve,
|
||||
Infiltration as IInfiltration,
|
||||
RunningScript as IRunningScript,
|
||||
RecentScript as IRecentScript,
|
||||
@ -93,6 +94,12 @@ import {
|
||||
BitNodeMultipliers as IBNMults,
|
||||
Server as IServerDef,
|
||||
RunningScript as IRunningScriptDef,
|
||||
Grafting as IGrafting,
|
||||
UserInterface as IUserInterface,
|
||||
TIX as ITIX,
|
||||
Corporation as ICorporation,
|
||||
CodingContract as ICodingContract,
|
||||
Hacknet as IHacknet,
|
||||
// ToastVariant,
|
||||
} from "./ScriptEditor/NetscriptDefinitions";
|
||||
import { NetscriptSingularity } from "./NetscriptFunctions/Singularity";
|
||||
@ -360,7 +367,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
};
|
||||
|
||||
const hack = function (
|
||||
const hack = async function (
|
||||
hostname: string,
|
||||
manual: boolean,
|
||||
{ threads: requestedThreads, stock }: any = {},
|
||||
@ -524,23 +531,35 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
},
|
||||
};
|
||||
|
||||
const gang = NetscriptGang(Player, workerScript, helper);
|
||||
const sleeve = NetscriptSleeve(Player, workerScript, helper);
|
||||
const extra = NetscriptExtra(Player, workerScript, helper);
|
||||
const hacknet = NetscriptHacknet(Player, workerScript, helper);
|
||||
const formulas = NetscriptFormulas(Player, workerScript, helper);
|
||||
|
||||
const gang = wrapAPI(helper, {}, workerScript, NetscriptGang(Player, workerScript), "gang").gang as unknown as IGang;
|
||||
const sleeve = wrapAPI(helper, {}, workerScript, NetscriptSleeve(Player), "sleeve").sleeve as unknown as ISleeve;
|
||||
const hacknet = wrapAPI(helper, {}, workerScript, NetscriptHacknet(Player, workerScript), "hacknet")
|
||||
.hacknet as unknown as IHacknet;
|
||||
const bladeburner = wrapAPI(helper, {}, workerScript, NetscriptBladeburner(Player, workerScript), "bladeburner")
|
||||
.bladeburner as unknown as IBladeburner;
|
||||
const codingcontract = wrapAPI(
|
||||
helper,
|
||||
{},
|
||||
workerScript,
|
||||
NetscriptCodingContract(Player, workerScript),
|
||||
"codingcontract",
|
||||
).codingcontract as unknown as ICodingContract;
|
||||
const infiltration = wrapAPI(helper, {}, workerScript, NetscriptInfiltration(Player), "infiltration")
|
||||
.infiltration as unknown as IInfiltration;
|
||||
const stanek = wrapAPI(helper, {}, workerScript, NetscriptStanek(Player, workerScript, helper), "stanek")
|
||||
.stanek as unknown as IStanek;
|
||||
const bladeburner = NetscriptBladeburner(Player, workerScript, helper);
|
||||
const codingcontract = NetscriptCodingContract(Player, workerScript, helper);
|
||||
const corporation = NetscriptCorporation(Player, workerScript, helper);
|
||||
const formulas = NetscriptFormulas(Player, workerScript, helper);
|
||||
const corporation = wrapAPI(helper, {}, workerScript, NetscriptCorporation(Player, workerScript), "corporation")
|
||||
.corporation as unknown as ICorporation;
|
||||
const singularity = wrapAPI(helper, {}, workerScript, NetscriptSingularity(Player, workerScript), "singularity")
|
||||
.singularity as unknown as ISingularity;
|
||||
const stockmarket = NetscriptStockMarket(Player, workerScript, helper);
|
||||
const ui = NetscriptUserInterface(Player, workerScript, helper);
|
||||
const grafting = NetscriptGrafting(Player, workerScript, helper);
|
||||
const stockmarket = wrapAPI(helper, {}, workerScript, NetscriptStockMarket(Player, workerScript), "stock")
|
||||
.stock as unknown as ITIX;
|
||||
const ui = wrapAPI(helper, {}, workerScript, NetscriptUserInterface(), "ui").ui as unknown as IUserInterface;
|
||||
const grafting = wrapAPI(helper, {}, workerScript, NetscriptGrafting(Player), "grafting")
|
||||
.grafting as unknown as IGrafting;
|
||||
|
||||
const base: INS = {
|
||||
...singularity,
|
||||
@ -988,6 +1007,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
LogBoxEvents.emit(runningScriptObj);
|
||||
},
|
||||
closeTail: function (_pid: unknown = workerScript.scriptRef.pid): void {
|
||||
updateDynamicRam("closeTail", getRamCost(Player, "closeTail"));
|
||||
const pid = helper.number("closeTail", "pid", _pid);
|
||||
//Emit an event to tell the game to close the tail window if it exists
|
||||
LogBoxCloserEvents.emit(pid);
|
||||
},
|
||||
nuke: function (_hostname: unknown): boolean {
|
||||
updateDynamicRam("nuke", getRamCost(Player, "nuke"));
|
||||
const hostname = helper.string("tail", "hostname", _hostname);
|
||||
|
@ -1,18 +1,13 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "../Bladeburner/Bladeburner";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { Bladeburner as INetscriptBladeburner, BladeburnerCurAction } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { IAction } from "src/Bladeburner/IAction";
|
||||
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||
|
||||
export function NetscriptBladeburner(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): INetscriptBladeburner {
|
||||
const checkBladeburnerAccess = function (func: string, skipjoined = false): void {
|
||||
export function NetscriptBladeburner(player: IPlayer, workerScript: WorkerScript): InternalAPI<INetscriptBladeburner> {
|
||||
const checkBladeburnerAccess = function (ctx: NetscriptContext, skipjoined = false): void {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
const apiAccess =
|
||||
@ -22,367 +17,368 @@ export function NetscriptBladeburner(
|
||||
});
|
||||
if (!apiAccess) {
|
||||
const apiDenied = `You do not currently have access to the Bladeburner API. You must either be in BitNode-7 or have Source-File 7.`;
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, apiDenied);
|
||||
throw ctx.makeRuntimeErrorMsg(apiDenied);
|
||||
}
|
||||
if (!skipjoined) {
|
||||
const bladeburnerAccess = bladeburner instanceof Bladeburner;
|
||||
if (!bladeburnerAccess) {
|
||||
const bladeburnerDenied = `You must be a member of the Bladeburner division to use this API.`;
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, bladeburnerDenied);
|
||||
throw ctx.makeRuntimeErrorMsg(bladeburnerDenied);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const checkBladeburnerCity = function (func: string, city: string): void {
|
||||
const checkBladeburnerCity = function (ctx: NetscriptContext, city: string): void {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
if (!bladeburner.cities.hasOwnProperty(city)) {
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid city: ${city}`);
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid city: ${city}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getBladeburnerActionObject = function (func: string, type: string, name: string): IAction {
|
||||
const getBladeburnerActionObject = function (ctx: NetscriptContext, type: string, name: string): IAction {
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Must have joined bladeburner");
|
||||
const actionId = bladeburner.getActionIdFromTypeAndName(type, name);
|
||||
if (!actionId) {
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid action type='${type}', name='${name}'`);
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`);
|
||||
}
|
||||
const actionObj = bladeburner.getActionObject(actionId);
|
||||
if (!actionObj) {
|
||||
throw helper.makeRuntimeErrorMsg(`bladeburner.${func}`, `Invalid action type='${type}', name='${name}'`);
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid action type='${type}', name='${name}'`);
|
||||
}
|
||||
|
||||
return actionObj;
|
||||
};
|
||||
|
||||
const updateRam = (funcName: string): void =>
|
||||
helper.updateDynamicRam(funcName, getRamCost(player, "bladeburner", funcName));
|
||||
|
||||
return {
|
||||
getContractNames: function (): string[] {
|
||||
updateRam("getContractNames");
|
||||
checkBladeburnerAccess("getContractNames");
|
||||
getContractNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getContractNamesNetscriptFn();
|
||||
},
|
||||
getOperationNames: function (): string[] {
|
||||
updateRam("getOperationNames");
|
||||
checkBladeburnerAccess("getOperationNames");
|
||||
getOperationNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getOperationNamesNetscriptFn();
|
||||
},
|
||||
getBlackOpNames: function (): string[] {
|
||||
updateRam("getBlackOpNames");
|
||||
checkBladeburnerAccess("getBlackOpNames");
|
||||
getBlackOpNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getBlackOpNamesNetscriptFn();
|
||||
},
|
||||
getBlackOpRank: function (_blackOpName: unknown): number {
|
||||
updateRam("getBlackOpRank");
|
||||
const blackOpName = helper.string("getBlackOpRank", "blackOpName", _blackOpName);
|
||||
checkBladeburnerAccess("getBlackOpRank");
|
||||
const action: any = getBladeburnerActionObject("getBlackOpRank", "blackops", blackOpName);
|
||||
return action.reqdRank;
|
||||
},
|
||||
getGeneralActionNames: function (): string[] {
|
||||
updateRam("getGeneralActionNames");
|
||||
checkBladeburnerAccess("getGeneralActionNames");
|
||||
getBlackOpRank:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_blackOpName: unknown): number => {
|
||||
const blackOpName = ctx.helper.string("blackOpName", _blackOpName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action: any = getBladeburnerActionObject(ctx, "blackops", blackOpName);
|
||||
return action.reqdRank;
|
||||
},
|
||||
getGeneralActionNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getGeneralActionNamesNetscriptFn();
|
||||
},
|
||||
getSkillNames: function (): string[] {
|
||||
updateRam("getSkillNames");
|
||||
checkBladeburnerAccess("getSkillNames");
|
||||
getSkillNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getSkillNamesNetscriptFn();
|
||||
},
|
||||
startAction: function (_type: unknown, _name: unknown): boolean {
|
||||
updateRam("startAction");
|
||||
const type = helper.string("startAction", "type", _type);
|
||||
const name = helper.string("startAction", "name", _name);
|
||||
checkBladeburnerAccess("startAction");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.startActionNetscriptFn(player, type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.startAction", e);
|
||||
}
|
||||
},
|
||||
stopBladeburnerAction: function (): void {
|
||||
updateRam("stopBladeburnerAction");
|
||||
checkBladeburnerAccess("stopBladeburnerAction");
|
||||
startAction:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): boolean => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.startActionNetscriptFn(player, type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
stopBladeburnerAction: (ctx: NetscriptContext) => (): void => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.resetAction();
|
||||
},
|
||||
getCurrentAction: function (): BladeburnerCurAction {
|
||||
updateRam("getCurrentAction");
|
||||
checkBladeburnerAccess("getCurrentAction");
|
||||
getCurrentAction: (ctx: NetscriptContext) => (): BladeburnerCurAction => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.getTypeAndNameFromActionId(bladeburner.action);
|
||||
},
|
||||
getActionTime: function (_type: unknown, _name: unknown): number {
|
||||
updateRam("getActionTime");
|
||||
const type = helper.string("getActionTime", "type", _type);
|
||||
const name = helper.string("getActionTime", "name", _name);
|
||||
checkBladeburnerAccess("getActionTime");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
const time = bladeburner.getActionTimeNetscriptFn(player, type, name);
|
||||
if (typeof time === "string") {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
workerScript.log("bladeburner.getActionTime", () => errorLogText);
|
||||
return -1;
|
||||
} else {
|
||||
return time;
|
||||
getActionTime:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
const time = bladeburner.getActionTimeNetscriptFn(player, type, name);
|
||||
if (typeof time === "string") {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
ctx.log(() => errorLogText);
|
||||
return -1;
|
||||
} else {
|
||||
return time;
|
||||
}
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getActionTime", e);
|
||||
}
|
||||
},
|
||||
getActionEstimatedSuccessChance: function (_type: unknown, _name: unknown): [number, number] {
|
||||
updateRam("getActionEstimatedSuccessChance");
|
||||
const type = helper.string("getActionEstimatedSuccessChance", "type", _type);
|
||||
const name = helper.string("getActionEstimatedSuccessChance", "name", _name);
|
||||
checkBladeburnerAccess("getActionEstimatedSuccessChance");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name);
|
||||
if (typeof chance === "string") {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
workerScript.log("bladeburner.getActionTime", () => errorLogText);
|
||||
return [-1, -1];
|
||||
} else {
|
||||
return chance;
|
||||
},
|
||||
getActionEstimatedSuccessChance:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): [number, number] => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name);
|
||||
if (typeof chance === "string") {
|
||||
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
|
||||
ctx.log(() => errorLogText);
|
||||
return [-1, -1];
|
||||
} else {
|
||||
return chance;
|
||||
}
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
getActionRepGain:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown, _level: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
const level = ctx.helper.number("level", _level);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action = getBladeburnerActionObject(ctx, type, name);
|
||||
let rewardMultiplier;
|
||||
if (level == null || isNaN(level)) {
|
||||
rewardMultiplier = Math.pow(action.rewardFac, action.level - 1);
|
||||
} else {
|
||||
rewardMultiplier = Math.pow(action.rewardFac, level - 1);
|
||||
}
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getActionEstimatedSuccessChance", e);
|
||||
}
|
||||
},
|
||||
getActionRepGain: function (_type: unknown, _name: unknown, _level: unknown): number {
|
||||
updateRam("getActionRepGain");
|
||||
const type = helper.string("getActionRepGain", "type", _type);
|
||||
const name = helper.string("getActionRepGain", "name", _name);
|
||||
const level = helper.number("getActionRepGain", "level", _level);
|
||||
checkBladeburnerAccess("getActionRepGain");
|
||||
const action = getBladeburnerActionObject("getActionRepGain", type, name);
|
||||
let rewardMultiplier;
|
||||
if (level == null || isNaN(level)) {
|
||||
rewardMultiplier = Math.pow(action.rewardFac, action.level - 1);
|
||||
} else {
|
||||
rewardMultiplier = Math.pow(action.rewardFac, level - 1);
|
||||
}
|
||||
|
||||
return action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank;
|
||||
},
|
||||
getActionCountRemaining: function (_type: unknown, _name: unknown): number {
|
||||
updateRam("getActionCountRemaining");
|
||||
const type = helper.string("getActionCountRemaining", "type", _type);
|
||||
const name = helper.string("getActionCountRemaining", "name", _name);
|
||||
checkBladeburnerAccess("getActionCountRemaining");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getActionCountRemainingNetscriptFn(type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getActionCountRemaining", e);
|
||||
}
|
||||
},
|
||||
getActionMaxLevel: function (_type: unknown, _name: unknown): number {
|
||||
updateRam("getActionMaxLevel");
|
||||
const type = helper.string("getActionMaxLevel", "type", _type);
|
||||
const name = helper.string("getActionMaxLevel", "name", _name);
|
||||
checkBladeburnerAccess("getActionMaxLevel");
|
||||
const action = getBladeburnerActionObject("getActionMaxLevel", type, name);
|
||||
return action.maxLevel;
|
||||
},
|
||||
getActionCurrentLevel: function (_type: unknown, _name: unknown): number {
|
||||
updateRam("getActionCurrentLevel");
|
||||
const type = helper.string("getActionCurrentLevel", "type", _type);
|
||||
const name = helper.string("getActionCurrentLevel", "name", _name);
|
||||
checkBladeburnerAccess("getActionCurrentLevel");
|
||||
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
|
||||
return action.level;
|
||||
},
|
||||
getActionAutolevel: function (_type: unknown, _name: unknown): boolean {
|
||||
updateRam("getActionAutolevel");
|
||||
const type = helper.string("getActionAutolevel", "type", _type);
|
||||
const name = helper.string("getActionAutolevel", "name", _name);
|
||||
checkBladeburnerAccess("getActionAutolevel");
|
||||
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
|
||||
return action.autoLevel;
|
||||
},
|
||||
setActionAutolevel: function (_type: unknown, _name: unknown, _autoLevel: unknown = true): void {
|
||||
updateRam("setActionAutolevel");
|
||||
const type = helper.string("setActionAutolevel", "type", _type);
|
||||
const name = helper.string("setActionAutolevel", "name", _name);
|
||||
const autoLevel = helper.boolean(_autoLevel);
|
||||
checkBladeburnerAccess("setActionAutolevel");
|
||||
const action = getBladeburnerActionObject("setActionAutolevel", type, name);
|
||||
action.autoLevel = autoLevel;
|
||||
},
|
||||
setActionLevel: function (_type: unknown, _name: unknown, _level: unknown = 1): void {
|
||||
updateRam("setActionLevel");
|
||||
const type = helper.string("setActionLevel", "type", _type);
|
||||
const name = helper.string("setActionLevel", "name", _name);
|
||||
const level = helper.number("setActionLevel", "level", _level);
|
||||
checkBladeburnerAccess("setActionLevel");
|
||||
const action = getBladeburnerActionObject("setActionLevel", type, name);
|
||||
if (level < 1 || level > action.maxLevel) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"bladeburner.setActionLevel",
|
||||
`Level must be between 1 and ${action.maxLevel}, is ${level}`,
|
||||
);
|
||||
}
|
||||
action.level = level;
|
||||
},
|
||||
getRank: function (): number {
|
||||
updateRam("getRank");
|
||||
checkBladeburnerAccess("getRank");
|
||||
return action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank;
|
||||
},
|
||||
getActionCountRemaining:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getActionCountRemainingNetscriptFn(type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
getActionMaxLevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action = getBladeburnerActionObject(ctx, type, name);
|
||||
return action.maxLevel;
|
||||
},
|
||||
getActionCurrentLevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action = getBladeburnerActionObject(ctx, type, name);
|
||||
return action.level;
|
||||
},
|
||||
getActionAutolevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): boolean => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action = getBladeburnerActionObject(ctx, type, name);
|
||||
return action.autoLevel;
|
||||
},
|
||||
setActionAutolevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown, _autoLevel: unknown = true): void => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
const autoLevel = ctx.helper.boolean(_autoLevel);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action = getBladeburnerActionObject(ctx, type, name);
|
||||
action.autoLevel = autoLevel;
|
||||
},
|
||||
setActionLevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown, _level: unknown = 1): void => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
const level = ctx.helper.number("level", _level);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const action = getBladeburnerActionObject(ctx, type, name);
|
||||
if (level < 1 || level > action.maxLevel) {
|
||||
ctx.helper.makeRuntimeErrorMsg(`Level must be between 1 and ${action.maxLevel}, is ${level}`);
|
||||
}
|
||||
action.level = level;
|
||||
},
|
||||
getRank: (ctx: NetscriptContext) => (): number => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.rank;
|
||||
},
|
||||
getSkillPoints: function (): number {
|
||||
updateRam("getSkillPoints");
|
||||
checkBladeburnerAccess("getSkillPoints");
|
||||
getSkillPoints: (ctx: NetscriptContext) => (): number => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.skillPoints;
|
||||
},
|
||||
getSkillLevel: function (_skillName: unknown): number {
|
||||
updateRam("getSkillLevel");
|
||||
const skillName = helper.string("getSkillLevel", "skillName", _skillName);
|
||||
checkBladeburnerAccess("getSkillLevel");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getSkillLevelNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getSkillLevel", e);
|
||||
}
|
||||
},
|
||||
getSkillUpgradeCost: function (_skillName: unknown): number {
|
||||
updateRam("getSkillUpgradeCost");
|
||||
const skillName = helper.string("getSkillUpgradeCost", "skillName", _skillName);
|
||||
checkBladeburnerAccess("getSkillUpgradeCost");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getSkillUpgradeCost", e);
|
||||
}
|
||||
},
|
||||
upgradeSkill: function (_skillName: unknown): boolean {
|
||||
updateRam("upgradeSkill");
|
||||
const skillName = helper.string("upgradeSkill", "skillName", _skillName);
|
||||
checkBladeburnerAccess("upgradeSkill");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.upgradeSkillNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.upgradeSkill", e);
|
||||
}
|
||||
},
|
||||
getTeamSize: function (_type: unknown, _name: unknown): number {
|
||||
updateRam("getTeamSize");
|
||||
const type = helper.string("getTeamSize", "type", _type);
|
||||
const name = helper.string("getTeamSize", "name", _name);
|
||||
checkBladeburnerAccess("getTeamSize");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getTeamSizeNetscriptFn(type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.getTeamSize", e);
|
||||
}
|
||||
},
|
||||
setTeamSize: function (_type: unknown, _name: unknown, _size: unknown): number {
|
||||
updateRam("setTeamSize");
|
||||
const type = helper.string("setTeamSize", "type", _type);
|
||||
const name = helper.string("setTeamSize", "name", _name);
|
||||
const size = helper.number("setTeamSize", "size", _size);
|
||||
checkBladeburnerAccess("setTeamSize");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.setTeamSizeNetscriptFn(type, name, size, workerScript);
|
||||
} catch (e: any) {
|
||||
throw helper.makeRuntimeErrorMsg("bladeburner.setTeamSize", e);
|
||||
}
|
||||
},
|
||||
getCityEstimatedPopulation: function (_cityName: unknown): number {
|
||||
updateRam("getCityEstimatedPopulation");
|
||||
const cityName = helper.string("getCityEstimatedPopulation", "cityName", _cityName);
|
||||
checkBladeburnerAccess("getCityEstimatedPopulation");
|
||||
checkBladeburnerCity("getCityEstimatedPopulation", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].popEst;
|
||||
},
|
||||
getCityCommunities: function (_cityName: unknown): number {
|
||||
updateRam("getCityCommunities");
|
||||
const cityName = helper.string("getCityCommunities", "cityName", _cityName);
|
||||
checkBladeburnerAccess("getCityCommunities");
|
||||
checkBladeburnerCity("getCityCommunities", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].comms;
|
||||
},
|
||||
getCityChaos: function (_cityName: unknown): number {
|
||||
updateRam("getCityChaos");
|
||||
const cityName = helper.string("getCityChaos", "cityName", _cityName);
|
||||
checkBladeburnerAccess("getCityChaos");
|
||||
checkBladeburnerCity("getCityChaos", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].chaos;
|
||||
},
|
||||
getCity: function (): string {
|
||||
updateRam("getCity");
|
||||
checkBladeburnerAccess("getCityChaos");
|
||||
getSkillLevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_skillName: unknown): number => {
|
||||
const skillName = ctx.helper.string("skillName", _skillName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getSkillLevelNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
getSkillUpgradeCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_skillName: unknown): number => {
|
||||
const skillName = ctx.helper.string("skillName", _skillName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
upgradeSkill:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_skillName: unknown): boolean => {
|
||||
const skillName = ctx.helper.string("skillName", _skillName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.upgradeSkillNetscriptFn(skillName, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
getTeamSize:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.getTeamSizeNetscriptFn(type, name, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
setTeamSize:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_type: unknown, _name: unknown, _size: unknown): number => {
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const name = ctx.helper.string("name", _name);
|
||||
const size = ctx.helper.number("size", _size);
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
try {
|
||||
return bladeburner.setTeamSizeNetscriptFn(type, name, size, workerScript);
|
||||
} catch (e: any) {
|
||||
throw ctx.makeRuntimeErrorMsg(e);
|
||||
}
|
||||
},
|
||||
getCityEstimatedPopulation:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_cityName: unknown): number => {
|
||||
const cityName = ctx.helper.string("cityName", _cityName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
checkBladeburnerCity(ctx, cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].popEst;
|
||||
},
|
||||
getCityCommunities:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_cityName: unknown): number => {
|
||||
const cityName = ctx.helper.string("cityName", _cityName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
checkBladeburnerCity(ctx, cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].comms;
|
||||
},
|
||||
getCityChaos:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_cityName: unknown): number => {
|
||||
const cityName = ctx.helper.string("cityName", _cityName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
checkBladeburnerCity(ctx, cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.cities[cityName].chaos;
|
||||
},
|
||||
getCity: (ctx: NetscriptContext) => (): string => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.city;
|
||||
},
|
||||
switchCity: function (_cityName: unknown): boolean {
|
||||
updateRam("switchCity");
|
||||
const cityName = helper.string("switchCity", "cityName", _cityName);
|
||||
checkBladeburnerAccess("switchCity");
|
||||
checkBladeburnerCity("switchCity", cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
bladeburner.city = cityName;
|
||||
return true;
|
||||
},
|
||||
getStamina: function (): [number, number] {
|
||||
updateRam("getStamina");
|
||||
checkBladeburnerAccess("getStamina");
|
||||
switchCity:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_cityName: unknown): boolean => {
|
||||
const cityName = ctx.helper.string("cityName", _cityName);
|
||||
checkBladeburnerAccess(ctx);
|
||||
checkBladeburnerCity(ctx, cityName);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
bladeburner.city = cityName;
|
||||
return true;
|
||||
},
|
||||
getStamina: (ctx: NetscriptContext) => (): [number, number] => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return [bladeburner.stamina, bladeburner.maxStamina];
|
||||
},
|
||||
joinBladeburnerFaction: function (): boolean {
|
||||
updateRam("joinBladeburnerFaction");
|
||||
checkBladeburnerAccess("joinBladeburnerFaction", true);
|
||||
joinBladeburnerFaction: (ctx: NetscriptContext) => (): boolean => {
|
||||
checkBladeburnerAccess(ctx, true);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return bladeburner.joinBladeburnerFactionNetscriptFn(workerScript);
|
||||
},
|
||||
joinBladeburnerDivision: function (): boolean {
|
||||
updateRam("joinBladeburnerDivision");
|
||||
joinBladeburnerDivision: (ctx: NetscriptContext) => (): boolean => {
|
||||
if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) {
|
||||
if (player.bitNodeN === 8) {
|
||||
return false;
|
||||
@ -396,22 +392,18 @@ export function NetscriptBladeburner(
|
||||
player.agility >= 100
|
||||
) {
|
||||
player.bladeburner = new Bladeburner(player);
|
||||
workerScript.log("joinBladeburnerDivision", () => "You have been accepted into the Bladeburner division");
|
||||
ctx.log(() => "You have been accepted into the Bladeburner division");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
workerScript.log(
|
||||
"joinBladeburnerDivision",
|
||||
() => "You do not meet the requirements for joining the Bladeburner division",
|
||||
);
|
||||
ctx.log(() => "You do not meet the requirements for joining the Bladeburner division");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getBonusTime: function (): number {
|
||||
updateRam("getBonusTime");
|
||||
checkBladeburnerAccess("getBonusTime");
|
||||
getBonusTime: (ctx: NetscriptContext) => (): number => {
|
||||
checkBladeburnerAccess(ctx);
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return Math.round(bladeburner.storedCycles / 5) * 1000;
|
||||
|
@ -1,132 +1,124 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { is2DArray } from "../utils/helpers/is2DArray";
|
||||
import { CodingContract } from "../CodingContracts";
|
||||
import { CodingAttemptOptions, CodingContract as ICodingContract } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||
|
||||
export function NetscriptCodingContract(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): ICodingContract {
|
||||
const getCodingContract = function (func: string, hostname: string, filename: string): CodingContract {
|
||||
const server = helper.getServer(hostname, func);
|
||||
export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScript): InternalAPI<ICodingContract> {
|
||||
const getCodingContract = function (
|
||||
ctx: NetscriptContext,
|
||||
func: string,
|
||||
hostname: string,
|
||||
filename: string,
|
||||
): CodingContract {
|
||||
const server = ctx.helper.getServer(hostname);
|
||||
const contract = server.getContract(filename);
|
||||
if (contract == null) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
`codingcontract.${func}`,
|
||||
`Cannot find contract '${filename}' on server '${hostname}'`,
|
||||
);
|
||||
throw ctx.makeRuntimeErrorMsg(`Cannot find contract '${filename}' on server '${hostname}'`);
|
||||
}
|
||||
|
||||
return contract;
|
||||
};
|
||||
|
||||
const updateRam = (funcName: string): void =>
|
||||
helper.updateDynamicRam(funcName, getRamCost(player, "codingcontract", funcName));
|
||||
|
||||
return {
|
||||
attempt: function (
|
||||
answer: any,
|
||||
_filename: unknown,
|
||||
_hostname: unknown = workerScript.hostname,
|
||||
{ returnReward }: CodingAttemptOptions = { returnReward: false },
|
||||
): boolean | string {
|
||||
updateRam("attempt");
|
||||
const filename = helper.string("attempt", "filename", _filename);
|
||||
const hostname = helper.string("attempt", "hostname", _hostname);
|
||||
const contract = getCodingContract("attempt", hostname, filename);
|
||||
attempt:
|
||||
(ctx: NetscriptContext) =>
|
||||
(
|
||||
answer: any,
|
||||
_filename: unknown,
|
||||
_hostname: unknown = workerScript.hostname,
|
||||
{ returnReward }: CodingAttemptOptions = { returnReward: false },
|
||||
): boolean | string => {
|
||||
const filename = ctx.helper.string("filename", _filename);
|
||||
const hostname = ctx.helper.string("hostname", _hostname);
|
||||
const contract = getCodingContract(ctx, "attempt", hostname, filename);
|
||||
|
||||
// Convert answer to string. If the answer is a 2D array, then we have to
|
||||
// manually add brackets for the inner arrays
|
||||
if (is2DArray(answer)) {
|
||||
const answerComponents = [];
|
||||
for (let i = 0; i < answer.length; ++i) {
|
||||
answerComponents.push(["[", answer[i].toString(), "]"].join(""));
|
||||
}
|
||||
|
||||
answer = answerComponents.join(",");
|
||||
} else {
|
||||
answer = String(answer);
|
||||
}
|
||||
|
||||
const creward = contract.reward;
|
||||
if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward");
|
||||
|
||||
const serv = helper.getServer(hostname, "codingcontract.attempt");
|
||||
if (contract.isSolution(answer)) {
|
||||
const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
|
||||
workerScript.log(
|
||||
"codingcontract.attempt",
|
||||
() => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`,
|
||||
);
|
||||
serv.removeContract(filename);
|
||||
return returnReward ? reward : true;
|
||||
} else {
|
||||
++contract.tries;
|
||||
if (contract.tries >= contract.getMaxNumTries()) {
|
||||
workerScript.log(
|
||||
"codingcontract.attempt",
|
||||
() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`,
|
||||
);
|
||||
serv.removeContract(filename);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"codingcontract.attempt",
|
||||
() =>
|
||||
`Coding Contract attempt '${filename}' failed. ${
|
||||
contract.getMaxNumTries() - contract.tries
|
||||
} attempts remaining.`,
|
||||
);
|
||||
}
|
||||
|
||||
return returnReward ? "" : false;
|
||||
}
|
||||
},
|
||||
getContractType: function (_filename: unknown, _hostname: unknown = workerScript.hostname): string {
|
||||
updateRam("getContractType");
|
||||
const filename = helper.string("getContractType", "filename", _filename);
|
||||
const hostname = helper.string("getContractType", "hostname", _hostname);
|
||||
const contract = getCodingContract("getContractType", hostname, filename);
|
||||
return contract.getType();
|
||||
},
|
||||
getData: function (_filename: unknown, _hostname: unknown = workerScript.hostname): any {
|
||||
updateRam("getData");
|
||||
const filename = helper.string("getContractType", "filename", _filename);
|
||||
const hostname = helper.string("getContractType", "hostname", _hostname);
|
||||
const contract = getCodingContract("getData", hostname, filename);
|
||||
const data = contract.getData();
|
||||
if (data.constructor === Array) {
|
||||
// For two dimensional arrays, we have to copy the internal arrays using
|
||||
// slice() as well. As of right now, no contract has arrays that have
|
||||
// more than two dimensions
|
||||
const copy = data.slice();
|
||||
for (let i = 0; i < copy.length; ++i) {
|
||||
if (data[i].constructor === Array) {
|
||||
copy[i] = data[i].slice();
|
||||
// Convert answer to string. If the answer is a 2D array, then we have to
|
||||
// manually add brackets for the inner arrays
|
||||
if (is2DArray(answer)) {
|
||||
const answerComponents = [];
|
||||
for (let i = 0; i < answer.length; ++i) {
|
||||
answerComponents.push(["[", answer[i].toString(), "]"].join(""));
|
||||
}
|
||||
|
||||
answer = answerComponents.join(",");
|
||||
} else {
|
||||
answer = String(answer);
|
||||
}
|
||||
|
||||
return copy;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
getDescription: function (_filename: unknown, _hostname: unknown = workerScript.hostname): string {
|
||||
updateRam("getDescription");
|
||||
const filename = helper.string("getDescription", "filename", _filename);
|
||||
const hostname = helper.string("getDescription", "hostname", _hostname);
|
||||
const contract = getCodingContract("getDescription", hostname, filename);
|
||||
return contract.getDescription();
|
||||
},
|
||||
getNumTriesRemaining: function (_filename: unknown, _hostname: unknown = workerScript.hostname): number {
|
||||
updateRam("getNumTriesRemaining");
|
||||
const filename = helper.string("getNumTriesRemaining", "filename", _filename);
|
||||
const hostname = helper.string("getNumTriesRemaining", "hostname", _hostname);
|
||||
const contract = getCodingContract("getNumTriesRemaining", hostname, filename);
|
||||
return contract.getMaxNumTries() - contract.tries;
|
||||
},
|
||||
const creward = contract.reward;
|
||||
if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward");
|
||||
|
||||
const serv = ctx.helper.getServer(hostname);
|
||||
if (contract.isSolution(answer)) {
|
||||
const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
|
||||
ctx.log(() => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`);
|
||||
serv.removeContract(filename);
|
||||
return returnReward ? reward : true;
|
||||
} else {
|
||||
++contract.tries;
|
||||
if (contract.tries >= contract.getMaxNumTries()) {
|
||||
ctx.log(() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`);
|
||||
serv.removeContract(filename);
|
||||
} else {
|
||||
ctx.log(
|
||||
() =>
|
||||
`Coding Contract attempt '${filename}' failed. ${
|
||||
contract.getMaxNumTries() - contract.tries
|
||||
} attempts remaining.`,
|
||||
);
|
||||
}
|
||||
|
||||
return returnReward ? "" : false;
|
||||
}
|
||||
},
|
||||
getContractType:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => {
|
||||
const filename = ctx.helper.string("filename", _filename);
|
||||
const hostname = ctx.helper.string("hostname", _hostname);
|
||||
const contract = getCodingContract(ctx, "getContractType", hostname, filename);
|
||||
return contract.getType();
|
||||
},
|
||||
getData:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_filename: unknown, _hostname: unknown = workerScript.hostname): any => {
|
||||
const filename = ctx.helper.string("filename", _filename);
|
||||
const hostname = ctx.helper.string("hostname", _hostname);
|
||||
const contract = getCodingContract(ctx, "getData", hostname, filename);
|
||||
const data = contract.getData();
|
||||
if (data.constructor === Array) {
|
||||
// For two dimensional arrays, we have to copy the internal arrays using
|
||||
// slice() as well. As of right now, no contract has arrays that have
|
||||
// more than two dimensions
|
||||
const copy = data.slice();
|
||||
for (let i = 0; i < copy.length; ++i) {
|
||||
if (data[i].constructor === Array) {
|
||||
copy[i] = data[i].slice();
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
getDescription:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => {
|
||||
const filename = ctx.helper.string("filename", _filename);
|
||||
const hostname = ctx.helper.string("hostname", _hostname);
|
||||
const contract = getCodingContract(ctx, "getDescription", hostname, filename);
|
||||
return contract.getDescription();
|
||||
},
|
||||
getNumTriesRemaining:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_filename: unknown, _hostname: unknown = workerScript.hostname): number => {
|
||||
const filename = ctx.helper.string("filename", _filename);
|
||||
const hostname = ctx.helper.string("hostname", _hostname);
|
||||
const contract = getCodingContract(ctx, "getNumTriesRemaining", hostname, filename);
|
||||
return contract.getMaxNumTries() - contract.tries;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,6 @@
|
||||
import { FactionNames } from "../Faction/data/FactionNames";
|
||||
import { GangConstants } from "../Gang/data/Constants";
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { Gang } from "../Gang/Gang";
|
||||
import { AllGangs } from "../Gang/AllGangs";
|
||||
import { GangMemberTasks } from "../Gang/GangMemberTasks";
|
||||
@ -20,63 +18,60 @@ import {
|
||||
EquipmentStats,
|
||||
GangTaskStats,
|
||||
} from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
||||
|
||||
export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IGang {
|
||||
const checkGangApiAccess = function (func: string): void {
|
||||
export function NetscriptGang(player: IPlayer, workerScript: WorkerScript): InternalAPI<IGang> {
|
||||
const checkGangApiAccess = function (ctx: NetscriptContext): void {
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Must have joined gang");
|
||||
const hasAccess = gang instanceof Gang;
|
||||
if (!hasAccess) {
|
||||
throw helper.makeRuntimeErrorMsg(`gang.${func}`, `You do not currently have a Gang`);
|
||||
throw ctx.makeRuntimeErrorMsg(`You do not currently have a Gang`);
|
||||
}
|
||||
};
|
||||
|
||||
const getGangMember = function (func: string, name: string): GangMember {
|
||||
const getGangMember = function (ctx: NetscriptContext, name: string): GangMember {
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Must have joined gang");
|
||||
for (const member of gang.members) if (member.name === name) return member;
|
||||
throw helper.makeRuntimeErrorMsg(`gang.${func}`, `Invalid gang member: '${name}'`);
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid gang member: '${name}'`);
|
||||
};
|
||||
|
||||
const getGangTask = function (func: string, name: string): GangMemberTask {
|
||||
const getGangTask = function (ctx: NetscriptContext, name: string): GangMemberTask {
|
||||
const task = GangMemberTasks[name];
|
||||
if (!task) {
|
||||
throw helper.makeRuntimeErrorMsg(`gang.${func}`, `Invalid task: '${name}'`);
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid task: '${name}'`);
|
||||
}
|
||||
|
||||
return task;
|
||||
};
|
||||
|
||||
const updateRam = (funcName: string): void => helper.updateDynamicRam(funcName, getRamCost(player, "gang", funcName));
|
||||
|
||||
return {
|
||||
createGang: function (_faction: unknown): boolean {
|
||||
updateRam("createGang");
|
||||
const faction = helper.string("createGang", "faction", _faction);
|
||||
// this list is copied from Faction/ui/Root.tsx
|
||||
createGang:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_faction: unknown): boolean => {
|
||||
const faction = ctx.helper.string("faction", _faction);
|
||||
// this list is copied from Faction/ui/Root.tsx
|
||||
|
||||
if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false;
|
||||
if (player.inGang()) return false;
|
||||
if (!player.factions.includes(faction)) return false;
|
||||
if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false;
|
||||
if (player.inGang()) return false;
|
||||
if (!player.factions.includes(faction)) return false;
|
||||
|
||||
const isHacking = faction === FactionNames.NiteSec || faction === FactionNames.TheBlackHand;
|
||||
player.startGang(faction, isHacking);
|
||||
return true;
|
||||
},
|
||||
inGang: function (): boolean {
|
||||
updateRam("inGang");
|
||||
const isHacking = faction === FactionNames.NiteSec || faction === FactionNames.TheBlackHand;
|
||||
player.startGang(faction, isHacking);
|
||||
return true;
|
||||
},
|
||||
inGang: () => (): boolean => {
|
||||
return player.inGang();
|
||||
},
|
||||
getMemberNames: function (): string[] {
|
||||
updateRam("getMemberNames");
|
||||
checkGangApiAccess("getMemberNames");
|
||||
getMemberNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return gang.members.map((member) => member.name);
|
||||
},
|
||||
getGangInformation: function (): GangGenInfo {
|
||||
updateRam("getGangInformation");
|
||||
checkGangApiAccess("getGangInformation");
|
||||
getGangInformation: (ctx: NetscriptContext) => (): GangGenInfo => {
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return {
|
||||
@ -94,9 +89,8 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
|
||||
wantedPenalty: gang.getWantedPenalty(),
|
||||
};
|
||||
},
|
||||
getOtherGangInformation: function (): GangOtherInfo {
|
||||
updateRam("getOtherGangInformation");
|
||||
checkGangApiAccess("getOtherGangInformation");
|
||||
getOtherGangInformation: (ctx: NetscriptContext) => (): GangOtherInfo => {
|
||||
checkGangApiAccess(ctx);
|
||||
const cpy: any = {};
|
||||
for (const gang of Object.keys(AllGangs)) {
|
||||
cpy[gang] = Object.assign({}, AllGangs[gang]);
|
||||
@ -104,242 +98,251 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
|
||||
|
||||
return cpy;
|
||||
},
|
||||
getMemberInformation: function (_memberName: unknown): GangMemberInfo {
|
||||
updateRam("getMemberInformation");
|
||||
const memberName = helper.string("getMemberInformation", "memberName", _memberName);
|
||||
checkGangApiAccess("getMemberInformation");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("getMemberInformation", memberName);
|
||||
return {
|
||||
name: member.name,
|
||||
task: member.task,
|
||||
earnedRespect: member.earnedRespect,
|
||||
hack: member.hack,
|
||||
str: member.str,
|
||||
def: member.def,
|
||||
dex: member.dex,
|
||||
agi: member.agi,
|
||||
cha: member.cha,
|
||||
getMemberInformation:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_memberName: unknown): GangMemberInfo => {
|
||||
const memberName = ctx.helper.string("memberName", _memberName);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember(ctx, memberName);
|
||||
return {
|
||||
name: member.name,
|
||||
task: member.task,
|
||||
earnedRespect: member.earnedRespect,
|
||||
hack: member.hack,
|
||||
str: member.str,
|
||||
def: member.def,
|
||||
dex: member.dex,
|
||||
agi: member.agi,
|
||||
cha: member.cha,
|
||||
|
||||
hack_exp: member.hack_exp,
|
||||
str_exp: member.str_exp,
|
||||
def_exp: member.def_exp,
|
||||
dex_exp: member.dex_exp,
|
||||
agi_exp: member.agi_exp,
|
||||
cha_exp: member.cha_exp,
|
||||
hack_exp: member.hack_exp,
|
||||
str_exp: member.str_exp,
|
||||
def_exp: member.def_exp,
|
||||
dex_exp: member.dex_exp,
|
||||
agi_exp: member.agi_exp,
|
||||
cha_exp: member.cha_exp,
|
||||
|
||||
hack_mult: member.hack_mult,
|
||||
str_mult: member.str_mult,
|
||||
def_mult: member.def_mult,
|
||||
dex_mult: member.dex_mult,
|
||||
agi_mult: member.agi_mult,
|
||||
cha_mult: member.cha_mult,
|
||||
hack_mult: member.hack_mult,
|
||||
str_mult: member.str_mult,
|
||||
def_mult: member.def_mult,
|
||||
dex_mult: member.dex_mult,
|
||||
agi_mult: member.agi_mult,
|
||||
cha_mult: member.cha_mult,
|
||||
|
||||
hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points),
|
||||
str_asc_mult: member.calculateAscensionMult(member.str_asc_points),
|
||||
def_asc_mult: member.calculateAscensionMult(member.def_asc_points),
|
||||
dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points),
|
||||
agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points),
|
||||
cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points),
|
||||
hack_asc_mult: member.calculateAscensionMult(member.hack_asc_points),
|
||||
str_asc_mult: member.calculateAscensionMult(member.str_asc_points),
|
||||
def_asc_mult: member.calculateAscensionMult(member.def_asc_points),
|
||||
dex_asc_mult: member.calculateAscensionMult(member.dex_asc_points),
|
||||
agi_asc_mult: member.calculateAscensionMult(member.agi_asc_points),
|
||||
cha_asc_mult: member.calculateAscensionMult(member.cha_asc_points),
|
||||
|
||||
hack_asc_points: member.hack_asc_points,
|
||||
str_asc_points: member.str_asc_points,
|
||||
def_asc_points: member.def_asc_points,
|
||||
dex_asc_points: member.dex_asc_points,
|
||||
agi_asc_points: member.agi_asc_points,
|
||||
cha_asc_points: member.cha_asc_points,
|
||||
hack_asc_points: member.hack_asc_points,
|
||||
str_asc_points: member.str_asc_points,
|
||||
def_asc_points: member.def_asc_points,
|
||||
dex_asc_points: member.dex_asc_points,
|
||||
agi_asc_points: member.agi_asc_points,
|
||||
cha_asc_points: member.cha_asc_points,
|
||||
|
||||
upgrades: member.upgrades.slice(),
|
||||
augmentations: member.augmentations.slice(),
|
||||
upgrades: member.upgrades.slice(),
|
||||
augmentations: member.augmentations.slice(),
|
||||
|
||||
respectGain: member.calculateRespectGain(gang),
|
||||
wantedLevelGain: member.calculateWantedLevelGain(gang),
|
||||
moneyGain: member.calculateMoneyGain(gang),
|
||||
};
|
||||
},
|
||||
canRecruitMember: function (): boolean {
|
||||
updateRam("canRecruitMember");
|
||||
checkGangApiAccess("canRecruitMember");
|
||||
respectGain: member.calculateRespectGain(gang),
|
||||
wantedLevelGain: member.calculateWantedLevelGain(gang),
|
||||
moneyGain: member.calculateMoneyGain(gang),
|
||||
};
|
||||
},
|
||||
canRecruitMember: (ctx: NetscriptContext) => (): boolean => {
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return gang.canRecruitMember();
|
||||
},
|
||||
recruitMember: function (_memberName: unknown): boolean {
|
||||
updateRam("recruitMember");
|
||||
const memberName = helper.string("recruitMember", "memberName", _memberName);
|
||||
checkGangApiAccess("recruitMember");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const recruited = gang.recruitMember(memberName);
|
||||
if (recruited) {
|
||||
workerScript.log("gang.recruitMember", () => `Successfully recruited Gang Member '${memberName}'`);
|
||||
} else {
|
||||
workerScript.log("gang.recruitMember", () => `Failed to recruit Gang Member '${memberName}'`);
|
||||
}
|
||||
recruitMember:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_memberName: unknown): boolean => {
|
||||
const memberName = ctx.helper.string("memberName", _memberName);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const recruited = gang.recruitMember(memberName);
|
||||
if (recruited) {
|
||||
workerScript.log("gang.recruitMember", () => `Successfully recruited Gang Member '${memberName}'`);
|
||||
} else {
|
||||
workerScript.log("gang.recruitMember", () => `Failed to recruit Gang Member '${memberName}'`);
|
||||
}
|
||||
|
||||
return recruited;
|
||||
},
|
||||
getTaskNames: function (): string[] {
|
||||
updateRam("getTaskNames");
|
||||
checkGangApiAccess("getTaskNames");
|
||||
return recruited;
|
||||
},
|
||||
getTaskNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const tasks = gang.getAllTaskNames();
|
||||
tasks.unshift("Unassigned");
|
||||
return tasks;
|
||||
},
|
||||
setMemberTask: function (_memberName: unknown, _taskName: unknown): boolean {
|
||||
updateRam("setMemberTask");
|
||||
const memberName = helper.string("setMemberTask", "memberName", _memberName);
|
||||
const taskName = helper.string("setMemberTask", "taskName", _taskName);
|
||||
checkGangApiAccess("setMemberTask");
|
||||
const member = getGangMember("setMemberTask", memberName);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (!gang.getAllTaskNames().includes(taskName)) {
|
||||
workerScript.log(
|
||||
"gang.setMemberTask",
|
||||
() =>
|
||||
`Failed to assign Gang Member '${memberName}' to Invalid task '${taskName}'. '${memberName}' is now Unassigned`,
|
||||
);
|
||||
return member.assignToTask("Unassigned");
|
||||
}
|
||||
const success = member.assignToTask(taskName);
|
||||
if (success) {
|
||||
workerScript.log(
|
||||
"gang.setMemberTask",
|
||||
() => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`,
|
||||
);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"gang.setMemberTask",
|
||||
() => `Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`,
|
||||
);
|
||||
}
|
||||
setMemberTask:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_memberName: unknown, _taskName: unknown): boolean => {
|
||||
const memberName = ctx.helper.string("memberName", _memberName);
|
||||
const taskName = ctx.helper.string("taskName", _taskName);
|
||||
checkGangApiAccess(ctx);
|
||||
const member = getGangMember(ctx, memberName);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (!gang.getAllTaskNames().includes(taskName)) {
|
||||
workerScript.log(
|
||||
"gang.setMemberTask",
|
||||
() =>
|
||||
`Failed to assign Gang Member '${memberName}' to Invalid task '${taskName}'. '${memberName}' is now Unassigned`,
|
||||
);
|
||||
return member.assignToTask("Unassigned");
|
||||
}
|
||||
const success = member.assignToTask(taskName);
|
||||
if (success) {
|
||||
workerScript.log(
|
||||
"gang.setMemberTask",
|
||||
() => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`,
|
||||
);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"gang.setMemberTask",
|
||||
() =>
|
||||
`Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`,
|
||||
);
|
||||
}
|
||||
|
||||
return success;
|
||||
},
|
||||
getTaskStats: function (_taskName: unknown): GangTaskStats {
|
||||
updateRam("getTaskStats");
|
||||
const taskName = helper.string("getTaskStats", "taskName", _taskName);
|
||||
checkGangApiAccess("getTaskStats");
|
||||
const task = getGangTask("getTaskStats", taskName);
|
||||
const copy = Object.assign({}, task);
|
||||
copy.territory = Object.assign({}, task.territory);
|
||||
return copy;
|
||||
},
|
||||
getEquipmentNames: function (): string[] {
|
||||
updateRam("getEquipmentNames");
|
||||
checkGangApiAccess("getEquipmentNames");
|
||||
return success;
|
||||
},
|
||||
getTaskStats:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_taskName: unknown): GangTaskStats => {
|
||||
const taskName = ctx.helper.string("taskName", _taskName);
|
||||
checkGangApiAccess(ctx);
|
||||
const task = getGangTask(ctx, taskName);
|
||||
const copy = Object.assign({}, task);
|
||||
copy.territory = Object.assign({}, task.territory);
|
||||
return copy;
|
||||
},
|
||||
getEquipmentNames: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkGangApiAccess(ctx);
|
||||
return Object.keys(GangMemberUpgrades);
|
||||
},
|
||||
getEquipmentCost: function (_equipName: any): number {
|
||||
updateRam("getEquipmentCost");
|
||||
const equipName = helper.string("getEquipmentCost", "equipName", _equipName);
|
||||
checkGangApiAccess("getEquipmentCost");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg === null) return Infinity;
|
||||
return gang.getUpgradeCost(upg);
|
||||
},
|
||||
getEquipmentType: function (_equipName: unknown): string {
|
||||
updateRam("getEquipmentType");
|
||||
const equipName = helper.string("getEquipmentType", "equipName", _equipName);
|
||||
checkGangApiAccess("getEquipmentType");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg == null) return "";
|
||||
return upg.getType();
|
||||
},
|
||||
getEquipmentStats: function (_equipName: unknown): EquipmentStats {
|
||||
updateRam("getEquipmentStats");
|
||||
const equipName = helper.string("getEquipmentStats", "equipName", _equipName);
|
||||
checkGangApiAccess("getEquipmentStats");
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) {
|
||||
throw helper.makeRuntimeErrorMsg("getEquipmentStats", `Invalid equipment: ${equipName}`);
|
||||
}
|
||||
const typecheck: EquipmentStats = equipment.mults;
|
||||
return Object.assign({}, typecheck) as any;
|
||||
},
|
||||
purchaseEquipment: function (_memberName: unknown, _equipName: unknown): boolean {
|
||||
updateRam("purchaseEquipment");
|
||||
const memberName = helper.string("purchaseEquipment", "memberName", _memberName);
|
||||
const equipName = helper.string("purchaseEquipment", "equipName", _equipName);
|
||||
checkGangApiAccess("purchaseEquipment");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("purchaseEquipment", memberName);
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) return false;
|
||||
const res = member.buyUpgrade(equipment, player, gang);
|
||||
if (res) {
|
||||
workerScript.log("gang.purchaseEquipment", () => `Purchased '${equipName}' for Gang member '${memberName}'`);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"gang.purchaseEquipment",
|
||||
() => `Failed to purchase '${equipName}' for Gang member '${memberName}'`,
|
||||
);
|
||||
}
|
||||
getEquipmentCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_equipName: any): number => {
|
||||
const equipName = ctx.helper.string("equipName", _equipName);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg === null) return Infinity;
|
||||
return gang.getUpgradeCost(upg);
|
||||
},
|
||||
getEquipmentType:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_equipName: unknown): string => {
|
||||
const equipName = ctx.helper.string("equipName", _equipName);
|
||||
checkGangApiAccess(ctx);
|
||||
const upg = GangMemberUpgrades[equipName];
|
||||
if (upg == null) return "";
|
||||
return upg.getType();
|
||||
},
|
||||
getEquipmentStats:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_equipName: unknown): EquipmentStats => {
|
||||
const equipName = ctx.helper.string("equipName", _equipName);
|
||||
checkGangApiAccess(ctx);
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid equipment: ${equipName}`);
|
||||
}
|
||||
const typecheck: EquipmentStats = equipment.mults;
|
||||
return Object.assign({}, typecheck) as any;
|
||||
},
|
||||
purchaseEquipment:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_memberName: unknown, _equipName: unknown): boolean => {
|
||||
const memberName = ctx.helper.string("memberName", _memberName);
|
||||
const equipName = ctx.helper.string("equipName", _equipName);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember(ctx, memberName);
|
||||
const equipment = GangMemberUpgrades[equipName];
|
||||
if (!equipment) return false;
|
||||
const res = member.buyUpgrade(equipment, player, gang);
|
||||
if (res) {
|
||||
workerScript.log("gang.purchaseEquipment", () => `Purchased '${equipName}' for Gang member '${memberName}'`);
|
||||
} else {
|
||||
workerScript.log(
|
||||
"gang.purchaseEquipment",
|
||||
() => `Failed to purchase '${equipName}' for Gang member '${memberName}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
ascendMember: function (_memberName: unknown): GangMemberAscension | undefined {
|
||||
updateRam("ascendMember");
|
||||
const memberName = helper.string("ascendMember", "memberName", _memberName);
|
||||
checkGangApiAccess("ascendMember");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("ascendMember", memberName);
|
||||
if (!member.canAscend()) return;
|
||||
return gang.ascendMember(member, workerScript);
|
||||
},
|
||||
getAscensionResult: function (_memberName: unknown): GangMemberAscension | undefined {
|
||||
updateRam("getAscensionResult");
|
||||
const memberName = helper.string("getAscensionResult", "memberName", _memberName);
|
||||
checkGangApiAccess("getAscensionResult");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember("getAscensionResult", memberName);
|
||||
if (!member.canAscend()) return;
|
||||
return {
|
||||
respect: member.earnedRespect,
|
||||
...member.getAscensionResults(),
|
||||
};
|
||||
},
|
||||
setTerritoryWarfare: function (_engage: unknown): void {
|
||||
updateRam("setTerritoryWarfare");
|
||||
const engage = helper.boolean(_engage);
|
||||
checkGangApiAccess("setTerritoryWarfare");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (engage) {
|
||||
gang.territoryWarfareEngaged = true;
|
||||
workerScript.log("gang.setTerritoryWarfare", () => "Engaging in Gang Territory Warfare");
|
||||
} else {
|
||||
gang.territoryWarfareEngaged = false;
|
||||
workerScript.log("gang.setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare");
|
||||
}
|
||||
},
|
||||
getChanceToWinClash: function (_otherGang: unknown): number {
|
||||
updateRam("getChanceToWinClash");
|
||||
const otherGang = helper.string("getChanceToWinClash", "otherGang", _otherGang);
|
||||
checkGangApiAccess("getChanceToWinClash");
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (AllGangs[otherGang] == null) {
|
||||
throw helper.makeRuntimeErrorMsg(`gang.getChanceToWinClash`, `Invalid gang: ${otherGang}`);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
ascendMember:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_memberName: unknown): GangMemberAscension | undefined => {
|
||||
const memberName = ctx.helper.string("memberName", _memberName);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember(ctx, memberName);
|
||||
if (!member.canAscend()) return;
|
||||
return gang.ascendMember(member, workerScript);
|
||||
},
|
||||
getAscensionResult:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_memberName: unknown): GangMemberAscension | undefined => {
|
||||
const memberName = ctx.helper.string("memberName", _memberName);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
const member = getGangMember(ctx, memberName);
|
||||
if (!member.canAscend()) return;
|
||||
return {
|
||||
respect: member.earnedRespect,
|
||||
...member.getAscensionResults(),
|
||||
};
|
||||
},
|
||||
setTerritoryWarfare:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_engage: unknown): void => {
|
||||
const engage = ctx.helper.boolean(_engage);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (engage) {
|
||||
gang.territoryWarfareEngaged = true;
|
||||
workerScript.log("gang.setTerritoryWarfare", () => "Engaging in Gang Territory Warfare");
|
||||
} else {
|
||||
gang.territoryWarfareEngaged = false;
|
||||
workerScript.log("gang.setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare");
|
||||
}
|
||||
},
|
||||
getChanceToWinClash:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_otherGang: unknown): number => {
|
||||
const otherGang = ctx.helper.string("otherGang", _otherGang);
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
if (AllGangs[otherGang] == null) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid gang: ${otherGang}`);
|
||||
}
|
||||
|
||||
const playerPower = AllGangs[gang.facName].power;
|
||||
const otherPower = AllGangs[otherGang].power;
|
||||
const playerPower = AllGangs[gang.facName].power;
|
||||
const otherPower = AllGangs[otherGang].power;
|
||||
|
||||
return playerPower / (otherPower + playerPower);
|
||||
},
|
||||
getBonusTime: function (): number {
|
||||
updateRam("getBonusTime");
|
||||
checkGangApiAccess("getBonusTime");
|
||||
return playerPower / (otherPower + playerPower);
|
||||
},
|
||||
getBonusTime: (ctx: NetscriptContext) => (): number => {
|
||||
checkGangApiAccess(ctx);
|
||||
const gang = player.gang;
|
||||
if (gang === null) throw new Error("Should not be called without Gang");
|
||||
return Math.round(gang.storedCycles / 5) * 1000;
|
||||
|
@ -1,104 +1,97 @@
|
||||
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
||||
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||
import { hasAugmentationPrereqs } from "../Faction/FactionHelpers";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation";
|
||||
import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../PersonObjects/Grafting/GraftingHelpers";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
|
||||
export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IGrafting {
|
||||
const checkGraftingAPIAccess = (func: string): void => {
|
||||
export function NetscriptGrafting(player: IPlayer): InternalAPI<IGrafting> {
|
||||
const checkGraftingAPIAccess = (ctx: NetscriptContext): void => {
|
||||
if (!player.canAccessGrafting()) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
`grafting.${func}`,
|
||||
throw ctx.makeRuntimeErrorMsg(
|
||||
"You do not currently have access to the Grafting API. This is either because you are not in BitNode 10 or because you do not have Source-File 10",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const updateRam = (funcName: string): void =>
|
||||
helper.updateDynamicRam(funcName, getRamCost(player, "grafting", funcName));
|
||||
|
||||
return {
|
||||
getAugmentationGraftPrice: (_augName: unknown): number => {
|
||||
updateRam("getAugmentationGraftPrice");
|
||||
const augName = helper.string("getAugmentationGraftPrice", "augName", _augName);
|
||||
checkGraftingAPIAccess("getAugmentationGraftPrice");
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftPrice", `Invalid aug: ${augName}`);
|
||||
}
|
||||
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||
return graftableAug.cost;
|
||||
},
|
||||
getAugmentationGraftPrice:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_augName: unknown): number => {
|
||||
const augName = ctx.helper.string("augName", _augName);
|
||||
checkGraftingAPIAccess(ctx);
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`);
|
||||
}
|
||||
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||
return graftableAug.cost;
|
||||
},
|
||||
|
||||
getAugmentationGraftTime: (_augName: string): number => {
|
||||
updateRam("getAugmentationGraftTime");
|
||||
const augName = helper.string("getAugmentationGraftTime", "augName", _augName);
|
||||
checkGraftingAPIAccess("getAugmentationGraftTime");
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftTime", `Invalid aug: ${augName}`);
|
||||
}
|
||||
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||
return calculateGraftingTimeWithBonus(player, graftableAug);
|
||||
},
|
||||
getAugmentationGraftTime:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_augName: string): number => {
|
||||
const augName = ctx.helper.string("augName", _augName);
|
||||
checkGraftingAPIAccess(ctx);
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`);
|
||||
}
|
||||
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||
return calculateGraftingTimeWithBonus(player, graftableAug);
|
||||
},
|
||||
|
||||
getGraftableAugmentations: (): string[] => {
|
||||
updateRam("getGraftableAugmentations");
|
||||
checkGraftingAPIAccess("getGraftableAugmentations");
|
||||
getGraftableAugmentations: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkGraftingAPIAccess(ctx);
|
||||
const graftableAugs = getGraftingAvailableAugs(player);
|
||||
return graftableAugs;
|
||||
},
|
||||
|
||||
graftAugmentation: (_augName: string, _focus: unknown = true): boolean => {
|
||||
updateRam("graftAugmentation");
|
||||
const augName = helper.string("graftAugmentation", "augName", _augName);
|
||||
const focus = helper.boolean(_focus);
|
||||
checkGraftingAPIAccess("graftAugmentation");
|
||||
if (player.city !== CityName.NewTokyo) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"grafting.graftAugmentation",
|
||||
"You must be in New Tokyo to begin grafting an Augmentation.",
|
||||
);
|
||||
}
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||
workerScript.log("grafting.graftAugmentation", () => `Invalid aug: ${augName}`);
|
||||
return false;
|
||||
}
|
||||
graftAugmentation:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_augName: string, _focus: unknown = true): boolean => {
|
||||
const augName = ctx.helper.string("augName", _augName);
|
||||
const focus = ctx.helper.boolean(_focus);
|
||||
checkGraftingAPIAccess(ctx);
|
||||
if (player.city !== CityName.NewTokyo) {
|
||||
throw ctx.makeRuntimeErrorMsg("You must be in New Tokyo to begin grafting an Augmentation.");
|
||||
}
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
|
||||
ctx.log(() => `Invalid aug: ${augName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const wasFocusing = player.focus;
|
||||
if (player.isWorking) {
|
||||
const txt = player.singularityStopWork();
|
||||
workerScript.log("graftAugmentation", () => txt);
|
||||
}
|
||||
const wasFocusing = player.focus;
|
||||
if (player.isWorking) {
|
||||
const txt = player.singularityStopWork();
|
||||
ctx.log(() => txt);
|
||||
}
|
||||
|
||||
const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||
if (player.money < craftableAug.cost) {
|
||||
workerScript.log("grafting.graftAugmentation", () => `You don't have enough money to craft ${augName}`);
|
||||
return false;
|
||||
}
|
||||
const craftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
|
||||
if (player.money < craftableAug.cost) {
|
||||
ctx.log(() => `You don't have enough money to craft ${augName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasAugmentationPrereqs(craftableAug.augmentation)) {
|
||||
workerScript.log("grafting.graftAugmentation", () => `You don't have the pre-requisites for ${augName}`);
|
||||
return false;
|
||||
}
|
||||
if (!hasAugmentationPrereqs(craftableAug.augmentation)) {
|
||||
ctx.log(() => `You don't have the pre-requisites for ${augName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
player.loseMoney(craftableAug.cost, "augmentations");
|
||||
player.startGraftAugmentationWork(augName, craftableAug.time);
|
||||
player.loseMoney(craftableAug.cost, "augmentations");
|
||||
player.startGraftAugmentationWork(augName, craftableAug.time);
|
||||
|
||||
if (focus) {
|
||||
player.startFocusing();
|
||||
Router.toWork();
|
||||
} else if (wasFocusing) {
|
||||
player.stopFocusing();
|
||||
Router.toTerminal();
|
||||
}
|
||||
if (focus) {
|
||||
player.startFocusing();
|
||||
Router.toWork();
|
||||
} else if (wasFocusing) {
|
||||
player.stopFocusing();
|
||||
Router.toTerminal();
|
||||
}
|
||||
|
||||
workerScript.log("grafting.graftAugmentation", () => `Began grafting Augmentation ${augName}.`);
|
||||
return true;
|
||||
},
|
||||
ctx.log(() => `Began grafting Augmentation ${augName}.`);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { HacknetServerConstants } from "../Hacknet/data/Constants";
|
||||
@ -21,12 +20,13 @@ import { HashUpgrade } from "../Hacknet/HashUpgrade";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
|
||||
import { Hacknet as IHacknet, NodeStats } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
||||
|
||||
export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IHacknet {
|
||||
export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript): InternalAPI<IHacknet> {
|
||||
// Utility function to get Hacknet Node object
|
||||
const getHacknetNode = function (i: number, callingFn = ""): HacknetNode | HacknetServer {
|
||||
const getHacknetNode = function (ctx: NetscriptContext, i: number): HacknetNode | HacknetServer {
|
||||
if (i < 0 || i >= player.hacknetNodes.length) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
throw ctx.makeRuntimeErrorMsg("Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
}
|
||||
|
||||
if (hasHacknetServers(player)) {
|
||||
@ -35,8 +35,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
||||
const hserver = GetServer(hi);
|
||||
if (!(hserver instanceof HacknetServer)) throw new Error("hacknet server was not actually hacknet server");
|
||||
if (hserver == null) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
callingFn,
|
||||
throw ctx.makeRuntimeErrorMsg(
|
||||
`Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`,
|
||||
);
|
||||
}
|
||||
@ -50,162 +49,186 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
||||
};
|
||||
|
||||
return {
|
||||
numNodes: function (): number {
|
||||
numNodes: () => (): number => {
|
||||
return player.hacknetNodes.length;
|
||||
},
|
||||
maxNumNodes: function (): number {
|
||||
maxNumNodes: () => (): number => {
|
||||
if (hasHacknetServers(player)) {
|
||||
return HacknetServerConstants.MaxServers;
|
||||
}
|
||||
return Infinity;
|
||||
},
|
||||
purchaseNode: function (): number {
|
||||
purchaseNode: () => (): number => {
|
||||
return purchaseHacknet(player);
|
||||
},
|
||||
getPurchaseNodeCost: function (): number {
|
||||
getPurchaseNodeCost: () => (): number => {
|
||||
if (hasHacknetServers(player)) {
|
||||
return getCostOfNextHacknetServer(player);
|
||||
} else {
|
||||
return getCostOfNextHacknetNode(player);
|
||||
}
|
||||
},
|
||||
getNodeStats: function (_i: unknown): NodeStats {
|
||||
const i = helper.number("getNodeStats", "i", _i);
|
||||
const node = getHacknetNode(i, "getNodeStats");
|
||||
const hasUpgraded = hasHacknetServers(player);
|
||||
const res: any = {
|
||||
name: node instanceof HacknetServer ? node.hostname : node.name,
|
||||
level: node.level,
|
||||
ram: node instanceof HacknetServer ? node.maxRam : node.ram,
|
||||
ramUsed: node instanceof HacknetServer ? node.ramUsed : undefined,
|
||||
cores: node.cores,
|
||||
production: node instanceof HacknetServer ? node.hashRate : node.moneyGainRatePerSecond,
|
||||
timeOnline: node.onlineTimeSeconds,
|
||||
totalProduction: node instanceof HacknetServer ? node.totalHashesGenerated : node.totalMoneyGenerated,
|
||||
};
|
||||
getNodeStats:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown): NodeStats => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
const hasUpgraded = hasHacknetServers(player);
|
||||
const res: any = {
|
||||
name: node instanceof HacknetServer ? node.hostname : node.name,
|
||||
level: node.level,
|
||||
ram: node instanceof HacknetServer ? node.maxRam : node.ram,
|
||||
ramUsed: node instanceof HacknetServer ? node.ramUsed : undefined,
|
||||
cores: node.cores,
|
||||
production: node instanceof HacknetServer ? node.hashRate : node.moneyGainRatePerSecond,
|
||||
timeOnline: node.onlineTimeSeconds,
|
||||
totalProduction: node instanceof HacknetServer ? node.totalHashesGenerated : node.totalMoneyGenerated,
|
||||
};
|
||||
|
||||
if (hasUpgraded && node instanceof HacknetServer) {
|
||||
res.cache = node.cache;
|
||||
res.hashCapacity = node.hashCapacity;
|
||||
}
|
||||
if (hasUpgraded && node instanceof HacknetServer) {
|
||||
res.cache = node.cache;
|
||||
res.hashCapacity = node.hashCapacity;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
upgradeLevel: function (_i: unknown, _n: unknown = 1): boolean {
|
||||
const i = helper.number("upgradeLevel", "i", _i);
|
||||
const n = helper.number("upgradeLevel", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return purchaseLevelUpgrade(player, node, n);
|
||||
},
|
||||
upgradeRam: function (_i: unknown, _n: unknown = 1): boolean {
|
||||
const i = helper.number("upgradeRam", "i", _i);
|
||||
const n = helper.number("upgradeRam", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return purchaseRamUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCore: function (_i: unknown, _n: unknown = 1): boolean {
|
||||
const i = helper.number("upgradeCore", "i", _i);
|
||||
const n = helper.number("upgradeCore", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return purchaseCoreUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCache: function (_i: unknown, _n: unknown = 1): boolean {
|
||||
const i = helper.number("upgradeCache", "i", _i);
|
||||
const n = helper.number("upgradeCache", "n", _n);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("hacknet.upgradeCache", () => "Can only be called on hacknet servers");
|
||||
return false;
|
||||
}
|
||||
const res = purchaseCacheUpgrade(player, node, n);
|
||||
if (res) {
|
||||
updateHashManagerCapacity(player);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getLevelUpgradeCost: function (_i: unknown, _n: unknown = 1): number {
|
||||
const i = helper.number("getLevelUpgradeCost", "i", _i);
|
||||
const n = helper.number("getLevelUpgradeCost", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return node.calculateLevelUpgradeCost(n, player.hacknet_node_level_cost_mult);
|
||||
},
|
||||
getRamUpgradeCost: function (_i: unknown, _n: unknown = 1): number {
|
||||
const i = helper.number("getRamUpgradeCost", "i", _i);
|
||||
const n = helper.number("getRamUpgradeCost", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return node.calculateRamUpgradeCost(n, player.hacknet_node_ram_cost_mult);
|
||||
},
|
||||
getCoreUpgradeCost: function (_i: unknown, _n: unknown = 1): number {
|
||||
const i = helper.number("getCoreUpgradeCost", "i", _i);
|
||||
const n = helper.number("getCoreUpgradeCost", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return node.calculateCoreUpgradeCost(n, player.hacknet_node_core_cost_mult);
|
||||
},
|
||||
getCacheUpgradeCost: function (_i: unknown, _n: unknown = 1): number {
|
||||
const i = helper.number("getCacheUpgradeCost", "i", _i);
|
||||
const n = helper.number("getCacheUpgradeCost", "n", _n);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("hacknet.getCacheUpgradeCost", () => "Can only be called on hacknet servers");
|
||||
return -1;
|
||||
}
|
||||
return node.calculateCacheUpgradeCost(n);
|
||||
},
|
||||
numHashes: function (): number {
|
||||
return res;
|
||||
},
|
||||
upgradeLevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): boolean => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
return purchaseLevelUpgrade(player, node, n);
|
||||
},
|
||||
upgradeRam:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): boolean => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
return purchaseRamUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCore:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): boolean => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
return purchaseCoreUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCache:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): boolean => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
const node = getHacknetNode(ctx, i);
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("hacknet.upgradeCache", () => "Can only be called on hacknet servers");
|
||||
return false;
|
||||
}
|
||||
const res = purchaseCacheUpgrade(player, node, n);
|
||||
if (res) {
|
||||
updateHashManagerCapacity(player);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getLevelUpgradeCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): number => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
return node.calculateLevelUpgradeCost(n, player.hacknet_node_level_cost_mult);
|
||||
},
|
||||
getRamUpgradeCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): number => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
return node.calculateRamUpgradeCost(n, player.hacknet_node_ram_cost_mult);
|
||||
},
|
||||
getCoreUpgradeCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): number => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
const node = getHacknetNode(ctx, i);
|
||||
return node.calculateCoreUpgradeCost(n, player.hacknet_node_core_cost_mult);
|
||||
},
|
||||
getCacheUpgradeCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_i: unknown, _n: unknown = 1): number => {
|
||||
const i = ctx.helper.number("i", _i);
|
||||
const n = ctx.helper.number("n", _n);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
const node = getHacknetNode(ctx, i);
|
||||
if (!(node instanceof HacknetServer)) {
|
||||
workerScript.log("hacknet.getCacheUpgradeCost", () => "Can only be called on hacknet servers");
|
||||
return -1;
|
||||
}
|
||||
return node.calculateCacheUpgradeCost(n);
|
||||
},
|
||||
numHashes: () => (): number => {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return 0;
|
||||
}
|
||||
return player.hashManager.hashes;
|
||||
},
|
||||
hashCapacity: function (): number {
|
||||
hashCapacity: () => (): number => {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return 0;
|
||||
}
|
||||
return player.hashManager.capacity;
|
||||
},
|
||||
hashCost: function (_upgName: unknown): number {
|
||||
const upgName = helper.string("hashCost", "upgName", _upgName);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
hashCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_upgName: unknown): number => {
|
||||
const upgName = ctx.helper.string("upgName", _upgName);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return player.hashManager.getUpgradeCost(upgName);
|
||||
},
|
||||
spendHashes: function (_upgName: unknown, _upgTarget: unknown = ""): boolean {
|
||||
const upgName = helper.string("spendHashes", "upgName", _upgName);
|
||||
const upgTarget = helper.string("spendHashes", "upgTarget", _upgTarget);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
return purchaseHashUpgrade(player, upgName, upgTarget);
|
||||
},
|
||||
getHashUpgrades: function (): string[] {
|
||||
return player.hashManager.getUpgradeCost(upgName);
|
||||
},
|
||||
spendHashes:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_upgName: unknown, _upgTarget: unknown = ""): boolean => {
|
||||
const upgName = ctx.helper.string("upgName", _upgName);
|
||||
const upgTarget = ctx.helper.string("upgTarget", _upgTarget);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
return purchaseHashUpgrade(player, upgName, upgTarget);
|
||||
},
|
||||
getHashUpgrades: () => (): string[] => {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(HashUpgrades).map((upgrade: HashUpgrade) => upgrade.name);
|
||||
},
|
||||
getHashUpgradeLevel: function (_upgName: unknown): number {
|
||||
const upgName = helper.string("getHashUpgradeLevel", "upgName", _upgName);
|
||||
const level = player.hashManager.upgrades[upgName];
|
||||
if (level === undefined) {
|
||||
throw helper.makeRuntimeErrorMsg("hacknet.hashUpgradeLevel", `Invalid Hash Upgrade: ${upgName}`);
|
||||
}
|
||||
return level;
|
||||
},
|
||||
getStudyMult: function (): number {
|
||||
getHashUpgradeLevel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_upgName: unknown): number => {
|
||||
const upgName = ctx.helper.string("upgName", _upgName);
|
||||
const level = player.hashManager.upgrades[upgName];
|
||||
if (level === undefined) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid Hash Upgrade: ${upgName}`);
|
||||
}
|
||||
return level;
|
||||
},
|
||||
getStudyMult: () => (): number => {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return 1;
|
||||
}
|
||||
return player.hashManager.getStudyMult();
|
||||
},
|
||||
getTrainingMult: function (): number {
|
||||
getTrainingMult: () => (): number => {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
if (script.filename === cbScript) {
|
||||
const ramUsage = script.ramUsage;
|
||||
const ramAvailable = home.maxRam - home.ramUsed;
|
||||
if (ramUsage > ramAvailable) {
|
||||
if (ramUsage > ramAvailable + 0.001) {
|
||||
return; // Not enough RAM
|
||||
}
|
||||
const runningScriptObj = new RunningScript(script, []); // No args
|
||||
@ -123,7 +123,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return [aug.getCost(player).moneyCost, aug.getCost(player).repCost];
|
||||
const costs = aug.getCost(player);
|
||||
return [costs.repCost, costs.moneyCost];
|
||||
},
|
||||
getAugmentationPrereq: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): string[] {
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { FactionWorkType } from "../Faction/FactionWorkTypeEnum";
|
||||
import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
||||
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
@ -17,22 +14,22 @@ import {
|
||||
SleeveTask,
|
||||
} from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { checkEnum } from "../utils/helpers/checkEnum";
|
||||
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
||||
|
||||
export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): ISleeve {
|
||||
const checkSleeveAPIAccess = function (func: string): void {
|
||||
export function NetscriptSleeve(player: IPlayer): InternalAPI<ISleeve> {
|
||||
const checkSleeveAPIAccess = function (ctx: NetscriptContext): void {
|
||||
if (player.bitNodeN !== 10 && !player.sourceFileLvl(10)) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
`sleeve.${func}`,
|
||||
throw ctx.makeRuntimeErrorMsg(
|
||||
"You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const checkSleeveNumber = function (func: string, sleeveNumber: number): void {
|
||||
const checkSleeveNumber = function (ctx: NetscriptContext, sleeveNumber: number): void {
|
||||
if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) {
|
||||
const msg = `Invalid sleeve number: ${sleeveNumber}`;
|
||||
workerScript.log(func, () => msg);
|
||||
throw helper.makeRuntimeErrorMsg(`sleeve.${func}`, msg);
|
||||
ctx.log(() => msg);
|
||||
throw ctx.makeRuntimeErrorMsg(msg);
|
||||
}
|
||||
};
|
||||
|
||||
@ -50,296 +47,299 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
|
||||
};
|
||||
};
|
||||
|
||||
const updateRam = (funcName: string): void =>
|
||||
helper.updateDynamicRam(funcName, getRamCost(player, "sleeve", funcName));
|
||||
|
||||
return {
|
||||
getNumSleeves: function (): number {
|
||||
updateRam("getNumSleeves");
|
||||
checkSleeveAPIAccess("getNumSleeves");
|
||||
getNumSleeves: (ctx: NetscriptContext) => (): number => {
|
||||
checkSleeveAPIAccess(ctx);
|
||||
return player.sleeves.length;
|
||||
},
|
||||
setToShockRecovery: function (_sleeveNumber: unknown): boolean {
|
||||
updateRam("setToShockRecovery");
|
||||
const sleeveNumber = helper.number("setToShockRecovery", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("setToShockRecovery");
|
||||
checkSleeveNumber("setToShockRecovery", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].shockRecovery(player);
|
||||
},
|
||||
setToSynchronize: function (_sleeveNumber: unknown): boolean {
|
||||
updateRam("setToSynchronize");
|
||||
const sleeveNumber = helper.number("setToSynchronize", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("setToSynchronize");
|
||||
checkSleeveNumber("setToSynchronize", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].synchronize(player);
|
||||
},
|
||||
setToCommitCrime: function (_sleeveNumber: unknown, _crimeRoughName: unknown): boolean {
|
||||
updateRam("setToCommitCrime");
|
||||
const sleeveNumber = helper.number("setToCommitCrime", "sleeveNumber", _sleeveNumber);
|
||||
const crimeRoughName = helper.string("setToCommitCrime", "crimeName", _crimeRoughName);
|
||||
checkSleeveAPIAccess("setToCommitCrime");
|
||||
checkSleeveNumber("setToCommitCrime", sleeveNumber);
|
||||
const crime = findCrime(crimeRoughName);
|
||||
if (crime === null) {
|
||||
return false;
|
||||
}
|
||||
return player.sleeves[sleeveNumber].commitCrime(player, crime.name);
|
||||
},
|
||||
setToUniversityCourse: function (_sleeveNumber: unknown, _universityName: unknown, _className: unknown): boolean {
|
||||
updateRam("setToUniversityCourse");
|
||||
const sleeveNumber = helper.number("setToUniversityCourse", "sleeveNumber", _sleeveNumber);
|
||||
const universityName = helper.string("setToUniversityCourse", "universityName", _universityName);
|
||||
const className = helper.string("setToUniversityCourse", "className", _className);
|
||||
checkSleeveAPIAccess("setToUniversityCourse");
|
||||
checkSleeveNumber("setToUniversityCourse", sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
|
||||
},
|
||||
travel: function (_sleeveNumber: unknown, _cityName: unknown): boolean {
|
||||
updateRam("travel");
|
||||
const sleeveNumber = helper.number("travel", "sleeveNumber", _sleeveNumber);
|
||||
const cityName = helper.string("travel", "cityName", _cityName);
|
||||
checkSleeveAPIAccess("travel");
|
||||
checkSleeveNumber("travel", sleeveNumber);
|
||||
if (checkEnum(CityName, cityName)) {
|
||||
return player.sleeves[sleeveNumber].travel(player, cityName);
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("sleeve.setToCompanyWork", `Invalid city name: '${cityName}'.`);
|
||||
}
|
||||
},
|
||||
setToCompanyWork: function (_sleeveNumber: unknown, acompanyName: unknown): boolean {
|
||||
updateRam("setToCompanyWork");
|
||||
const sleeveNumber = helper.number("setToCompanyWork", "sleeveNumber", _sleeveNumber);
|
||||
const companyName = helper.string("setToCompanyWork", "companyName", acompanyName);
|
||||
checkSleeveAPIAccess("setToCompanyWork");
|
||||
checkSleeveNumber("setToCompanyWork", sleeveNumber);
|
||||
|
||||
// Cannot work at the same company that another sleeve is working at
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
setToShockRecovery:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].shockRecovery(player);
|
||||
},
|
||||
setToSynchronize:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].synchronize(player);
|
||||
},
|
||||
setToCommitCrime:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _crimeRoughName: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const crimeRoughName = ctx.helper.string("crimeName", _crimeRoughName);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
const crime = findCrime(crimeRoughName);
|
||||
if (crime === null) {
|
||||
return false;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sleeve.setToCompanyWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
return player.sleeves[sleeveNumber].commitCrime(player, crime.name);
|
||||
},
|
||||
setToUniversityCourse:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _universityName: unknown, _className: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const universityName = ctx.helper.string("universityName", _universityName);
|
||||
const className = ctx.helper.string("className", _className);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
|
||||
},
|
||||
travel:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _cityName: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const cityName = ctx.helper.string("cityName", _cityName);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
if (checkEnum(CityName, cityName)) {
|
||||
return player.sleeves[sleeveNumber].travel(player, cityName);
|
||||
} else {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid city name: '${cityName}'.`);
|
||||
}
|
||||
}
|
||||
},
|
||||
setToCompanyWork:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, acompanyName: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const companyName = ctx.helper.string("companyName", acompanyName);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
return player.sleeves[sleeveNumber].workForCompany(player, companyName);
|
||||
},
|
||||
setToFactionWork: function (
|
||||
_sleeveNumber: unknown,
|
||||
_factionName: unknown,
|
||||
_workType: unknown,
|
||||
): boolean | undefined {
|
||||
updateRam("setToFactionWork");
|
||||
const sleeveNumber = helper.number("setToFactionWork", "sleeveNumber", _sleeveNumber);
|
||||
const factionName = helper.string("setToFactionWork", "factionName", _factionName);
|
||||
const workType = helper.string("setToFactionWork", "workType", _workType);
|
||||
checkSleeveAPIAccess("setToFactionWork");
|
||||
checkSleeveNumber("setToFactionWork", sleeveNumber);
|
||||
|
||||
// Cannot work at the same faction that another sleeve is working at
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sleeve.setToFactionWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (player.gang && player.gang.facName == factionName) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sleeve.setToFactionWork",
|
||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`,
|
||||
);
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].workForFaction(player, factionName, workType);
|
||||
},
|
||||
setToGymWorkout: function (_sleeveNumber: unknown, _gymName: unknown, _stat: unknown): boolean {
|
||||
updateRam("setToGymWorkout");
|
||||
const sleeveNumber = helper.number("setToGymWorkout", "sleeveNumber", _sleeveNumber);
|
||||
const gymName = helper.string("setToGymWorkout", "gymName", _gymName);
|
||||
const stat = helper.string("setToGymWorkout", "stat", _stat);
|
||||
checkSleeveAPIAccess("setToGymWorkout");
|
||||
checkSleeveNumber("setToGymWorkout", sleeveNumber);
|
||||
|
||||
return player.sleeves[sleeveNumber].workoutAtGym(player, gymName, stat);
|
||||
},
|
||||
getSleeveStats: function (_sleeveNumber: unknown): SleeveSkills {
|
||||
updateRam("getSleeveStats");
|
||||
const sleeveNumber = helper.number("getSleeveStats", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("getSleeveStats");
|
||||
checkSleeveNumber("getSleeveStats", sleeveNumber);
|
||||
return getSleeveStats(sleeveNumber);
|
||||
},
|
||||
getTask: function (_sleeveNumber: unknown): SleeveTask {
|
||||
updateRam("getTask");
|
||||
const sleeveNumber = helper.number("getTask", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("getTask");
|
||||
checkSleeveNumber("getTask", sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
task: SleeveTaskType[sl.currentTask],
|
||||
crime: sl.crimeType,
|
||||
location: sl.currentTaskLocation,
|
||||
gymStatType: sl.gymStatType,
|
||||
factionWorkType: FactionWorkType[sl.factionWorkType],
|
||||
};
|
||||
},
|
||||
getInformation: function (_sleeveNumber: unknown): SleeveInformation {
|
||||
updateRam("getInformation");
|
||||
const sleeveNumber = helper.number("getInformation", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("getInformation");
|
||||
checkSleeveNumber("getInformation", sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
tor: false,
|
||||
city: sl.city,
|
||||
hp: sl.hp,
|
||||
jobs: Object.keys(player.jobs), // technically sleeves have the same jobs as the player.
|
||||
jobTitle: Object.values(player.jobs),
|
||||
maxHp: sl.max_hp,
|
||||
|
||||
mult: {
|
||||
agility: sl.agility_mult,
|
||||
agilityExp: sl.agility_exp_mult,
|
||||
charisma: sl.charisma_mult,
|
||||
charismaExp: sl.charisma_exp_mult,
|
||||
companyRep: sl.company_rep_mult,
|
||||
crimeMoney: sl.crime_money_mult,
|
||||
crimeSuccess: sl.crime_success_mult,
|
||||
defense: sl.defense_mult,
|
||||
defenseExp: sl.defense_exp_mult,
|
||||
dexterity: sl.dexterity_mult,
|
||||
dexterityExp: sl.dexterity_exp_mult,
|
||||
factionRep: sl.faction_rep_mult,
|
||||
hacking: sl.hacking_mult,
|
||||
hackingExp: sl.hacking_exp_mult,
|
||||
strength: sl.strength_mult,
|
||||
strengthExp: sl.strength_exp_mult,
|
||||
workMoney: sl.work_money_mult,
|
||||
},
|
||||
|
||||
timeWorked: sl.currentTaskTime,
|
||||
earningsForSleeves: {
|
||||
workHackExpGain: sl.earningsForSleeves.hack,
|
||||
workStrExpGain: sl.earningsForSleeves.str,
|
||||
workDefExpGain: sl.earningsForSleeves.def,
|
||||
workDexExpGain: sl.earningsForSleeves.dex,
|
||||
workAgiExpGain: sl.earningsForSleeves.agi,
|
||||
workChaExpGain: sl.earningsForSleeves.cha,
|
||||
workMoneyGain: sl.earningsForSleeves.money,
|
||||
},
|
||||
earningsForPlayer: {
|
||||
workHackExpGain: sl.earningsForPlayer.hack,
|
||||
workStrExpGain: sl.earningsForPlayer.str,
|
||||
workDefExpGain: sl.earningsForPlayer.def,
|
||||
workDexExpGain: sl.earningsForPlayer.dex,
|
||||
workAgiExpGain: sl.earningsForPlayer.agi,
|
||||
workChaExpGain: sl.earningsForPlayer.cha,
|
||||
workMoneyGain: sl.earningsForPlayer.money,
|
||||
},
|
||||
earningsForTask: {
|
||||
workHackExpGain: sl.earningsForTask.hack,
|
||||
workStrExpGain: sl.earningsForTask.str,
|
||||
workDefExpGain: sl.earningsForTask.def,
|
||||
workDexExpGain: sl.earningsForTask.dex,
|
||||
workAgiExpGain: sl.earningsForTask.agi,
|
||||
workChaExpGain: sl.earningsForTask.cha,
|
||||
workMoneyGain: sl.earningsForTask.money,
|
||||
},
|
||||
workRepGain: sl.getRepGain(player),
|
||||
};
|
||||
},
|
||||
getSleeveAugmentations: function (_sleeveNumber: unknown): string[] {
|
||||
updateRam("getSleeveAugmentations");
|
||||
const sleeveNumber = helper.number("getSleeveAugmentations", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("getSleeveAugmentations");
|
||||
checkSleeveNumber("getSleeveAugmentations", sleeveNumber);
|
||||
|
||||
const augs = [];
|
||||
for (let i = 0; i < player.sleeves[sleeveNumber].augmentations.length; i++) {
|
||||
augs.push(player.sleeves[sleeveNumber].augmentations[i].name);
|
||||
}
|
||||
return augs;
|
||||
},
|
||||
getSleevePurchasableAugs: function (_sleeveNumber: unknown): AugmentPair[] {
|
||||
updateRam("getSleevePurchasableAugs");
|
||||
const sleeveNumber = helper.number("getSleevePurchasableAugs", "sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess("getSleevePurchasableAugs");
|
||||
checkSleeveNumber("getSleevePurchasableAugs", sleeveNumber);
|
||||
|
||||
const purchasableAugs = findSleevePurchasableAugs(player.sleeves[sleeveNumber], player);
|
||||
const augs = [];
|
||||
for (let i = 0; i < purchasableAugs.length; i++) {
|
||||
const aug = purchasableAugs[i];
|
||||
augs.push({
|
||||
name: aug.name,
|
||||
cost: aug.baseCost,
|
||||
});
|
||||
}
|
||||
|
||||
return augs;
|
||||
},
|
||||
purchaseSleeveAug: function (_sleeveNumber: unknown, _augName: unknown): boolean {
|
||||
updateRam("purchaseSleeveAug");
|
||||
const sleeveNumber = helper.number("purchaseSleeveAug", "sleeveNumber", _sleeveNumber);
|
||||
const augName = helper.string("purchaseSleeveAug", "augName", _augName);
|
||||
checkSleeveAPIAccess("purchaseSleeveAug");
|
||||
checkSleeveNumber("purchaseSleeveAug", sleeveNumber);
|
||||
|
||||
if (getSleeveStats(sleeveNumber).shock > 0) {
|
||||
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Sleeve shock too high: Sleeve ${sleeveNumber}`);
|
||||
}
|
||||
|
||||
const aug = StaticAugmentations[augName];
|
||||
if (!aug) {
|
||||
throw helper.makeRuntimeErrorMsg("sleeve.purchaseSleeveAug", `Invalid aug: ${augName}`);
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
|
||||
},
|
||||
setToBladeburnerAction: function (_sleeveNumber: unknown, _action: unknown, _contract?: unknown): boolean {
|
||||
updateRam("setToBladeburnerAction");
|
||||
const sleeveNumber = helper.number("setToBladeburnerAction", "sleeveNumber", _sleeveNumber);
|
||||
const action = helper.string("setToBladeburnerAction", "action", _action);
|
||||
let contract: string;
|
||||
if (typeof _contract === "undefined") {
|
||||
contract = "------";
|
||||
} else {
|
||||
contract = helper.string("setToBladeburnerAction", "contract", _contract);
|
||||
}
|
||||
checkSleeveAPIAccess("setToBladeburnerAction");
|
||||
checkSleeveNumber("setToBladeburnerAction", sleeveNumber);
|
||||
|
||||
// Cannot Take on Contracts if another sleeve is performing that action
|
||||
if (action === "Take on contracts") {
|
||||
// Cannot work at the same company that another sleeve is working at
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Bladeburner && other.bbAction === action) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sleeve.setToBladeburnerAction",
|
||||
`Sleeve ${sleeveNumber} cannot take of contracts because Sleeve ${i} is already performing that action.`,
|
||||
if (other.currentTask === SleeveTaskType.Company && other.currentTaskLocation === companyName) {
|
||||
throw ctx.makeRuntimeErrorMsg(
|
||||
`Sleeve ${sleeveNumber} cannot work for company ${companyName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].bladeburner(player, action, contract);
|
||||
},
|
||||
return player.sleeves[sleeveNumber].workForCompany(player, companyName);
|
||||
},
|
||||
setToFactionWork:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _factionName: unknown, _workType: unknown): boolean | undefined => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const factionName = ctx.helper.string("factionName", _factionName);
|
||||
const workType = ctx.helper.string("workType", _workType);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
// Cannot work at the same faction that another sleeve is working at
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Faction && other.currentTaskLocation === factionName) {
|
||||
throw ctx.makeRuntimeErrorMsg(
|
||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because Sleeve ${i} is already working for them.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (player.gang && player.gang.facName == factionName) {
|
||||
throw ctx.makeRuntimeErrorMsg(
|
||||
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`,
|
||||
);
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].workForFaction(player, factionName, workType);
|
||||
},
|
||||
setToGymWorkout:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _gymName: unknown, _stat: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const gymName = ctx.helper.string("gymName", _gymName);
|
||||
const stat = ctx.helper.string("stat", _stat);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
return player.sleeves[sleeveNumber].workoutAtGym(player, gymName, stat);
|
||||
},
|
||||
getSleeveStats:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): SleeveSkills => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
return getSleeveStats(sleeveNumber);
|
||||
},
|
||||
getTask:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): SleeveTask => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
task: SleeveTaskType[sl.currentTask],
|
||||
crime: sl.crimeType,
|
||||
location: sl.currentTaskLocation,
|
||||
gymStatType: sl.gymStatType,
|
||||
factionWorkType: FactionWorkType[sl.factionWorkType],
|
||||
};
|
||||
},
|
||||
getInformation:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): SleeveInformation => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
const sl = player.sleeves[sleeveNumber];
|
||||
return {
|
||||
tor: false,
|
||||
city: sl.city,
|
||||
hp: sl.hp,
|
||||
jobs: Object.keys(player.jobs), // technically sleeves have the same jobs as the player.
|
||||
jobTitle: Object.values(player.jobs),
|
||||
maxHp: sl.max_hp,
|
||||
|
||||
mult: {
|
||||
agility: sl.agility_mult,
|
||||
agilityExp: sl.agility_exp_mult,
|
||||
charisma: sl.charisma_mult,
|
||||
charismaExp: sl.charisma_exp_mult,
|
||||
companyRep: sl.company_rep_mult,
|
||||
crimeMoney: sl.crime_money_mult,
|
||||
crimeSuccess: sl.crime_success_mult,
|
||||
defense: sl.defense_mult,
|
||||
defenseExp: sl.defense_exp_mult,
|
||||
dexterity: sl.dexterity_mult,
|
||||
dexterityExp: sl.dexterity_exp_mult,
|
||||
factionRep: sl.faction_rep_mult,
|
||||
hacking: sl.hacking_mult,
|
||||
hackingExp: sl.hacking_exp_mult,
|
||||
strength: sl.strength_mult,
|
||||
strengthExp: sl.strength_exp_mult,
|
||||
workMoney: sl.work_money_mult,
|
||||
},
|
||||
|
||||
timeWorked: sl.currentTaskTime,
|
||||
earningsForSleeves: {
|
||||
workHackExpGain: sl.earningsForSleeves.hack,
|
||||
workStrExpGain: sl.earningsForSleeves.str,
|
||||
workDefExpGain: sl.earningsForSleeves.def,
|
||||
workDexExpGain: sl.earningsForSleeves.dex,
|
||||
workAgiExpGain: sl.earningsForSleeves.agi,
|
||||
workChaExpGain: sl.earningsForSleeves.cha,
|
||||
workMoneyGain: sl.earningsForSleeves.money,
|
||||
},
|
||||
earningsForPlayer: {
|
||||
workHackExpGain: sl.earningsForPlayer.hack,
|
||||
workStrExpGain: sl.earningsForPlayer.str,
|
||||
workDefExpGain: sl.earningsForPlayer.def,
|
||||
workDexExpGain: sl.earningsForPlayer.dex,
|
||||
workAgiExpGain: sl.earningsForPlayer.agi,
|
||||
workChaExpGain: sl.earningsForPlayer.cha,
|
||||
workMoneyGain: sl.earningsForPlayer.money,
|
||||
},
|
||||
earningsForTask: {
|
||||
workHackExpGain: sl.earningsForTask.hack,
|
||||
workStrExpGain: sl.earningsForTask.str,
|
||||
workDefExpGain: sl.earningsForTask.def,
|
||||
workDexExpGain: sl.earningsForTask.dex,
|
||||
workAgiExpGain: sl.earningsForTask.agi,
|
||||
workChaExpGain: sl.earningsForTask.cha,
|
||||
workMoneyGain: sl.earningsForTask.money,
|
||||
},
|
||||
workRepGain: sl.getRepGain(player),
|
||||
};
|
||||
},
|
||||
getSleeveAugmentations:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): string[] => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
const augs = [];
|
||||
for (let i = 0; i < player.sleeves[sleeveNumber].augmentations.length; i++) {
|
||||
augs.push(player.sleeves[sleeveNumber].augmentations[i].name);
|
||||
}
|
||||
return augs;
|
||||
},
|
||||
getSleevePurchasableAugs:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown): AugmentPair[] => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
const purchasableAugs = findSleevePurchasableAugs(player.sleeves[sleeveNumber], player);
|
||||
const augs = [];
|
||||
for (let i = 0; i < purchasableAugs.length; i++) {
|
||||
const aug = purchasableAugs[i];
|
||||
augs.push({
|
||||
name: aug.name,
|
||||
cost: aug.baseCost,
|
||||
});
|
||||
}
|
||||
|
||||
return augs;
|
||||
},
|
||||
purchaseSleeveAug:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _augName: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const augName = ctx.helper.string("augName", _augName);
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
if (getSleeveStats(sleeveNumber).shock > 0) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Sleeve shock too high: Sleeve ${sleeveNumber}`);
|
||||
}
|
||||
|
||||
const aug = StaticAugmentations[augName];
|
||||
if (!aug) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid aug: ${augName}`);
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
|
||||
},
|
||||
setToBladeburnerAction:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_sleeveNumber: unknown, _action: unknown, _contract?: unknown): boolean => {
|
||||
const sleeveNumber = ctx.helper.number("sleeveNumber", _sleeveNumber);
|
||||
const action = ctx.helper.string("action", _action);
|
||||
let contract: string;
|
||||
if (typeof _contract === "undefined") {
|
||||
contract = "------";
|
||||
} else {
|
||||
contract = ctx.helper.string("contract", _contract);
|
||||
}
|
||||
checkSleeveAPIAccess(ctx);
|
||||
checkSleeveNumber(ctx, sleeveNumber);
|
||||
|
||||
// Cannot Take on Contracts if another sleeve is performing that action
|
||||
if (action === "Take on contracts") {
|
||||
for (let i = 0; i < player.sleeves.length; ++i) {
|
||||
if (i === sleeveNumber) {
|
||||
continue;
|
||||
}
|
||||
const other = player.sleeves[i];
|
||||
if (other.currentTask === SleeveTaskType.Bladeburner && other.bbAction === action) {
|
||||
throw ctx.helper.makeRuntimeErrorMsg(
|
||||
`Sleeve ${sleeveNumber} cannot take of contracts because Sleeve ${i} is already performing that action.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return player.sleeves[sleeveNumber].bladeburner(player, action, contract);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { netscriptDelay } from "../NetscriptEvaluator";
|
||||
|
||||
import { staneksGift } from "../CotMG/Helper";
|
||||
import { Fragments, FragmentById } from "../CotMG/Fragment";
|
||||
import { FragmentType } from "../CotMG/FragmentType";
|
||||
|
||||
import {
|
||||
Fragment as IFragment,
|
||||
@ -25,7 +26,7 @@ export function NetscriptStanek(
|
||||
): InternalAPI<IStanek> {
|
||||
function checkStanekAPIAccess(func: string): void {
|
||||
if (!player.hasAugmentation(AugmentationNames.StaneksGift1, true)) {
|
||||
helper.makeRuntimeErrorMsg(func, "Requires Stanek's Gift installed.");
|
||||
throw helper.makeRuntimeErrorMsg(func, "Stanek's Gift is not installed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,15 +43,23 @@ export function NetscriptStanek(
|
||||
},
|
||||
chargeFragment: (_ctx: NetscriptContext) =>
|
||||
function (_rootX: unknown, _rootY: unknown): Promise<void> {
|
||||
//Get the fragment object using the given coordinates
|
||||
const rootX = _ctx.helper.number("rootX", _rootX);
|
||||
const rootY = _ctx.helper.number("rootY", _rootY);
|
||||
checkStanekAPIAccess("chargeFragment");
|
||||
const fragment = staneksGift.findFragment(rootX, rootY);
|
||||
//Check whether the selected fragment can ge charged
|
||||
if (!fragment) throw _ctx.makeRuntimeErrorMsg(`No fragment with root (${rootX}, ${rootY}).`);
|
||||
if (fragment.fragment().type == FragmentType.Booster) {
|
||||
throw _ctx.makeRuntimeErrorMsg(
|
||||
`The fragment with root (${rootX}, ${rootY}) is a Booster Fragment and thus cannot be charged.`,
|
||||
);
|
||||
}
|
||||
//Charge the fragment
|
||||
const time = staneksGift.inBonus() ? 200 : 1000;
|
||||
return netscriptDelay(time, workerScript).then(function () {
|
||||
const charge = staneksGift.charge(player, fragment, workerScript.scriptRef.threads);
|
||||
_ctx.log(() => `Charged fragment for ${charge} charge.`);
|
||||
staneksGift.charge(player, fragment, workerScript.scriptRef.threads);
|
||||
_ctx.log(() => `Charged fragment with ${_ctx.workerScript.scriptRef.threads} threads.`);
|
||||
return Promise.resolve();
|
||||
});
|
||||
},
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling";
|
||||
import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder, initStockMarketFn } from "../StockMarket/StockMarket";
|
||||
import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers";
|
||||
@ -16,301 +14,286 @@ import {
|
||||
} from "../StockMarket/StockMarketCosts";
|
||||
import { Stock } from "../StockMarket/Stock";
|
||||
import { TIX } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||
|
||||
export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): TIX {
|
||||
export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript): InternalAPI<TIX> {
|
||||
/**
|
||||
* Checks if the player has TIX API access. Throws an error if the player does not
|
||||
*/
|
||||
const checkTixApiAccess = function (callingFn: string): void {
|
||||
const checkTixApiAccess = function (ctx: NetscriptContext): void {
|
||||
if (!player.hasWseAccount) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, `You don't have WSE Access! Cannot use ${callingFn}()`);
|
||||
throw ctx.makeRuntimeErrorMsg(`You don't have WSE Access! Cannot use ${ctx.function}()`);
|
||||
}
|
||||
if (!player.hasTixApiAccess) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, `You don't have TIX API Access! Cannot use ${callingFn}()`);
|
||||
throw ctx.makeRuntimeErrorMsg(`You don't have TIX API Access! Cannot use ${ctx.function}()`);
|
||||
}
|
||||
};
|
||||
|
||||
const getStockFromSymbol = function (symbol: string, callingFn: string): Stock {
|
||||
const getStockFromSymbol = function (ctx: NetscriptContext, symbol: string): Stock {
|
||||
const stock = SymbolToStockMap[symbol];
|
||||
if (stock == null) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, `Invalid stock symbol: '${symbol}'`);
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: '${symbol}'`);
|
||||
}
|
||||
|
||||
return stock;
|
||||
};
|
||||
|
||||
const updateRam = (funcName: string): void =>
|
||||
helper.updateDynamicRam(funcName, getRamCost(player, "stock", funcName));
|
||||
|
||||
return {
|
||||
getSymbols: function (): string[] {
|
||||
updateRam("getSymbols");
|
||||
checkTixApiAccess("getSymbols");
|
||||
getSymbols: (ctx: NetscriptContext) => (): string[] => {
|
||||
checkTixApiAccess(ctx);
|
||||
return Object.values(StockSymbols);
|
||||
},
|
||||
getPrice: function (_symbol: unknown): number {
|
||||
updateRam("getPrice");
|
||||
const symbol = helper.string("getPrice", "symbol", _symbol);
|
||||
checkTixApiAccess("getPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getPrice");
|
||||
getPrice:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
return stock.price;
|
||||
},
|
||||
getAskPrice: function (_symbol: unknown): number {
|
||||
updateRam("getAskPrice");
|
||||
const symbol = helper.string("getAskPrice", "symbol", _symbol);
|
||||
checkTixApiAccess("getAskPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getAskPrice");
|
||||
return stock.price;
|
||||
},
|
||||
getAskPrice:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
return stock.getAskPrice();
|
||||
},
|
||||
getBidPrice: function (_symbol: unknown): number {
|
||||
updateRam("getBidPrice");
|
||||
const symbol = helper.string("getBidPrice", "symbol", _symbol);
|
||||
checkTixApiAccess("getBidPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getBidPrice");
|
||||
return stock.getAskPrice();
|
||||
},
|
||||
getBidPrice:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
return stock.getBidPrice();
|
||||
},
|
||||
getPosition: function (_symbol: unknown): [number, number, number, number] {
|
||||
updateRam("getPosition");
|
||||
const symbol = helper.string("getPosition", "symbol", _symbol);
|
||||
checkTixApiAccess("getPosition");
|
||||
const stock = SymbolToStockMap[symbol];
|
||||
if (stock == null) {
|
||||
throw helper.makeRuntimeErrorMsg("getPosition", `Invalid stock symbol: ${symbol}`);
|
||||
}
|
||||
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
||||
},
|
||||
getMaxShares: function (_symbol: unknown): number {
|
||||
updateRam("getMaxShares");
|
||||
const symbol = helper.string("getMaxShares", "symbol", _symbol);
|
||||
checkTixApiAccess("getMaxShares");
|
||||
const stock = getStockFromSymbol(symbol, "getMaxShares");
|
||||
|
||||
return stock.maxShares;
|
||||
},
|
||||
getPurchaseCost: function (_symbol: unknown, _shares: unknown, _posType: unknown): number {
|
||||
updateRam("getPurchaseCost");
|
||||
const symbol = helper.string("getPurchaseCost", "symbol", _symbol);
|
||||
let shares = helper.number("getPurchaseCost", "shares", _shares);
|
||||
const posType = helper.string("getPurchaseCost", "posType", _posType);
|
||||
checkTixApiAccess("getPurchaseCost");
|
||||
const stock = getStockFromSymbol(symbol, "getPurchaseCost");
|
||||
shares = Math.round(shares);
|
||||
|
||||
let pos;
|
||||
const sanitizedPosType = posType.toLowerCase();
|
||||
if (sanitizedPosType.includes("l")) {
|
||||
pos = PositionTypes.Long;
|
||||
} else if (sanitizedPosType.includes("s")) {
|
||||
pos = PositionTypes.Short;
|
||||
} else {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
const res = getBuyTransactionCost(stock, shares, pos);
|
||||
if (res == null) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
getSaleGain: function (_symbol: unknown, _shares: unknown, _posType: unknown): number {
|
||||
updateRam("getSaleGain");
|
||||
const symbol = helper.string("getSaleGain", "symbol", _symbol);
|
||||
let shares = helper.number("getSaleGain", "shares", _shares);
|
||||
const posType = helper.string("getSaleGain", "posType", _posType);
|
||||
checkTixApiAccess("getSaleGain");
|
||||
const stock = getStockFromSymbol(symbol, "getSaleGain");
|
||||
shares = Math.round(shares);
|
||||
|
||||
let pos;
|
||||
const sanitizedPosType = posType.toLowerCase();
|
||||
if (sanitizedPosType.includes("l")) {
|
||||
pos = PositionTypes.Long;
|
||||
} else if (sanitizedPosType.includes("s")) {
|
||||
pos = PositionTypes.Short;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const res = getSellTransactionGain(stock, shares, pos);
|
||||
if (res == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
buy: function (_symbol: unknown, _shares: unknown): number {
|
||||
updateRam("buy");
|
||||
const symbol = helper.string("buy", "symbol", _symbol);
|
||||
const shares = helper.number("buy", "shares", _shares);
|
||||
checkTixApiAccess("buy");
|
||||
const stock = getStockFromSymbol(symbol, "buy");
|
||||
const res = buyStock(stock, shares, workerScript, {});
|
||||
return res ? stock.getAskPrice() : 0;
|
||||
},
|
||||
sell: function (_symbol: unknown, _shares: unknown): number {
|
||||
updateRam("sell");
|
||||
const symbol = helper.string("sell", "symbol", _symbol);
|
||||
const shares = helper.number("sell", "shares", _shares);
|
||||
checkTixApiAccess("sell");
|
||||
const stock = getStockFromSymbol(symbol, "sell");
|
||||
const res = sellStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.getBidPrice() : 0;
|
||||
},
|
||||
short: function (_symbol: unknown, _shares: unknown): number {
|
||||
updateRam("short");
|
||||
const symbol = helper.string("short", "symbol", _symbol);
|
||||
const shares = helper.number("short", "shares", _shares);
|
||||
checkTixApiAccess("short");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 1) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"short",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
|
||||
);
|
||||
return stock.getBidPrice();
|
||||
},
|
||||
getPosition:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): [number, number, number, number] => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = SymbolToStockMap[symbol];
|
||||
if (stock == null) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid stock symbol: ${symbol}`);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "short");
|
||||
const res = shortStock(stock, shares, workerScript, {});
|
||||
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
||||
},
|
||||
getMaxShares:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
return res ? stock.getBidPrice() : 0;
|
||||
},
|
||||
sellShort: function (_symbol: unknown, _shares: unknown): number {
|
||||
updateRam("sellShort");
|
||||
const symbol = helper.string("sellShort", "symbol", _symbol);
|
||||
const shares = helper.number("sellShort", "shares", _shares);
|
||||
checkTixApiAccess("sellShort");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 1) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"sellShort",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 2.",
|
||||
);
|
||||
return stock.maxShares;
|
||||
},
|
||||
getPurchaseCost:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown, _posType: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
let shares = ctx.helper.number("shares", _shares);
|
||||
const posType = ctx.helper.string("posType", _posType);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
shares = Math.round(shares);
|
||||
|
||||
let pos;
|
||||
const sanitizedPosType = posType.toLowerCase();
|
||||
if (sanitizedPosType.includes("l")) {
|
||||
pos = PositionTypes.Long;
|
||||
} else if (sanitizedPosType.includes("s")) {
|
||||
pos = PositionTypes.Short;
|
||||
} else {
|
||||
return Infinity;
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "sellShort");
|
||||
const res = sellShort(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.getAskPrice() : 0;
|
||||
},
|
||||
placeOrder: function (_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean {
|
||||
updateRam("placeOrder");
|
||||
const symbol = helper.string("placeOrder", "symbol", _symbol);
|
||||
const shares = helper.number("placeOrder", "shares", _shares);
|
||||
const price = helper.number("placeOrder", "price", _price);
|
||||
const type = helper.string("placeOrder", "type", _type);
|
||||
const pos = helper.string("placeOrder", "pos", _pos);
|
||||
checkTixApiAccess("placeOrder");
|
||||
const res = getBuyTransactionCost(stock, shares, pos);
|
||||
if (res == null) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
getSaleGain:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown, _posType: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
let shares = ctx.helper.number("shares", _shares);
|
||||
const posType = ctx.helper.string("posType", _posType);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
shares = Math.round(shares);
|
||||
|
||||
let pos;
|
||||
const sanitizedPosType = posType.toLowerCase();
|
||||
if (sanitizedPosType.includes("l")) {
|
||||
pos = PositionTypes.Long;
|
||||
} else if (sanitizedPosType.includes("s")) {
|
||||
pos = PositionTypes.Short;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const res = getSellTransactionGain(stock, shares, pos);
|
||||
if (res == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
buy:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
const shares = ctx.helper.number("shares", _shares);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
const res = buyStock(stock, shares, workerScript, {});
|
||||
return res ? stock.getAskPrice() : 0;
|
||||
},
|
||||
sell:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
const shares = ctx.helper.number("shares", _shares);
|
||||
checkTixApiAccess(ctx);
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
const res = sellStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.getBidPrice() : 0;
|
||||
},
|
||||
short:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
const shares = ctx.helper.number("shares", _shares);
|
||||
checkTixApiAccess(ctx);
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 1) {
|
||||
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 2.");
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
const res = shortStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.getBidPrice() : 0;
|
||||
},
|
||||
sellShort:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
const shares = ctx.helper.number("shares", _shares);
|
||||
checkTixApiAccess(ctx);
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 1) {
|
||||
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 2.");
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
const res = sellShort(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.getAskPrice() : 0;
|
||||
},
|
||||
placeOrder:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
const shares = ctx.helper.number("shares", _shares);
|
||||
const price = ctx.helper.number("price", _price);
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const pos = ctx.helper.string("pos", _pos);
|
||||
checkTixApiAccess(ctx);
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 3.");
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
let orderType;
|
||||
let orderPos;
|
||||
const ltype = type.toLowerCase();
|
||||
if (ltype.includes("limit") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.LimitBuy;
|
||||
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.LimitSell;
|
||||
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.StopBuy;
|
||||
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.StopSell;
|
||||
} else {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`);
|
||||
}
|
||||
|
||||
const lpos = pos.toLowerCase();
|
||||
if (lpos.includes("l")) {
|
||||
orderPos = PositionTypes.Long;
|
||||
} else if (lpos.includes("s")) {
|
||||
orderPos = PositionTypes.Short;
|
||||
} else {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`);
|
||||
}
|
||||
|
||||
return placeOrder(stock, shares, price, orderType, orderPos, workerScript);
|
||||
},
|
||||
cancelOrder:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
const shares = ctx.helper.number("shares", _shares);
|
||||
const price = ctx.helper.number("price", _price);
|
||||
const type = ctx.helper.string("type", _type);
|
||||
const pos = ctx.helper.string("pos", _pos);
|
||||
checkTixApiAccess(ctx);
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or you must have Source-File 8 Level 3.");
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
if (isNaN(shares) || isNaN(price)) {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`);
|
||||
}
|
||||
let orderType;
|
||||
let orderPos;
|
||||
const ltype = type.toLowerCase();
|
||||
if (ltype.includes("limit") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.LimitBuy;
|
||||
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.LimitSell;
|
||||
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.StopBuy;
|
||||
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.StopSell;
|
||||
} else {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid order type: ${type}`);
|
||||
}
|
||||
|
||||
const lpos = pos.toLowerCase();
|
||||
if (lpos.includes("l")) {
|
||||
orderPos = PositionTypes.Long;
|
||||
} else if (lpos.includes("s")) {
|
||||
orderPos = PositionTypes.Short;
|
||||
} else {
|
||||
throw ctx.makeRuntimeErrorMsg(`Invalid position type: ${pos}`);
|
||||
}
|
||||
const params = {
|
||||
stock: stock,
|
||||
shares: shares,
|
||||
price: price,
|
||||
type: orderType,
|
||||
pos: orderPos,
|
||||
};
|
||||
return cancelOrder(params, workerScript);
|
||||
},
|
||||
getOrders: (ctx: NetscriptContext) => (): any => {
|
||||
checkTixApiAccess(ctx);
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"placeOrder",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "placeOrder");
|
||||
|
||||
let orderType;
|
||||
let orderPos;
|
||||
const ltype = type.toLowerCase();
|
||||
if (ltype.includes("limit") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.LimitBuy;
|
||||
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.LimitSell;
|
||||
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.StopBuy;
|
||||
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.StopSell;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid order type: ${type}`);
|
||||
}
|
||||
|
||||
const lpos = pos.toLowerCase();
|
||||
if (lpos.includes("l")) {
|
||||
orderPos = PositionTypes.Long;
|
||||
} else if (lpos.includes("s")) {
|
||||
orderPos = PositionTypes.Short;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("placeOrder", `Invalid position type: ${pos}`);
|
||||
}
|
||||
|
||||
return placeOrder(stock, shares, price, orderType, orderPos, workerScript);
|
||||
},
|
||||
cancelOrder: function (
|
||||
_symbol: unknown,
|
||||
_shares: unknown,
|
||||
_price: unknown,
|
||||
_type: unknown,
|
||||
_pos: unknown,
|
||||
): boolean {
|
||||
updateRam("cancelOrder");
|
||||
const symbol = helper.string("cancelOrder", "symbol", _symbol);
|
||||
const shares = helper.number("cancelOrder", "shares", _shares);
|
||||
const price = helper.number("cancelOrder", "price", _price);
|
||||
const type = helper.string("cancelOrder", "type", _type);
|
||||
const pos = helper.string("cancelOrder", "pos", _pos);
|
||||
checkTixApiAccess("cancelOrder");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"cancelOrder",
|
||||
"You must either be in BitNode-8 or you must have Source-File 8 Level 3.",
|
||||
);
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "cancelOrder");
|
||||
if (isNaN(shares) || isNaN(price)) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"cancelOrder",
|
||||
`Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`,
|
||||
);
|
||||
}
|
||||
let orderType;
|
||||
let orderPos;
|
||||
const ltype = type.toLowerCase();
|
||||
if (ltype.includes("limit") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.LimitBuy;
|
||||
} else if (ltype.includes("limit") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.LimitSell;
|
||||
} else if (ltype.includes("stop") && ltype.includes("buy")) {
|
||||
orderType = OrderTypes.StopBuy;
|
||||
} else if (ltype.includes("stop") && ltype.includes("sell")) {
|
||||
orderType = OrderTypes.StopSell;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid order type: ${type}`);
|
||||
}
|
||||
|
||||
const lpos = pos.toLowerCase();
|
||||
if (lpos.includes("l")) {
|
||||
orderPos = PositionTypes.Long;
|
||||
} else if (lpos.includes("s")) {
|
||||
orderPos = PositionTypes.Short;
|
||||
} else {
|
||||
throw helper.makeRuntimeErrorMsg("cancelOrder", `Invalid position type: ${pos}`);
|
||||
}
|
||||
const params = {
|
||||
stock: stock,
|
||||
shares: shares,
|
||||
price: price,
|
||||
type: orderType,
|
||||
pos: orderPos,
|
||||
};
|
||||
return cancelOrder(params, workerScript);
|
||||
},
|
||||
getOrders: function (): any {
|
||||
updateRam("getOrders");
|
||||
checkTixApiAccess("getOrders");
|
||||
if (player.bitNodeN !== 8) {
|
||||
if (player.sourceFileLvl(8) <= 2) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
"getOrders",
|
||||
"You must either be in BitNode-8 or have Source-File 8 Level 3.",
|
||||
);
|
||||
throw ctx.makeRuntimeErrorMsg("You must either be in BitNode-8 or have Source-File 8 Level 3.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,103 +317,95 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return orders;
|
||||
},
|
||||
getVolatility: function (_symbol: unknown): number {
|
||||
updateRam("getVolatility");
|
||||
const symbol = helper.string("getVolatility", "symbol", _symbol);
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw helper.makeRuntimeErrorMsg("getVolatility", "You don't have 4S Market Data TIX API Access!");
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "getVolatility");
|
||||
getVolatility:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw ctx.makeRuntimeErrorMsg("You don't have 4S Market Data TIX API Access!");
|
||||
}
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
return stock.mv / 100; // Convert from percentage to decimal
|
||||
},
|
||||
getForecast: function (_symbol: unknown): number {
|
||||
updateRam("getForecast");
|
||||
const symbol = helper.string("getForecast", "symbol", _symbol);
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw helper.makeRuntimeErrorMsg("getForecast", "You don't have 4S Market Data TIX API Access!");
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "getForecast");
|
||||
|
||||
let forecast = 50;
|
||||
stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag);
|
||||
return forecast / 100; // Convert from percentage to decimal
|
||||
},
|
||||
purchase4SMarketData: function (): boolean {
|
||||
updateRam("purchase4SMarketData");
|
||||
return stock.mv / 100; // Convert from percentage to decimal
|
||||
},
|
||||
getForecast:
|
||||
(ctx: NetscriptContext) =>
|
||||
(_symbol: unknown): number => {
|
||||
const symbol = ctx.helper.string("symbol", _symbol);
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw ctx.makeRuntimeErrorMsg("You don't have 4S Market Data TIX API Access!");
|
||||
}
|
||||
const stock = getStockFromSymbol(ctx, symbol);
|
||||
|
||||
let forecast = 50;
|
||||
stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag);
|
||||
return forecast / 100; // Convert from percentage to decimal
|
||||
},
|
||||
purchase4SMarketData: (ctx: NetscriptContext) => (): boolean => {
|
||||
if (player.has4SData) {
|
||||
workerScript.log("stock.purchase4SMarketData", () => "Already purchased 4S Market Data.");
|
||||
ctx.log(() => "Already purchased 4S Market Data.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.money < getStockMarket4SDataCost()) {
|
||||
workerScript.log("stock.purchase4SMarketData", () => "Not enough money to purchase 4S Market Data.");
|
||||
ctx.log(() => "Not enough money to purchase 4S Market Data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
player.has4SData = true;
|
||||
player.loseMoney(getStockMarket4SDataCost(), "stock");
|
||||
workerScript.log("stock.purchase4SMarketData", () => "Purchased 4S Market Data");
|
||||
ctx.log(() => "Purchased 4S Market Data");
|
||||
return true;
|
||||
},
|
||||
purchase4SMarketDataTixApi: function (): boolean {
|
||||
updateRam("purchase4SMarketDataTixApi");
|
||||
checkTixApiAccess("purchase4SMarketDataTixApi");
|
||||
purchase4SMarketDataTixApi: (ctx: NetscriptContext) => (): boolean => {
|
||||
checkTixApiAccess(ctx);
|
||||
|
||||
if (player.has4SDataTixApi) {
|
||||
workerScript.log("stock.purchase4SMarketDataTixApi", () => "Already purchased 4S Market Data TIX API");
|
||||
ctx.log(() => "Already purchased 4S Market Data TIX API");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.money < getStockMarket4STixApiCost()) {
|
||||
workerScript.log(
|
||||
"stock.purchase4SMarketDataTixApi",
|
||||
() => "Not enough money to purchase 4S Market Data TIX API",
|
||||
);
|
||||
ctx.log(() => "Not enough money to purchase 4S Market Data TIX API");
|
||||
return false;
|
||||
}
|
||||
|
||||
player.has4SDataTixApi = true;
|
||||
player.loseMoney(getStockMarket4STixApiCost(), "stock");
|
||||
workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API");
|
||||
ctx.log(() => "Purchased 4S Market Data TIX API");
|
||||
return true;
|
||||
},
|
||||
purchaseWseAccount: function (): boolean {
|
||||
updateRam("PurchaseWseAccount");
|
||||
|
||||
purchaseWseAccount: (ctx: NetscriptContext) => (): boolean => {
|
||||
if (player.hasWseAccount) {
|
||||
workerScript.log("stock.purchaseWseAccount", () => "Already purchased WSE Account");
|
||||
ctx.log(() => "Already purchased WSE Account");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.money < getStockMarketWseCost()) {
|
||||
workerScript.log("stock.purchaseWseAccount", () => "Not enough money to purchase WSE Account Access");
|
||||
ctx.log(() => "Not enough money to purchase WSE Account Access");
|
||||
return false;
|
||||
}
|
||||
|
||||
player.hasWseAccount = true;
|
||||
initStockMarketFn();
|
||||
player.loseMoney(getStockMarketWseCost(), "stock");
|
||||
workerScript.log("stock.purchaseWseAccount", () => "Purchased WSE Account Access");
|
||||
ctx.log(() => "Purchased WSE Account Access");
|
||||
return true;
|
||||
},
|
||||
purchaseTixApi: function (): boolean {
|
||||
updateRam("purchaseTixApi");
|
||||
|
||||
purchaseTixApi: (ctx: NetscriptContext) => (): boolean => {
|
||||
if (player.hasTixApiAccess) {
|
||||
workerScript.log("stock.purchaseTixApi", () => "Already purchased TIX API");
|
||||
ctx.log(() => "Already purchased TIX API");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player.money < getStockMarketTixApiCost()) {
|
||||
workerScript.log("stock.purchaseTixApi", () => "Not enough money to purchase TIX API Access");
|
||||
ctx.log(() => "Not enough money to purchase TIX API Access");
|
||||
return false;
|
||||
}
|
||||
|
||||
player.hasTixApiAccess = true;
|
||||
player.loseMoney(getStockMarketTixApiCost(), "stock");
|
||||
workerScript.log("stock.purchaseTixApi", () => "Purchased TIX API");
|
||||
ctx.log(() => "Purchased TIX API");
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
@ -1,7 +1,3 @@
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import {
|
||||
GameInfo,
|
||||
IStyleSettings,
|
||||
@ -14,88 +10,81 @@ import { defaultTheme } from "../Themes/Themes";
|
||||
import { defaultStyles } from "../Themes/Styles";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { hash } from "../hash/hash";
|
||||
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||
import { Terminal } from "../../src/Terminal";
|
||||
|
||||
export function NetscriptUserInterface(
|
||||
player: IPlayer,
|
||||
workerScript: WorkerScript,
|
||||
helper: INetscriptHelper,
|
||||
): IUserInterface {
|
||||
const updateRam = (funcName: string): void => helper.updateDynamicRam(funcName, getRamCost(player, "ui", funcName));
|
||||
export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
|
||||
return {
|
||||
getTheme: function (): UserInterfaceTheme {
|
||||
updateRam("getTheme");
|
||||
getTheme: () => (): UserInterfaceTheme => {
|
||||
return { ...Settings.theme };
|
||||
},
|
||||
|
||||
getStyles: function (): IStyleSettings {
|
||||
updateRam("getStyles");
|
||||
getStyles: () => (): IStyleSettings => {
|
||||
return { ...Settings.styles };
|
||||
},
|
||||
|
||||
setTheme: function (newTheme: UserInterfaceTheme): void {
|
||||
updateRam("setTheme");
|
||||
const hex = /^(#)((?:[A-Fa-f0-9]{2}){3,4}|(?:[A-Fa-f0-9]{3}))$/;
|
||||
const currentTheme = { ...Settings.theme };
|
||||
const errors: string[] = [];
|
||||
for (const key of Object.keys(newTheme)) {
|
||||
if (!currentTheme[key]) {
|
||||
// Invalid key
|
||||
errors.push(`Invalid key "${key}"`);
|
||||
} else if (!hex.test(newTheme[key] ?? "")) {
|
||||
errors.push(`Invalid color "${key}": ${newTheme[key]}`);
|
||||
} else {
|
||||
currentTheme[key] = newTheme[key];
|
||||
setTheme:
|
||||
(ctx: NetscriptContext) =>
|
||||
(newTheme: UserInterfaceTheme): void => {
|
||||
const hex = /^(#)((?:[A-Fa-f0-9]{2}){3,4}|(?:[A-Fa-f0-9]{3}))$/;
|
||||
const currentTheme = { ...Settings.theme };
|
||||
const errors: string[] = [];
|
||||
for (const key of Object.keys(newTheme)) {
|
||||
if (!currentTheme[key]) {
|
||||
// Invalid key
|
||||
errors.push(`Invalid key "${key}"`);
|
||||
} else if (!hex.test(newTheme[key] ?? "")) {
|
||||
errors.push(`Invalid color "${key}": ${newTheme[key]}`);
|
||||
} else {
|
||||
currentTheme[key] = newTheme[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length === 0) {
|
||||
Object.assign(Settings.theme, currentTheme);
|
||||
ThemeEvents.emit();
|
||||
workerScript.log("ui.setTheme", () => `Successfully set theme`);
|
||||
} else {
|
||||
workerScript.log("ui.setTheme", () => `Failed to set theme. Errors: ${errors.join(", ")}`);
|
||||
}
|
||||
},
|
||||
|
||||
setStyles: function (newStyles: IStyleSettings): void {
|
||||
updateRam("setStyles");
|
||||
|
||||
const currentStyles = { ...Settings.styles };
|
||||
const errors: string[] = [];
|
||||
for (const key of Object.keys(newStyles)) {
|
||||
if (!(currentStyles as any)[key]) {
|
||||
// Invalid key
|
||||
errors.push(`Invalid key "${key}"`);
|
||||
if (errors.length === 0) {
|
||||
Object.assign(Settings.theme, currentTheme);
|
||||
ThemeEvents.emit();
|
||||
ctx.log(() => `Successfully set theme`);
|
||||
} else {
|
||||
(currentStyles as any)[key] = (newStyles as any)[key];
|
||||
ctx.log(() => `Failed to set theme. Errors: ${errors.join(", ")}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
if (errors.length === 0) {
|
||||
Object.assign(Settings.styles, currentStyles);
|
||||
ThemeEvents.emit();
|
||||
workerScript.log("ui.setStyles", () => `Successfully set styles`);
|
||||
} else {
|
||||
workerScript.log("ui.setStyles", () => `Failed to set styles. Errors: ${errors.join(", ")}`);
|
||||
}
|
||||
},
|
||||
setStyles:
|
||||
(ctx: NetscriptContext) =>
|
||||
(newStyles: IStyleSettings): void => {
|
||||
const currentStyles = { ...Settings.styles };
|
||||
const errors: string[] = [];
|
||||
for (const key of Object.keys(newStyles)) {
|
||||
if (!(currentStyles as any)[key]) {
|
||||
// Invalid key
|
||||
errors.push(`Invalid key "${key}"`);
|
||||
} else {
|
||||
(currentStyles as any)[key] = (newStyles as any)[key];
|
||||
}
|
||||
}
|
||||
|
||||
resetTheme: function (): void {
|
||||
updateRam("resetTheme");
|
||||
if (errors.length === 0) {
|
||||
Object.assign(Settings.styles, currentStyles);
|
||||
ThemeEvents.emit();
|
||||
ctx.log(() => `Successfully set styles`);
|
||||
} else {
|
||||
ctx.log(() => `Failed to set styles. Errors: ${errors.join(", ")}`);
|
||||
}
|
||||
},
|
||||
|
||||
resetTheme: (ctx: NetscriptContext) => (): void => {
|
||||
Settings.theme = { ...defaultTheme };
|
||||
ThemeEvents.emit();
|
||||
workerScript.log("ui.resetTheme", () => `Reinitialized theme to default`);
|
||||
ctx.log(() => `Reinitialized theme to default`);
|
||||
},
|
||||
|
||||
resetStyles: function (): void {
|
||||
updateRam("resetStyles");
|
||||
resetStyles: (ctx: NetscriptContext) => (): void => {
|
||||
Settings.styles = { ...defaultStyles };
|
||||
ThemeEvents.emit();
|
||||
workerScript.log("ui.resetStyles", () => `Reinitialized styles to default`);
|
||||
ctx.log(() => `Reinitialized styles to default`);
|
||||
},
|
||||
|
||||
getGameInfo: function (): GameInfo {
|
||||
updateRam("getGameInfo");
|
||||
getGameInfo: () => (): GameInfo => {
|
||||
const version = CONSTANTS.VersionString;
|
||||
const commit = hash();
|
||||
const platform = navigator.userAgent.toLowerCase().indexOf(" electron/") > -1 ? "Steam" : "Browser";
|
||||
@ -108,5 +97,10 @@ export function NetscriptUserInterface(
|
||||
|
||||
return gameInfo;
|
||||
},
|
||||
|
||||
clearTerminal: (ctx: NetscriptContext) => (): void => {
|
||||
ctx.log(() => `Clearing terminal`);
|
||||
Terminal.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -532,7 +532,7 @@ function createAndAddWorkerScript(
|
||||
const oneRamUsage = getRamUsageFromRunningScript(runningScriptObj);
|
||||
const ramUsage = roundToTwo(oneRamUsage * threads);
|
||||
const ramAvailable = server.maxRam - server.ramUsed;
|
||||
if (ramUsage > ramAvailable) {
|
||||
if (ramUsage > ramAvailable + 0.001) {
|
||||
dialogBoxCreate(
|
||||
`Not enough RAM to run script ${runningScriptObj.filename} with args ` +
|
||||
`${arrayToString(runningScriptObj.args)}. This likely occurred because you re-loaded ` +
|
||||
@ -750,7 +750,7 @@ export function runScriptFromScript(
|
||||
if (server.hasAdminRights == false) {
|
||||
workerScript.log(caller, () => `You do not have root access on '${server.hostname}'`);
|
||||
return 0;
|
||||
} else if (ramUsage > ramAvailable) {
|
||||
} else if (ramUsage > ramAvailable + 0.001) {
|
||||
workerScript.log(
|
||||
caller,
|
||||
() =>
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { Construction, CheckBox, CheckBoxOutlineBlank } from "@mui/icons-material";
|
||||
import { CheckBox, CheckBoxOutlineBlank, Construction } from "@mui/icons-material";
|
||||
import { Box, Button, Container, List, ListItemButton, Paper, Typography } from "@mui/material";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Augmentation } from "../../../Augmentation/Augmentation";
|
||||
import { StaticAugmentations } from "../../../Augmentation/StaticAugmentations";
|
||||
import { AugmentationNames } from "../../../Augmentation/data/AugmentationNames";
|
||||
import { StaticAugmentations } from "../../../Augmentation/StaticAugmentations";
|
||||
import { CONSTANTS } from "../../../Constants";
|
||||
import { hasAugmentationPrereqs } from "../../../Faction/FactionHelpers";
|
||||
import { LocationName } from "../../../Locations/data/LocationNames";
|
||||
import { Locations } from "../../../Locations/Locations";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../../Settings/SettingEnums";
|
||||
import { Settings } from "../../../Settings/Settings";
|
||||
import { IMap } from "../../../types";
|
||||
import { use } from "../../../ui/Context";
|
||||
@ -15,8 +16,8 @@ import { ConfirmationModal } from "../../../ui/React/ConfirmationModal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { convertTimeMsToTimeElapsedString, formatNumber } from "../../../utils/StringHelperFunctions";
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../GraftingHelpers";
|
||||
import { GraftableAugmentation } from "../GraftableAugmentation";
|
||||
import { calculateGraftingTimeWithBonus, getGraftingAvailableAugs } from "../GraftingHelpers";
|
||||
|
||||
const GraftableAugmentations: IMap<GraftableAugmentation> = {};
|
||||
|
||||
@ -69,6 +70,21 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
const getAugsSorted = (): string[] => {
|
||||
const augs = getGraftingAvailableAugs(player);
|
||||
switch (Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost:
|
||||
return augs.sort((a, b) => GraftableAugmentations[a].cost - GraftableAugmentations[b].cost);
|
||||
default:
|
||||
return augs;
|
||||
}
|
||||
};
|
||||
|
||||
const switchSortOrder = (newOrder: PurchaseAugmentationsOrderSetting): void => {
|
||||
Settings.PurchaseAugmentationsOrder = newOrder;
|
||||
rerender();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, 200);
|
||||
return () => clearInterval(id);
|
||||
@ -91,13 +107,31 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ my: 3 }}>
|
||||
<Typography variant="h5">Graft Augmentations</Typography>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5">Graft Augmentations</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
|
||||
<Button sx={{ width: "100%" }} onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>
|
||||
Sort by Cost
|
||||
</Button>
|
||||
<Button sx={{ width: "100%" }} onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>
|
||||
Sort by Default Order
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
{getGraftingAvailableAugs(player).length > 0 ? (
|
||||
<Paper sx={{ my: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||
<Paper sx={{ mb: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
|
||||
{getGraftingAvailableAugs(player).map((k, i) => (
|
||||
{getAugsSorted().map((k, i) => (
|
||||
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
|
||||
<Typography>{k}</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
color: canGraft(player, GraftableAugmentations[k])
|
||||
? Settings.theme.primary
|
||||
: Settings.theme.disabled,
|
||||
}}
|
||||
>
|
||||
{k}
|
||||
</Typography>
|
||||
</ListItemButton>
|
||||
))}
|
||||
</List>
|
||||
|
@ -13,7 +13,7 @@ import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/A
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
|
||||
export function hasTorRouter(this: IPlayer): boolean {
|
||||
return !!GetServer(SpecialServers.DarkWeb);
|
||||
return this.getHomeComputer().serversOnNetwork.includes(SpecialServers.DarkWeb);
|
||||
}
|
||||
|
||||
export function getCurrentServer(this: IPlayer): BaseServer {
|
||||
|
@ -4,7 +4,14 @@ import { CONSTANTS } from "./Constants";
|
||||
import { Factions, loadFactions } from "./Faction/Factions";
|
||||
import { loadAllGangs, AllGangs } from "./Gang/AllGangs";
|
||||
import { Player, loadPlayer } from "./Player";
|
||||
import { saveAllServers, loadAllServers, GetAllServers } from "./Server/AllServers";
|
||||
import {
|
||||
saveAllServers,
|
||||
loadAllServers,
|
||||
GetAllServers,
|
||||
createUniqueRandomIp,
|
||||
AddToAllServers,
|
||||
GetServer,
|
||||
} from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
|
||||
import { staneksGift, loadStaneksGift } from "./CotMG/Helper";
|
||||
@ -26,6 +33,8 @@ import { pushGameSaved } from "./Electron";
|
||||
import { defaultMonacoTheme } from "./ScriptEditor/ui/themes";
|
||||
import { FactionNames } from "./Faction/data/FactionNames";
|
||||
import { Faction } from "./Faction/Faction";
|
||||
import { safetlyCreateUniqueServer } from "./Server/ServerHelpers";
|
||||
import { SpecialServers } from "./Server/data/SpecialServers";
|
||||
|
||||
/* SaveObject.js
|
||||
* Defines the object used to save/load games
|
||||
@ -434,6 +443,22 @@ function evaluateVersionCompatibility(ver: string | number): void {
|
||||
Player.reapplyAllAugmentations(true);
|
||||
Player.reapplyAllSourceFiles();
|
||||
}
|
||||
if (ver < 18) {
|
||||
// Create the darkweb for everyone but it won't be linked
|
||||
const dw = GetServer(SpecialServers.DarkWeb);
|
||||
if (!dw) {
|
||||
const darkweb = safetlyCreateUniqueServer({
|
||||
ip: createUniqueRandomIp(),
|
||||
hostname: SpecialServers.DarkWeb,
|
||||
organizationName: "",
|
||||
isConnectedTo: false,
|
||||
adminRights: false,
|
||||
purchasedByPlayer: false,
|
||||
maxRam: 1,
|
||||
});
|
||||
AddToAllServers(darkweb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
24
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
24
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -560,7 +560,7 @@ export interface BitNodeMultipliers {
|
||||
/** Influences how much money the player earns when completing working their job. */
|
||||
CompanyWorkMoney: number;
|
||||
/** Influences the money gain from dividends of corporations created by the player. */
|
||||
CorporationSoftCap: number;
|
||||
CorporationSoftcap: number;
|
||||
/** Influences the valuation of corporations created by the player. */
|
||||
CorporationValuation: number;
|
||||
/** Influences the base experience gained for each ability when the player commits a crime. */
|
||||
@ -4405,6 +4405,13 @@ interface UserInterface {
|
||||
* RAM cost: 0 GB
|
||||
*/
|
||||
getGameInfo(): GameInfo;
|
||||
|
||||
/**
|
||||
* Clear the Terminal window, as if the player ran `clear` in the terminal
|
||||
* @remarks
|
||||
* RAM cost: 0.2 GB
|
||||
*/
|
||||
clearTerminal(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4988,6 +4995,21 @@ export interface NS {
|
||||
*/
|
||||
tail(fn?: FilenameOrPID, host?: string, ...args: any[]): void;
|
||||
|
||||
/**
|
||||
* Close the tail window of a script.
|
||||
* @remarks
|
||||
* RAM cost: 0 GB
|
||||
*
|
||||
* Closes a script’s logs. This is functionally the same pressing the "Close" button on the tail window.
|
||||
*
|
||||
* If the function is called with no arguments, it will close the current script’s logs.
|
||||
*
|
||||
* Otherwise, the pid argument can be used to close the logs from another script.
|
||||
*
|
||||
* @param pid - Optional. PID of the script having its tail closed. If omitted, the current script is used.
|
||||
*/
|
||||
closeTail(pid?: number): void;
|
||||
|
||||
/**
|
||||
* Get the list of servers connected to a server.
|
||||
* @remarks
|
||||
|
@ -1565,4 +1565,12 @@ export const serverMetadata: IServerMetadata[] = [
|
||||
serverGrowth: 0,
|
||||
specialName: SpecialServers.WorldDaemon,
|
||||
},
|
||||
{
|
||||
hostname: SpecialServers.DarkWeb,
|
||||
moneyAvailable: 0,
|
||||
numOpenPortsRequired: 5,
|
||||
organizationName: SpecialServers.DarkWeb,
|
||||
requiredHackingSkill: 1,
|
||||
specialName: SpecialServers.DarkWeb,
|
||||
},
|
||||
];
|
||||
|
@ -54,6 +54,11 @@ interface IDefaultSettings {
|
||||
*/
|
||||
EnableBashHotkeys: boolean;
|
||||
|
||||
/**
|
||||
* Infinite loop safety net
|
||||
*/
|
||||
InfinityLoopSafety: boolean;
|
||||
|
||||
/**
|
||||
* Timestamps format
|
||||
*/
|
||||
@ -201,6 +206,7 @@ export const defaultSettings: IDefaultSettings = {
|
||||
DisableOverviewProgressBars: false,
|
||||
EnableBashHotkeys: false,
|
||||
TimestampsFormat: "",
|
||||
InfinityLoopSafety: true,
|
||||
Locale: "en",
|
||||
MaxRecentScriptsCapacity: 50,
|
||||
MaxLogCapacity: 50,
|
||||
@ -241,6 +247,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
DisableOverviewProgressBars: defaultSettings.DisableOverviewProgressBars,
|
||||
EnableBashHotkeys: defaultSettings.EnableBashHotkeys,
|
||||
TimestampsFormat: defaultSettings.TimestampsFormat,
|
||||
InfinityLoopSafety: defaultSettings.InfinityLoopSafety,
|
||||
Locale: "en",
|
||||
MaxRecentScriptsCapacity: defaultSettings.MaxRecentScriptsCapacity,
|
||||
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
||||
|
@ -67,8 +67,18 @@ SourceFiles["SourceFile5"] = new SourceFile(
|
||||
This Source-File grants a special new stat called Intelligence. Intelligence is unique because it is permanent and
|
||||
persistent (it never gets reset back to 1). However, gaining Intelligence experience is much slower than other
|
||||
stats. Higher Intelligence levels will boost your production for many actions in the game. In addition, this
|
||||
Source-File will unlock the getBitNodeMultipliers() Netscript function and let you start with Formulas.exe, and
|
||||
will raise all of your hacking-related multipliers by:
|
||||
Source-File will unlock:
|
||||
<br />
|
||||
<ul>
|
||||
<li>
|
||||
The <code>getBitNodeMultipliers()</code> Netscript function
|
||||
</li>
|
||||
<li>Permanent access to Formulas.exe</li>
|
||||
<li>
|
||||
Access to BitNode multiplier information on the <b>Stats</b> page
|
||||
</li>
|
||||
</ul>
|
||||
It will also raise all of your hacking-related multipliers by:
|
||||
<br />
|
||||
<br />
|
||||
Level 1: 8%
|
||||
|
@ -49,9 +49,11 @@ export function isValidFilename(filename: string): boolean {
|
||||
* not an entire path
|
||||
*/
|
||||
export function isValidDirectoryName(name: string): boolean {
|
||||
// Allows alphanumerics, hyphens, underscores, and percentage signs.
|
||||
// Name can begin with a single period, but otherwise cannot have any
|
||||
const regex = /^.?[a-zA-Z0-9_-]+$/;
|
||||
// A valid directory name:
|
||||
// Must be at least 1 character long
|
||||
// Can only include characters in the character set [-.%a-zA-Z0-9_]
|
||||
// Cannot end with a '.'
|
||||
const regex = /^(?:[-.%]|\w)*[-%a-zA-Z0-9_]$/;
|
||||
|
||||
// match() returns null if no match is found
|
||||
return name.match(regex) != null;
|
||||
|
@ -463,6 +463,12 @@ export class Terminal implements ITerminal {
|
||||
this.contractOpen = true;
|
||||
const res = await contract.prompt();
|
||||
|
||||
//Check if the contract still exists by the time the promise is fullfilled
|
||||
if (serv.getContract(contractName) == null) {
|
||||
this.contractOpen = false;
|
||||
return this.error("Contract no longer exists (Was it solved by a script?)");
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case CodingContractResult.Success:
|
||||
if (contract.reward !== null) {
|
||||
|
@ -66,6 +66,13 @@ export function mv(
|
||||
|
||||
if (destFile != null) {
|
||||
// Already exists, will be overwritten, so we'll delete it
|
||||
|
||||
// Command doesnt work if script is running
|
||||
if (server.isRunning(destPath)) {
|
||||
terminal.error(`Cannot use 'mv' on a script that is running`);
|
||||
return;
|
||||
}
|
||||
|
||||
const status = server.removeFile(destPath);
|
||||
if (!status.res) {
|
||||
terminal.error(`Something went wrong...please contact game dev (probably a bug)`);
|
||||
|
@ -63,13 +63,11 @@ export function runScript(
|
||||
return;
|
||||
}
|
||||
|
||||
if (ramUsage > ramAvailable) {
|
||||
if (ramUsage > ramAvailable + 0.001) {
|
||||
terminal.error(
|
||||
"This machine does not have enough RAM to run this script with " +
|
||||
numThreads +
|
||||
" threads. Script requires " +
|
||||
numeralWrapper.formatRAM(ramUsage) +
|
||||
" of RAM",
|
||||
"This machine does not have enough RAM to run this script" +
|
||||
(numThreads === 1 ? "" : ` with ${numThreads} threads`) +
|
||||
`. Script requires ${numeralWrapper.formatRAM(ramUsage)} of RAM`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -1382,7 +1382,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
return [n + m, edges];
|
||||
},
|
||||
solver: (data: [number, [number, number][]], ans: string): boolean => {
|
||||
//Case where the player believes there is no solution
|
||||
//Case where the player believes there is no solution.
|
||||
//Attempt to construct one to check if this is correct.
|
||||
if (ans == "[]") {
|
||||
//Helper function to get neighbourhood of a vertex
|
||||
function neighbourhood(vertex: number): number[] {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Paper, Table, TableBody, Box, IconButton, Typography, Container, Tooltip } from "@mui/material";
|
||||
import { MoreHoriz, Info } from "@mui/icons-material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BitNodes } from "../BitNode/BitNode";
|
||||
import { BitNodes, defaultMultipliers, getBitNodeMultipliers } from "../BitNode/BitNode";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { BitNodeMultipliersDisplay } from "../BitNode/ui/BitnodeMultipliersDescription";
|
||||
import { HacknetServerConstants } from "../Hacknet/data/Constants";
|
||||
import { getPurchaseServerLimit } from "../Server/ServerPurchases";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
@ -14,6 +15,7 @@ import { Modal } from "./React/Modal";
|
||||
import { Money } from "./React/Money";
|
||||
import { StatsRow } from "./React/StatsRow";
|
||||
import { StatsTable } from "./React/StatsTable";
|
||||
import { isEqual } from "lodash";
|
||||
|
||||
interface EmployersModalProps {
|
||||
open: boolean;
|
||||
@ -36,8 +38,22 @@ const EmployersModal = ({ open, onClose }: EmployersModalProps): React.ReactElem
|
||||
);
|
||||
};
|
||||
|
||||
interface IMultRow {
|
||||
// The name of the multiplier
|
||||
mult: string;
|
||||
|
||||
// The player's raw multiplier value
|
||||
value: number;
|
||||
|
||||
// The player's effective multiplier value, affected by BitNode mults
|
||||
effValue?: number;
|
||||
|
||||
// The text color for the row
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface MultTableProps {
|
||||
rows: (string | number)[][];
|
||||
rows: IMultRow[];
|
||||
color: string;
|
||||
noMargin?: boolean;
|
||||
}
|
||||
@ -48,29 +64,22 @@ function MultiplierTable(props: MultTableProps): React.ReactElement {
|
||||
<Table sx={{ display: "table", width: "100%", mb: (props.noMargin ?? false) === true ? 0 : 2 }}>
|
||||
<TableBody>
|
||||
{props.rows.map((data) => {
|
||||
const mult = data[0] as string,
|
||||
value = data[1] as number,
|
||||
modded = data[2] as number | null;
|
||||
const { mult, value, effValue = null, color = props.color } = data;
|
||||
|
||||
if (modded && modded !== value && player.sourceFileLvl(5) > 0) {
|
||||
if (effValue !== null && effValue !== value && player.sourceFileLvl(5) > 0) {
|
||||
return (
|
||||
<StatsRow key={mult} name={mult} color={props.color} data={{}}>
|
||||
<StatsRow key={mult} name={mult} color={color} data={{}}>
|
||||
<>
|
||||
<Typography color={props.color}>
|
||||
<Typography color={color}>
|
||||
<span style={{ opacity: 0.5 }}>{numeralWrapper.formatPercentage(value)}</span>{" "}
|
||||
{numeralWrapper.formatPercentage(modded)}
|
||||
{numeralWrapper.formatPercentage(effValue)}
|
||||
</Typography>
|
||||
</>
|
||||
</StatsRow>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<StatsRow
|
||||
key={mult}
|
||||
name={mult}
|
||||
color={props.color}
|
||||
data={{ content: numeralWrapper.formatPercentage(value) }}
|
||||
/>
|
||||
<StatsRow key={mult} name={mult} color={color} data={{ content: numeralWrapper.formatPercentage(value) }} />
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
@ -82,16 +91,14 @@ function CurrentBitNode(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
if (player.sourceFiles.length > 0) {
|
||||
const index = "BitNode" + player.bitNodeN;
|
||||
const lvl = player.sourceFileLvl(player.bitNodeN) + 1;
|
||||
const lvl = Math.min(player.sourceFileLvl(player.bitNodeN) + 1, player.bitNodeN === 12 ? Infinity : 3);
|
||||
return (
|
||||
<Box>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5">
|
||||
BitNode {player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
|
||||
</Typography>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Paper sx={{ mb: 1, p: 1 }}>
|
||||
<Typography variant="h5">
|
||||
BitNode {player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
|
||||
</Typography>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
@ -218,6 +225,14 @@ export function CharacterStats(): React.ReactElement {
|
||||
}
|
||||
timeRows.push(["Total", convertTimeMsToTimeElapsedString(player.totalPlaytime)]);
|
||||
|
||||
let showBitNodeMults = false;
|
||||
if (player.sourceFileLvl(5) > 0) {
|
||||
const n = player.bitNodeN;
|
||||
const maxSfLevel = n === 12 ? Infinity : 3;
|
||||
const mults = getBitNodeMultipliers(n, Math.min(player.sourceFileLvl(n) + 1, maxSfLevel));
|
||||
showBitNodeMults = !isEqual(mults, defaultMultipliers);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
|
||||
<Typography variant="h4">Stats</Typography>
|
||||
@ -332,186 +347,255 @@ export function CharacterStats(): React.ReactElement {
|
||||
</Table>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Box sx={{ mb: 1 }}>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
Multipliers
|
||||
{player.sourceFileLvl(5) > 0 && (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Displays your current multipliers.
|
||||
<br />
|
||||
<br />
|
||||
When there is a dim number next to a multiplier, that means that the multiplier in question is being
|
||||
affected by BitNode multipliers.
|
||||
<br />
|
||||
<br />
|
||||
The dim number is the raw multiplier, and the undimmed number is the effective multiplier, as
|
||||
dictated by the BitNode.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1 }}>
|
||||
<Box>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Hacking Chance", player.hacking_chance_mult],
|
||||
["Hacking Speed", player.hacking_speed_mult],
|
||||
[
|
||||
"Hacking Money",
|
||||
player.hacking_money_mult,
|
||||
player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
|
||||
],
|
||||
[
|
||||
"Hacking Growth",
|
||||
player.hacking_grow_mult,
|
||||
player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
|
||||
],
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Hacking Level",
|
||||
player.hacking_mult,
|
||||
player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
|
||||
],
|
||||
[
|
||||
"Hacking Experience",
|
||||
player.hacking_exp_mult,
|
||||
player.hacking_exp_mult * BitNodeMultipliers.HackExpGain,
|
||||
],
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Strength Level",
|
||||
player.strength_mult,
|
||||
player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
],
|
||||
["Strength Experience", player.strength_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Defense Level",
|
||||
player.defense_mult,
|
||||
player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
],
|
||||
["Defense Experience", player.defense_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Dexterity Level",
|
||||
player.dexterity_mult,
|
||||
player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
],
|
||||
["Dexterity Experience", player.dexterity_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Agility Level",
|
||||
player.agility_mult,
|
||||
player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
],
|
||||
["Agility Experience", player.agility_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Charisma Level",
|
||||
player.charisma_mult,
|
||||
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
],
|
||||
["Charisma Experience", player.charisma_exp_mult],
|
||||
]}
|
||||
color={Settings.theme.cha}
|
||||
noMargin
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||
Multipliers
|
||||
{player.sourceFileLvl(5) > 0 && (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Displays your current multipliers.
|
||||
<br />
|
||||
<br />
|
||||
When there is a dim number next to a multiplier, that means that the multiplier in question is being
|
||||
affected by BitNode multipliers.
|
||||
<br />
|
||||
<br />
|
||||
The dim number is the raw multiplier, and the undimmed number is the effective multiplier, as dictated
|
||||
by the BitNode.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1 }}>
|
||||
<Box>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Hacking Chance",
|
||||
value: player.hacking_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Speed",
|
||||
value: player.hacking_speed_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Money",
|
||||
value: player.hacking_money_mult,
|
||||
effValue: player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Growth",
|
||||
value: player.hacking_grow_mult,
|
||||
effValue: player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Hacking Level",
|
||||
value: player.hacking_mult,
|
||||
effValue: player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Hacking Experience",
|
||||
value: player.hacking_exp_mult,
|
||||
effValue: player.hacking_exp_mult * BitNodeMultipliers.HackExpGain,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.hack}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Strength Level",
|
||||
value: player.strength_mult,
|
||||
effValue: player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Strength Experience",
|
||||
value: player.strength_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Defense Level",
|
||||
value: player.defense_mult,
|
||||
effValue: player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Defense Experience",
|
||||
value: player.defense_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Dexterity Level",
|
||||
value: player.dexterity_mult,
|
||||
effValue: player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Dexterity Experience",
|
||||
value: player.dexterity_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Agility Level",
|
||||
value: player.agility_mult,
|
||||
effValue: player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Agility Experience",
|
||||
value: player.agility_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Charisma Level",
|
||||
value: player.charisma_mult,
|
||||
effValue: player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||
},
|
||||
{
|
||||
mult: "Charisma Experience",
|
||||
value: player.charisma_exp_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.cha}
|
||||
noMargin
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Hacknet Node Production",
|
||||
value: player.hacknet_node_money_mult,
|
||||
effValue: player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Purchase Cost",
|
||||
value: player.hacknet_node_purchase_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node RAM Upgrade Cost",
|
||||
value: player.hacknet_node_ram_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Core Purchase Cost",
|
||||
value: player.hacknet_node_core_cost_mult,
|
||||
},
|
||||
{
|
||||
mult: "Hacknet Node Level Upgrade Cost",
|
||||
value: player.hacknet_node_level_cost_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.primary}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Company Reputation Gain",
|
||||
value: player.company_rep_mult,
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
{
|
||||
mult: "Faction Reputation Gain",
|
||||
value: player.faction_rep_mult,
|
||||
effValue: player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
|
||||
color: Settings.theme.rep,
|
||||
},
|
||||
{
|
||||
mult: "Salary",
|
||||
value: player.work_money_mult,
|
||||
effValue: player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.money}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
{
|
||||
mult: "Crime Success Chance",
|
||||
value: player.crime_success_mult,
|
||||
},
|
||||
{
|
||||
mult: "Crime Money",
|
||||
value: player.crime_money_mult,
|
||||
effValue: player.crime_money_mult * BitNodeMultipliers.CrimeMoney,
|
||||
color: Settings.theme.money,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
{player.canAccessBladeburner() && (
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
[
|
||||
"Hacknet Node production",
|
||||
player.hacknet_node_money_mult,
|
||||
player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
|
||||
],
|
||||
["Hacknet Node purchase cost", player.hacknet_node_purchase_cost_mult],
|
||||
["Hacknet Node RAM upgrade cost", player.hacknet_node_ram_cost_mult],
|
||||
["Hacknet Node Core purchase cost", player.hacknet_node_core_cost_mult],
|
||||
["Hacknet Node level upgrade cost", player.hacknet_node_level_cost_mult],
|
||||
{
|
||||
mult: "Bladeburner Success Chance",
|
||||
value: player.bladeburner_success_chance_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Max Stamina",
|
||||
value: player.bladeburner_max_stamina_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Stamina Gain",
|
||||
value: player.bladeburner_stamina_gain_mult,
|
||||
},
|
||||
{
|
||||
mult: "Bladeburner Field Analysis",
|
||||
value: player.bladeburner_analysis_mult,
|
||||
},
|
||||
]}
|
||||
color={Settings.theme.primary}
|
||||
noMargin
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Company reputation gain", player.company_rep_mult],
|
||||
[
|
||||
"Faction reputation gain",
|
||||
player.faction_rep_mult,
|
||||
player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
|
||||
],
|
||||
["Salary", player.work_money_mult, player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney],
|
||||
]}
|
||||
color={Settings.theme.money}
|
||||
/>
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Crime success", player.crime_success_mult],
|
||||
["Crime money", player.crime_money_mult, player.crime_money_mult * BitNodeMultipliers.CrimeMoney],
|
||||
]}
|
||||
color={Settings.theme.combat}
|
||||
/>
|
||||
{player.canAccessBladeburner() && (
|
||||
<MultiplierTable
|
||||
rows={[
|
||||
["Bladeburner Success Chance", player.bladeburner_success_chance_mult],
|
||||
["Bladeburner Max Stamina", player.bladeburner_max_stamina_mult],
|
||||
["Bladeburner Stamina Gain", player.bladeburner_stamina_gain_mult],
|
||||
["Bladeburner Field Analysis", player.bladeburner_analysis_mult],
|
||||
]}
|
||||
color={Settings.theme.primary}
|
||||
noMargin
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography variant="h5">Time Played</Typography>
|
||||
<Table>
|
||||
<TableBody>
|
||||
{timeRows.map(([name, content]) => (
|
||||
<StatsRow key={name} name={name} color={Settings.theme.primary} data={{ content: content }} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
|
||||
<Box sx={{ mb: 1 }}>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography variant="h5">Time Played</Typography>
|
||||
<Table>
|
||||
<TableBody>
|
||||
{timeRows.map(([name, content]) => (
|
||||
<StatsRow key={name} name={name} color={Settings.theme.primary} data={{ content: content }} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
</Box>
|
||||
<CurrentBitNode />
|
||||
|
||||
{showBitNodeMults && (
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography variant="h5">BitNode Multipliers</Typography>
|
||||
<BitNodeMultipliersDisplay n={player.bitNodeN} />
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
<MoneyModal open={moneyOpen} onClose={() => setMoneyOpen(false)} />
|
||||
<EmployersModal open={employersOpen} onClose={() => setEmployersOpen(false)} />
|
||||
</Container>
|
||||
|
@ -35,7 +35,7 @@ export function NSSelection(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Modal open={props.open} onClose={props.onClose} sx={{ zIndex: 999999 }}>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
|
||||
<Tab label="NS1" />
|
||||
<Tab label="NS2" />
|
||||
|
@ -18,10 +18,12 @@ import { Theme } from "@mui/material";
|
||||
import { findRunningScript } from "../../Script/ScriptHelpers";
|
||||
import { Player } from "../../Player";
|
||||
import { debounce } from "lodash";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
let layerCounter = 0;
|
||||
|
||||
export const LogBoxEvents = new EventEmitter<[RunningScript]>();
|
||||
export const LogBoxCloserEvents = new EventEmitter<[number]>();
|
||||
export const LogBoxClearEvents = new EventEmitter<[]>();
|
||||
|
||||
interface Log {
|
||||
@ -50,6 +52,15 @@ export function LogBoxManager(): React.ReactElement {
|
||||
[],
|
||||
);
|
||||
|
||||
//Event used by ns.closeTail to close tail windows
|
||||
useEffect(
|
||||
() =>
|
||||
LogBoxCloserEvents.subscribe((pid: number) => {
|
||||
closePid(pid);
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() =>
|
||||
LogBoxClearEvents.subscribe(() => {
|
||||
logs = [];
|
||||
@ -57,11 +68,18 @@ export function LogBoxManager(): React.ReactElement {
|
||||
}),
|
||||
);
|
||||
|
||||
//Close tail windows by their id
|
||||
function close(id: string): void {
|
||||
logs = logs.filter((l) => l.id !== id);
|
||||
rerender();
|
||||
}
|
||||
|
||||
//Close tail windows by their pid
|
||||
function closePid(pid: number): void {
|
||||
logs = logs.filter((log) => log.script.pid != pid);
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{logs.map((log) => (
|
||||
@ -77,42 +95,18 @@ interface IProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
const useStyles = makeStyles((_theme: Theme) =>
|
||||
createStyles({
|
||||
title: {
|
||||
"&.is-minimized + *": {
|
||||
border: "none",
|
||||
margin: 0,
|
||||
"max-height": 0,
|
||||
padding: 0,
|
||||
"pointer-events": "none",
|
||||
visibility: "hidden",
|
||||
},
|
||||
},
|
||||
logs: {
|
||||
overflowY: "scroll",
|
||||
overflowX: "hidden",
|
||||
scrollbarWidth: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column-reverse",
|
||||
whiteSpace: "pre-wrap",
|
||||
},
|
||||
titleButton: {
|
||||
padding: "1px 6px",
|
||||
},
|
||||
success: {
|
||||
color: theme.colors.success,
|
||||
},
|
||||
error: {
|
||||
color: theme.palette.error.main,
|
||||
},
|
||||
primary: {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
info: {
|
||||
color: theme.palette.info.main,
|
||||
},
|
||||
warning: {
|
||||
color: theme.palette.warning.main,
|
||||
padding: "1px 0",
|
||||
height: "100%",
|
||||
},
|
||||
}),
|
||||
);
|
||||
@ -190,20 +184,20 @@ function LogWindow(props: IProps): React.ReactElement {
|
||||
setMinimized(!minimized);
|
||||
}
|
||||
|
||||
function lineClass(s: string): string {
|
||||
function lineColor(s: string): string {
|
||||
if (s.match(/(^\[[^\]]+\] )?ERROR/) || s.match(/(^\[[^\]]+\] )?FAIL/)) {
|
||||
return classes.error;
|
||||
return Settings.theme.error;
|
||||
}
|
||||
if (s.match(/(^\[[^\]]+\] )?SUCCESS/)) {
|
||||
return classes.success;
|
||||
return Settings.theme.success;
|
||||
}
|
||||
if (s.match(/(^\[[^\]]+\] )?WARN/)) {
|
||||
return classes.warning;
|
||||
return Settings.theme.warning;
|
||||
}
|
||||
if (s.match(/(^\[[^\]]+\] )?INFO/)) {
|
||||
return classes.info;
|
||||
return Settings.theme.info;
|
||||
}
|
||||
return classes.primary;
|
||||
return Settings.theme.primary;
|
||||
}
|
||||
|
||||
// And trigger fakeDrag when the window is resized
|
||||
@ -242,74 +236,99 @@ function LogWindow(props: IProps): React.ReactElement {
|
||||
if (e.clientX < 0 || e.clientY < 0 || e.clientX > innerWidth || e.clientY > innerHeight) return false;
|
||||
};
|
||||
|
||||
// Max [width, height]
|
||||
const minConstraints: [number, number] = [250, 33];
|
||||
|
||||
return (
|
||||
<Draggable handle=".drag" onDrag={boundToBody} ref={rootRef}>
|
||||
<Paper
|
||||
style={{
|
||||
display: "flex",
|
||||
<Draggable handle=".drag" onDrag={boundToBody} ref={rootRef} onMouseDown={updateLayer}>
|
||||
<Box
|
||||
display="flex"
|
||||
sx={{
|
||||
flexFlow: "column",
|
||||
position: "fixed",
|
||||
left: "40%",
|
||||
top: "30%",
|
||||
zIndex: 1400,
|
||||
minWidth: `${minConstraints[0]}px`,
|
||||
minHeight: `${minConstraints[1]}px`,
|
||||
...(minimized
|
||||
? {
|
||||
border: "none",
|
||||
margin: 0,
|
||||
maxHeight: 0,
|
||||
padding: 0,
|
||||
}
|
||||
: {
|
||||
border: `1px solid ${Settings.theme.welllight}`,
|
||||
}),
|
||||
}}
|
||||
ref={container}
|
||||
>
|
||||
<div onMouseDown={updateLayer}>
|
||||
<Paper
|
||||
className={classes.title + " " + (minimized ? "is-minimized" : "")}
|
||||
style={{
|
||||
cursor: "grab",
|
||||
}}
|
||||
>
|
||||
<Box className="drag" display="flex" alignItems="center" ref={draggableRef}>
|
||||
<Typography color="primary" variant="h6" sx={{ marginRight: "auto" }} title={title(true)}>
|
||||
{title()}
|
||||
<ResizableBox
|
||||
height={500}
|
||||
width={500}
|
||||
minConstraints={minConstraints}
|
||||
handle={
|
||||
<span
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: "-10px",
|
||||
bottom: "-16px",
|
||||
cursor: "nw-resize",
|
||||
display: minimized ? "none" : "inline-block",
|
||||
}}
|
||||
>
|
||||
<ArrowForwardIosIcon color="primary" style={{ transform: "rotate(45deg)", fontSize: "1.75rem" }} />
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<Paper className="drag" sx={{ display: "flex", alignItems: "center", cursor: "grab" }} ref={draggableRef}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ marginRight: "auto", textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden" }}
|
||||
title={title(true)}
|
||||
>
|
||||
{title(true)}
|
||||
</Typography>
|
||||
|
||||
{!workerScripts.has(script.pid) ? (
|
||||
<Button className={classes.titleButton} onClick={run} onTouchEnd={run}>
|
||||
Run
|
||||
<span style={{ minWidth: "fit-content", height: `${minConstraints[1]}px` }}>
|
||||
{!workerScripts.has(script.pid) ? (
|
||||
<Button className={classes.titleButton} onClick={run} onTouchEnd={run}>
|
||||
Run
|
||||
</Button>
|
||||
) : (
|
||||
<Button className={classes.titleButton} onClick={kill} onTouchEnd={kill}>
|
||||
Kill
|
||||
</Button>
|
||||
)}
|
||||
<Button className={classes.titleButton} onClick={minimize} onTouchEnd={minimize}>
|
||||
{minimized ? "\u{1F5D6}" : "\u{1F5D5}"}
|
||||
</Button>
|
||||
) : (
|
||||
<Button className={classes.titleButton} onClick={kill} onTouchEnd={kill}>
|
||||
Kill
|
||||
<Button className={classes.titleButton} onClick={props.onClose} onTouchEnd={props.onClose}>
|
||||
Close
|
||||
</Button>
|
||||
)}
|
||||
<Button className={classes.titleButton} onClick={minimize} onTouchEnd={minimize}>
|
||||
{minimized ? "\u{1F5D6}" : "\u{1F5D5}"}
|
||||
</Button>
|
||||
<Button className={classes.titleButton} onClick={props.onClose} onTouchEnd={props.onClose}>
|
||||
Close
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Paper sx={{ overflow: "scroll", overflowWrap: "break-word", whiteSpace: "pre-wrap" }}>
|
||||
<ResizableBox
|
||||
</span>
|
||||
</Paper>
|
||||
|
||||
<Paper
|
||||
className={classes.logs}
|
||||
height={500}
|
||||
width={500}
|
||||
minConstraints={[250, 30]}
|
||||
handle={
|
||||
<span style={{ position: "absolute", right: "-10px", bottom: "-13px", cursor: "nw-resize" }}>
|
||||
<ArrowForwardIosIcon color="primary" style={{ transform: "rotate(45deg)" }} />
|
||||
</span>
|
||||
}
|
||||
sx={{ height: `calc(100% - ${minConstraints[1]}px)`, display: minimized ? "none" : "flex" }}
|
||||
>
|
||||
<Box>
|
||||
<span style={{ display: "flex", flexDirection: "column" }}>
|
||||
{script.logs.map(
|
||||
(line: string, i: number): JSX.Element => (
|
||||
<Typography key={i} className={lineClass(line)}>
|
||||
<Typography key={i} sx={{ color: lineColor(line) }}>
|
||||
{line}
|
||||
<br />
|
||||
</Typography>
|
||||
),
|
||||
)}
|
||||
</Box>
|
||||
</ResizableBox>
|
||||
</Paper>
|
||||
</div>
|
||||
</Paper>
|
||||
</span>
|
||||
</Paper>
|
||||
</>
|
||||
</ResizableBox>
|
||||
</Box>
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
import React from "react";
|
||||
import { Theme } from "@mui/material";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import M from "@mui/material/Modal";
|
||||
import Fade from "@mui/material/Fade";
|
||||
import Box from "@mui/material/Box";
|
||||
import Fade from "@mui/material/Fade";
|
||||
import M from "@mui/material/Modal";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { SxProps } from "@mui/system";
|
||||
import React from "react";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@ -12,7 +13,6 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 999999,
|
||||
},
|
||||
paper: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
@ -35,6 +35,7 @@ interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
children: React.ReactNode;
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
export const Modal = (props: IProps): React.ReactElement => {
|
||||
@ -49,6 +50,7 @@ export const Modal = (props: IProps): React.ReactElement => {
|
||||
onClose={props.onClose}
|
||||
closeAfterTransition
|
||||
className={classes.modal}
|
||||
sx={props.sx}
|
||||
>
|
||||
<Fade in={props.open}>
|
||||
<div className={classes.paper}>
|
||||
|
9
test/cypress/tsconfig.json
Normal file
9
test/cypress/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
"types": ["cypress", "@testing-library/cypress"]
|
||||
},
|
||||
"include": ["**/*"],
|
||||
"exclude": []
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import { jest, describe, expect } from "@jest/globals";
|
||||
|
||||
import { Player } from "../../../src/Player";
|
||||
import { NetscriptFunctions } from "../../../src/NetscriptFunctions";
|
||||
import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator";
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { jest, describe, expect } from "@jest/globals";
|
||||
|
||||
import { Player } from "../../../src/Player";
|
||||
import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator";
|
||||
import { calculateRamUsage } from "../../../src/Script/RamCalculations";
|
||||
|
@ -1,6 +1,3 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { describe, expect, jest } from "@jest/globals";
|
||||
|
||||
// Player is needed for calculating costs like Singularity functions, that depend on acquired source files
|
||||
import { Player } from "../../../src/Player";
|
||||
|
||||
|
@ -1,6 +1,3 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { jest, describe, expect, test } from "@jest/globals";
|
||||
|
||||
import { Script } from "../../../src/Script/Script";
|
||||
import { Player } from "../../../src/Player";
|
||||
|
||||
|
@ -1,6 +1,3 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { jest, describe, expect, test } from "@jest/globals";
|
||||
|
||||
import { CONSTANTS } from "../../src/Constants";
|
||||
import { Player } from "../../src/Player";
|
||||
import { IMap } from "../../src/types";
|
||||
|
@ -1,5 +1,3 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { jest, describe, expect, test } from "@jest/globals";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../src/utils/StringHelperFunctions";
|
||||
|
||||
describe("StringHelperFunctions Tests", function () {
|
||||
|
@ -1,5 +1,3 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { jest, describe, expect, test } from "@jest/globals";
|
||||
import * as dirHelpers from "../../../src/Terminal/DirectoryHelpers";
|
||||
|
||||
describe("Terminal Directory Tests", function () {
|
||||
@ -102,17 +100,28 @@ describe("Terminal Directory Tests", function () {
|
||||
expect(isValidDirectoryName(".a1")).toEqual(true);
|
||||
expect(isValidDirectoryName("._foo")).toEqual(true);
|
||||
expect(isValidDirectoryName("_foo")).toEqual(true);
|
||||
expect(isValidDirectoryName("foo.dir")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1.0.0.1")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1..0..0..1")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1-0-0-1")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1-0-0-1-")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1--0--0--1--")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1_0_0_1")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1_0_0_1_")).toEqual(true);
|
||||
expect(isValidDirectoryName("foov1__0__0__1")).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false for invalid directory names", function () {
|
||||
expect(isValidDirectoryName("")).toEqual(false);
|
||||
expect(isValidDirectoryName("foo.dir")).toEqual(false);
|
||||
expect(isValidDirectoryName("1.")).toEqual(false);
|
||||
expect(isValidDirectoryName("foo.")).toEqual(false);
|
||||
expect(isValidDirectoryName("👨💻")).toEqual(false);
|
||||
expect(isValidDirectoryName("dir#")).toEqual(false);
|
||||
expect(isValidDirectoryName("dir!")).toEqual(false);
|
||||
expect(isValidDirectoryName("dir*")).toEqual(false);
|
||||
expect(isValidDirectoryName(".")).toEqual(false);
|
||||
expect(isValidDirectoryName("..")).toEqual(false);
|
||||
expect(isValidDirectoryName("1.")).toEqual(false);
|
||||
expect(isValidDirectoryName("foo.")).toEqual(false);
|
||||
expect(isValidDirectoryName("foov1.0.0.1.")).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { CityName } from "./../../../src/Locations/data/CityNames";
|
||||
/* eslint-disable no-await-in-loop */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { jest, describe, expect, test } from "@jest/globals";
|
||||
|
||||
import { Player } from "../../../src/Player";
|
||||
import { determineAllPossibilitiesForTabCompletion } from "../../../src/Terminal/determineAllPossibilitiesForTabCompletion";
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { describe, expect, test } from "@jest/globals";
|
||||
import { numeralWrapper } from "../../../src/ui/numeralFormat";
|
||||
|
||||
let decimalFormat = "0.[000000]";
|
||||
|
9
test/tsconfig.json
Normal file
9
test/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"types": ["jest"]
|
||||
},
|
||||
"include": ["**/*", "../src/**/*.d.ts"],
|
||||
"exclude": ["cypress/**/*"]
|
||||
}
|
@ -4,13 +4,13 @@
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react",
|
||||
"lib": ["es2016", "dom", "es2017.object", "es2019"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"resolveJsonModule": true,
|
||||
"types": ["cypress", "@testing-library/cypress", "node"]
|
||||
"target": "es2019"
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user