Merge pull request #1491 from danielyxie/dev

Added atExit
This commit is contained in:
hydroflame 2021-10-14 20:13:43 -04:00 committed by GitHub
commit 1c92e0cffa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 2502 additions and 14236 deletions

22
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -0,0 +1,18 @@
atExit() Netscript Function
============================
.. js:function:: atExit(f)
:RAM cost: 0 GB
:param function f: function to call when the script dies.
Runs when the script dies.
Example:
.. code-block:: javascript
function onDeath() {
console.log('I died!!!')
}
atExit(onDeath);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

14356
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -14,7 +14,6 @@
"@emotion/styled": "^11.3.0",
"@monaco-editor/react": "^4.2.2",
"@mui/icons-material": "^5.0.3",
"@mui/lab": "^5.0.0-alpha.46",
"@mui/material": "^5.0.3",
"@mui/styles": "^5.0.1",
"@types/escodegen": "^0.0.7",
@ -25,47 +24,23 @@
"@types/react-resizable": "^1.7.3",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"ajv": "^5.1.5",
"ajv-keywords": "^2.0.0",
"arg": "^5.0.0",
"async": "^2.6.1",
"autosize": "^4.0.2",
"better-react-mathjax": "^1.0.3",
"brace": "^0.11.1",
"codemirror": "^5.58.2",
"clsx": "^1.1.1",
"decimal.js": "7.2.3",
"enhanced-resolve": "^4.0.0",
"escodegen": "^1.11.0",
"escope": "^3.6.0",
"file-saver": "^1.3.8",
"interpret": "^1.0.0",
"jquery": "^3.5.0",
"jshint": "^2.10.2",
"json-loader": "^0.5.4",
"jsplumb": "^2.6.8",
"jszip": "^3.7.0",
"loader-runner": "^2.3.0",
"loader-utils": "^1.1.0",
"material-ui-color": "^1.2.0",
"mathjax-full": "^3.2.0",
"memory-fs": "~0.4.1",
"monaco-editor": "^0.27.0",
"node-sass": "^6.0.1",
"normalize.css": "^8.0.0",
"notistack": "^2.0.2",
"numeral": "2.0.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.4",
"react-modal": "^3.12.1",
"react-resizable": "^3.0.4",
"sprintf-js": "^1.1.1",
"tapable": "^1.0.0",
"treant-js": "^1.0.1",
"unused-webpack-plugin": "^2.4.0",
"uuid": "^3.2.1",
"w3c-blob": "0.0.1",
"webpack-deadcode-plugin": "^0.1.15"
"sprintf-js": "^1.1.1"
},
"description": "A cyberpunk-themed incremental game",
"devDependencies": {
@ -76,64 +51,33 @@
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
"@testing-library/cypress": "^8.0.1",
"@types/file-saver": "^2.0.3",
"@types/jest": "^27.0.1",
"@types/lodash": "^4.14.168",
"@types/node": "^16.9.1",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.0.5",
"beautify-lint": "^1.0.3",
"benchmark": "^2.1.1",
"bundle-loader": "~0.5.0",
"css-loader": "^0.28.11",
"cypress": "^8.3.1",
"electron": "^14.0.1",
"electron-packager": "^15.4.0",
"es6-promise-polyfill": "^1.1.1",
"eslint": "^7.24.0",
"eslint-plugin-node": "^11.1.0",
"file-loader": "^1.1.11",
"fork-ts-checker-webpack-plugin": "^6.3.3",
"html-webpack-plugin": "^3.2.0",
"http-server": "^13.0.1",
"i18n-webpack-plugin": "^1.0.0",
"istanbul": "^0.4.5",
"jest": "^27.1.0",
"js-beautify": "^1.5.10",
"jsdom": "^15.0.0",
"jsdom-global": "^3.0.2",
"json5": "^1.0.1",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1",
"null-loader": "^1.0.0",
"prettier": "^2.3.2",
"raw-loader": "~0.5.0",
"react-refresh": "^0.10.0",
"regenerator-runtime": "^0.13.9",
"sass-loader": "^7.0.3",
"script-loader": "~0.7.0",
"should": "^11.1.1",
"simple-git": "^1.96.0",
"sinon": "^2.3.2",
"source-map": "^0.7.3",
"start-server-and-test": "^1.14.0",
"style-loader": "^0.21.0",
"stylelint": "^9.2.1",
"stylelint-order": "^0.8.1",
"typescript": "^4.2.4",
"uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^1.3.0",
"url-loader": "^1.0.1",
"watchpack": "^1.6.0",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-middleware": "^3.7.3",
"webpack-dev-server": "^3.11.2",
"worker-loader": "^2.0.0"
"webpack-dev-server": "^3.11.2"
},
"engines": {
"node": ">=8 || <=9"
@ -157,7 +101,6 @@
"build:dev": "webpack --mode development",
"lint": "npm run lint:jsts & npm run lint:style",
"lint:jsts": "eslint --fix . --ext js,jsx,ts,tsx",
"lint:style": "stylelint --fix ./css/*",
"preinstall": "node ./scripts/engines-check.js",
"test": "jest",
"test:watch": "jest --watch",

@ -2,25 +2,25 @@ const numSpaces = 4;
const maxLineLength = 160;
module.exports = {
env: {
es6: true,
node: true,
"env": {
"es6": true,
"node": true
},
extends: "eslint:recommended",
parserOptions: {
ecmaFeatures: {
experimentalObjectRestSpread: true,
"extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
},
ecmaVersion: 8,
sourceType: "module",
"ecmaVersion": 8,
"sourceType": "module"
},
rules: {
"rules": {
"accessor-pairs": [
"error",
{
getWithoutSet: false,
setWithoutGet: true,
},
"getWithoutSet": false,
"setWithoutGet": true
}
],
"array-bracket-newline": ["error"],
"array-bracket-spacing": ["error"],
@ -33,35 +33,50 @@ module.exports = {
"block-spacing": ["error"],
"brace-style": ["error"],
"callback-return": ["error"],
camelcase: ["error"],
"camelcase": ["error"],
"capitalized-comments": ["error"],
"class-methods-use-this": ["error"],
"comma-dangle": ["error"],
"comma-spacing": ["error"],
"comma-style": ["error", "last"],
complexity: ["error"],
"computed-property-spacing": ["error", "never"],
"comma-style": [
"error",
"last"
],
"complexity": ["error"],
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": ["error"],
"consistent-this": ["error"],
"constructor-super": ["error"],
curly: ["error"],
"curly": ["error"],
"default-case": ["error"],
"dot-location": ["error", "property"],
"dot-location": [
"error",
"property"
],
"dot-notation": ["error"],
"eol-last": ["error"],
eqeqeq: ["error"],
"eqeqeq": ["error"],
"for-direction": ["error"],
"func-call-spacing": ["error"],
"func-name-matching": ["error"],
"func-names": ["error", "never"],
"func-names": [
"error",
"never"
],
"func-style": ["error"],
"function-paren-newline": ["error"],
"generator-star-spacing": ["error", "before"],
"generator-star-spacing": [
"error",
"before"
],
"getter-return": [
"error",
{
allowImplicit: false,
},
"allowImplicit": false
}
],
"global-require": ["error"],
"guard-for-in": ["error"],
@ -69,37 +84,52 @@ module.exports = {
"id-blacklist": ["error"],
"id-length": ["error"],
"id-match": ["error"],
"implicit-arrow-linebreak": ["error", "beside"],
indent: [
"implicit-arrow-linebreak": [
"error",
"beside"
],
"indent": [
"error",
numSpaces,
{
SwitchCase: 1,
},
"SwitchCase": 1
}
],
"init-declarations": ["error"],
"jsx-quotes": ["error"],
"key-spacing": ["error"],
"keyword-spacing": ["error"],
"line-comment-position": ["error"],
"linebreak-style": ["error", "windows"],
"linebreak-style": [
"error",
"windows"
],
"lines-around-comment": ["error"],
"lines-between-class-members": ["error"],
"max-depth": ["error"],
"max-len": ["error", maxLineLength],
"max-len": [
"error",
maxLineLength
],
"max-lines": [
"error",
{
skipBlankLines: true,
skipComments: true,
},
"skipBlankLines": true,
"skipComments": true
}
],
"max-nested-callbacks": ["error"],
"max-params": ["error"],
"max-statements": ["error"],
"max-statements-per-line": ["error"],
"multiline-comment-style": ["off", "starred-block"],
"multiline-ternary": ["error", "never"],
"multiline-comment-style": [
"off",
"starred-block"
],
"multiline-ternary": [
"error",
"never"
],
"new-cap": ["error"],
"new-parens": ["error"],
// TODO: configure this...
@ -115,15 +145,18 @@ module.exports = {
"no-catch-shadow": ["error"],
"no-class-assign": ["error"],
"no-compare-neg-zero": ["error"],
"no-cond-assign": ["error", "except-parens"],
"no-cond-assign": [
"error",
"except-parens"
],
"no-confusing-arrow": ["error"],
"no-console": ["error"],
"no-const-assign": ["error"],
"no-constant-condition": [
"error",
{
checkLoops: false,
},
"checkLoops": false
}
],
"no-continue": ["off"],
"no-control-regex": ["error"],
@ -137,15 +170,15 @@ module.exports = {
"no-duplicate-imports": [
"error",
{
includeExports: true,
},
"includeExports": true
}
],
"no-else-return": ["error"],
"no-empty": [
"error",
{
allowEmptyCatch: false,
},
"allowEmptyCatch": false
}
],
"no-empty-character-class": ["error"],
"no-empty-function": ["error"],
@ -161,8 +194,8 @@ module.exports = {
"error",
"all",
{
conditionalAssign: false,
},
"conditionalAssign": false
}
],
"no-extra-semi": ["error"],
"no-fallthrough": ["error"],
@ -173,17 +206,20 @@ module.exports = {
"no-implicit-globals": ["error"],
"no-implied-eval": ["error"],
"no-inline-comments": ["error"],
"no-inner-declarations": ["error", "both"],
"no-inner-declarations": [
"error",
"both"
],
"no-invalid-regexp": ["error"],
"no-invalid-this": ["error"],
"no-irregular-whitespace": [
"error",
{
skipComments: false,
skipRegExps: false,
skipStrings: false,
skipTemplates: false,
},
"skipComments": false,
"skipRegExps": false,
"skipStrings": false,
"skipTemplates": false
}
],
"no-iterator": ["error"],
"no-label-var": ["error"],
@ -194,9 +230,13 @@ module.exports = {
"no-magic-numbers": [
"error",
{
ignore: [-1, 0, 1],
ignoreArrayIndexes: true,
},
"ignore": [
-1,
0,
1
],
"ignoreArrayIndexes": true
}
],
"no-mixed-operators": ["error"],
"no-mixed-requires": ["error"],
@ -207,8 +247,8 @@ module.exports = {
"no-multiple-empty-lines": [
"error",
{
max: 1,
},
"max": 1
}
],
"no-native-reassign": ["error"],
"no-negated-condition": ["error"],
@ -228,8 +268,8 @@ module.exports = {
"no-plusplus": [
"error",
{
allowForLoopAfterthoughts: true,
},
"allowForLoopAfterthoughts": true
}
],
"no-process-env": ["error"],
"no-process-exit": ["error"],
@ -243,10 +283,10 @@ module.exports = {
"no-restricted-properties": [
"error",
{
message: "'log' is too general, use an appropriate level when logging.",
object: "console",
property: "log",
},
"message": "'log' is too general, use an appropriate level when logging.",
"object": "console",
"property": "log"
}
],
"no-restricted-syntax": ["error"],
"no-return-assign": ["error"],
@ -255,8 +295,8 @@ module.exports = {
"no-self-assign": [
"error",
{
props: false,
},
"props": false
}
],
"no-self-compare": ["error"],
"no-sequences": ["error"],
@ -293,10 +333,10 @@ module.exports = {
"no-useless-rename": [
"error",
{
ignoreDestructuring: false,
ignoreExport: false,
ignoreImport: false,
},
"ignoreDestructuring": false,
"ignoreExport": false,
"ignoreImport": false
}
],
"no-useless-return": ["error"],
"no-var": ["error"],
@ -304,7 +344,10 @@ module.exports = {
"no-warning-comments": ["error"],
"no-whitespace-before-property": ["error"],
"no-with": ["error"],
"nonblock-statement-body-position": ["error", "below"],
"nonblock-statement-body-position": [
"error",
"below"
],
"object-curly-newline": ["error"],
"object-curly-spacing": ["error"],
"object-property-newline": ["error"],
@ -312,7 +355,10 @@ module.exports = {
"one-var": ["off"],
"one-var-declaration-per-line": ["error"],
"operator-assignment": ["error"],
"operator-linebreak": ["error", "none"],
"operator-linebreak": [
"error",
"none"
],
"padded-blocks": ["off"],
"padding-line-between-statements": ["error"],
"prefer-arrow-callback": ["error"],
@ -325,15 +371,24 @@ module.exports = {
"prefer-spread": ["error"],
"prefer-template": ["error"],
"quote-props": ["error"],
quotes: ["error"],
radix: ["error", "as-needed"],
"quotes": ["error"],
"radix": [
"error",
"as-needed"
],
"require-await": ["error"],
"require-jsdoc": ["off"],
"require-yield": ["error"],
"rest-spread-spacing": ["error", "never"],
semi: ["error"],
"rest-spread-spacing": [
"error",
"never"
],
"semi": ["error"],
"semi-spacing": ["error"],
"semi-style": ["error", "last"],
"semi-style": [
"error",
"last"
],
"sort-imports": ["error"],
"sort-keys": ["error"],
"sort-vars": ["error"],
@ -343,25 +398,37 @@ module.exports = {
"space-infix-ops": ["error"],
"space-unary-ops": ["error"],
"spaced-comment": ["error"],
strict: ["error"],
"strict": ["error"],
"switch-colon-spacing": [
"error",
{
after: true,
before: false,
},
"after": true,
"before": false
}
],
"symbol-description": ["error"],
"template-curly-spacing": ["error"],
"template-tag-spacing": ["error"],
"unicode-bom": ["error", "never"],
"unicode-bom": [
"error",
"never"
],
"use-isnan": ["error"],
"valid-jsdoc": ["error"],
"valid-typeof": ["error"],
"vars-on-top": ["error"],
"wrap-iife": ["error", "any"],
"wrap-iife": [
"error",
"any"
],
"wrap-regex": ["error"],
"yield-star-spacing": ["error", "before"],
yoda: ["error", "never"],
},
"yield-star-spacing": [
"error",
"before"
],
"yoda": [
"error",
"never"
]
}
};

@ -8,8 +8,7 @@ const path = require("path");
const exec = require("child_process").exec;
const semver = require("./semver");
const getPackageJson = () =>
new Promise((resolve, reject) => {
const getPackageJson = () => new Promise((resolve, reject) => {
try {
/* eslint-disable-next-line global-require */
resolve(require(path.resolve(process.cwd(), "package.json")));
@ -18,8 +17,7 @@ const getPackageJson = () =>
}
});
const getEngines = (data) =>
new Promise((resolve, reject) => {
const getEngines = (data) => new Promise((resolve, reject) => {
let versions = null;
if (data.engines) {
@ -33,8 +31,7 @@ const getEngines = (data) =>
}
});
const checkNpmVersion = (engines) =>
new Promise((resolve, reject) => {
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
exec("npm -v", (error, stdout, stderr) => {
if (error) {
reject(`Unable to find NPM version\n${stderr}`);
@ -46,23 +43,18 @@ const checkNpmVersion = (engines) =>
if (semver.satisfies(npmVersion, engineVersion)) {
resolve();
} else {
reject(
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
);
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
}
});
});
const checkNodeVersion = (engines) =>
new Promise((resolve, reject) => {
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
const nodeVersion = process.version.substring(1);
if (semver.satisfies(nodeVersion, engines.node)) {
resolve(engines);
} else {
reject(
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
);
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
}
});
@ -77,5 +69,5 @@ getPackageJson()
/* eslint-disable no-console, no-process-exit */
console.error(error);
process.exit(1);
},
}
);

@ -444,6 +444,7 @@ function parseComparator(comp, loose) {
}
class SemVer {
/**
* A semantic version.
* @param {string} version The version.
@ -487,7 +488,7 @@ class SemVer {
// Numberify any prerelease numeric ids
if (matches[4]) {
this.prerelease = matches[4].split(".").map((id) => {
if (/^[0-9]+$/.test(id)) {
if ((/^[0-9]+$/).test(id)) {
const num = Number(id);
if (num >= 0 && num < MAX_SAFE_INTEGER) {
return num;
@ -531,9 +532,7 @@ class SemVer {
}
return (
compareIdentifiers(this.major, other.major) ||
compareIdentifiers(this.minor, other.minor) ||
compareIdentifiers(this.patch, other.patch)
compareIdentifiers(this.major, other.major) || compareIdentifiers(this.minor, other.minor) || compareIdentifiers(this.patch, other.patch)
);
}
@ -573,8 +572,7 @@ class SemVer {
}
}
const compare = (leftVersion, rightVersion, loose) =>
new SemVer(leftVersion, loose).compare(new SemVer(rightVersion, loose));
const compare = (leftVersion, rightVersion, loose) => new SemVer(leftVersion, loose).compare(new SemVer(rightVersion, loose));
const gt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) > 0;
const lt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) < 0;
const eq = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) === 0;

@ -1,6 +1,6 @@
import { IBladeburner } from "./IBladeburner";
export interface IStatsMultiplier {
interface IStatsMultiplier {
[key: string]: number;
hack: number;

@ -1,4 +1,4 @@
export interface RNG {
interface RNG {
random(): number;
}

@ -45,7 +45,7 @@ export function generateRandomContractOnHome(): void {
serv.addContract(contract);
}
export interface IGenerateContractParams {
interface IGenerateContractParams {
problemType?: string;
server?: string;
fn?: string;

@ -8,7 +8,7 @@ import { CodingContractEvent } from "./ui/React/CodingContractModal";
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
/* Represents different types of problems that a Coding Contract can have */
export class CodingContractType {
class CodingContractType {
/**
* Function that generates a description of the problem
*/

@ -45,8 +45,3 @@ export function initCompanies(): void {
export function loadCompanies(saveString: string): void {
Companies = JSON.parse(saveString, Reviver);
}
// Utility function to check if a string is valid company name
export function companyExists(name: string): boolean {
return Companies.hasOwnProperty(name);
}

@ -20,7 +20,7 @@ export function IndustryProductEquation(props: IProps): React.ReactElement {
return (
<MathJaxContext>
<MathJax>{"\\(" + reqs.join("+") + `\\Rightarrow` + prod.map((p) => `1\\text{ }${p}`).join("+") + "\\)"}</MathJax>
<MathJax>{"\\(" + reqs.join("+") + `\\Rightarrow` + prod.map((p) => `1 \\text{${p}}`).join("+") + "\\)"}</MathJax>
</MathJaxContext>
);
}

@ -76,11 +76,6 @@ function MarketTA2(props: IMarketTA2Props): React.ReactElement {
</Tooltip>
}
/>
<Typography>
Note that Market-TA.II overrides Market-TA.I. This means that if both are enabled, then Market-TA.II will take
effect, not Market-TA.I
</Typography>
</>
);
}
@ -93,6 +88,7 @@ interface IProps {
// Create a popup that lets the player use the Market TA research for Materials
export function MaterialMarketTaModal(props: IProps): React.ReactElement {
const division = useDivision();
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
@ -106,11 +102,13 @@ export function MaterialMarketTaModal(props: IProps): React.ReactElement {
return (
<Modal open={props.open} onClose={props.onClose}>
{!division.hasResearch("Market-TA.II") && (
<>
<Typography variant="h4">Market-TA.I</Typography>
<Typography>
The maximum sale price you can mark this up to is {numeralWrapper.formatMoney(props.mat.bCost + markupLimit)}.
This means that if you set the sale price higher than this, you will begin to experience a loss in number of
sales
The maximum sale price you can mark this up to is{" "}
{numeralWrapper.formatMoney(props.mat.bCost + markupLimit)}. This means that if you set the sale price
higher than this, you will begin to experience a loss in number of sales
</Typography>
<FormControlLabel
@ -119,8 +117,8 @@ export function MaterialMarketTaModal(props: IProps): React.ReactElement {
<Tooltip
title={
<Typography>
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I
(i.e. the price shown above)
If this is enabled, then this Material will automatically be sold at the price identified by
Market-TA.I (i.e. the price shown above)
</Typography>
}
>
@ -128,6 +126,8 @@ export function MaterialMarketTaModal(props: IProps): React.ReactElement {
</Tooltip>
}
/>
</>
)}
<MarketTA2 mat={props.mat} />
</Modal>
);

@ -66,11 +66,6 @@ function MarketTA2(props: ITa2Props): React.ReactElement {
</Tooltip>
}
/>
<Typography>
Note that Market-TA.II overrides Market-TA.I. This means that if both are enabled, then Market-TA.II will take
effect, not Market-TA.I
</Typography>
</>
);
}
@ -83,6 +78,7 @@ interface IProps {
// Create a popup that lets the player use the Market TA research for Products
export function ProductMarketTaModal(props: IProps): React.ReactElement {
const division = useDivision();
const markupLimit = props.product.rat / props.product.mku;
const setRerender = useState(false)[1];
function rerender(): void {
@ -96,6 +92,8 @@ export function ProductMarketTaModal(props: IProps): React.ReactElement {
return (
<Modal open={props.open} onClose={props.onClose}>
{!division.hasResearch("Market-TA.II") && (
<>
<Typography variant="h4">Market-TA.I</Typography>
<Typography>
The maximum sale price you can mark this up to is{" "}
@ -109,8 +107,8 @@ export function ProductMarketTaModal(props: IProps): React.ReactElement {
<Tooltip
title={
<Typography>
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I
(i.e. the price shown above)
If this is enabled, then this Material will automatically be sold at the price identified by
Market-TA.I (i.e. the price shown above)
</Typography>
}
>
@ -118,7 +116,8 @@ export function ProductMarketTaModal(props: IProps): React.ReactElement {
</Tooltip>
}
/>
</>
)}
<MarketTA2 product={props.product} />
</Modal>
);

@ -4,7 +4,7 @@ import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
import { IRouter } from "../ui/Router";
import { WorkerScript } from "../Netscript/WorkerScript";
export interface IConstructorParams {
interface IConstructorParams {
hacking_success_weight?: number;
strength_success_weight?: number;
defense_success_weight?: number;

@ -24,7 +24,7 @@ export function loadFactions(saveString: string): void {
}
}
export function AddToFactions(faction: Faction): void {
function AddToFactions(faction: Faction): void {
const name: string = faction.name;
Factions[name] = faction;
}
@ -42,7 +42,7 @@ export function initFactions(): void {
//Resets a faction during (re-)initialization. Saves the favor in the new
//Faction object and deletes the old Faction Object from "Factions". Then
//reinserts the new Faction object
export function resetFaction(newFactionObject: Faction): void {
function resetFaction(newFactionObject: Faction): void {
if (!(newFactionObject instanceof Faction)) {
throw new Error("Invalid argument 'newFactionObject' passed into resetFaction()");
}

@ -5,7 +5,7 @@ import { ITaskParams } from "../ITaskParams";
* Defines the parameters that can be used to initialize and describe a GangMemberTask
* (defined in Gang.js)
*/
export interface IGangMemberTaskMetadata {
interface IGangMemberTaskMetadata {
/**
* Description of the task
*/

@ -19,7 +19,7 @@ export enum UpgradeType {
* Defines the parameters that can be used to initialize and describe a GangMemberUpgrade
* (defined in Gang.js)
*/
export interface IGangMemberUpgradeMetadata {
interface IGangMemberUpgradeMetadata {
cost: number;
mults: IMults;
name: string;

@ -69,6 +69,7 @@ export function TechVendorLocation(props: IProps): React.ReactElement {
return (
<>
<br />
{purchaseServerButtons}
<br />
<Typography>

@ -217,4 +217,4 @@ function initMessages(): void {
);
}
export { Messages, checkForMessagesToSend, sendMessage, showMessage, loadMessages, initMessages, Message };
export { Messages, checkForMessagesToSend, showMessage, loadMessages, initMessages };

@ -1,11 +0,0 @@
import { Milestone } from "./Milestone";
export class Quest {
title: string;
milestones: Milestone[];
constructor(title: string, milestones: Milestone[]) {
this.title = title;
this.milestones = milestones;
}
}

@ -106,6 +106,11 @@ export class WorkerScript {
*/
hostname: string;
/**
* Function called when the script ends.
*/
atExit: any;
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => any) {
this.name = runningScriptObj.filename;
this.hostname = runningScriptObj.server;

@ -10,6 +10,7 @@ import { RunningScript } from "../Script/RunningScript";
import { GetServer } from "../Server/AllServers";
import { compareArrays } from "../utils/helpers/compareArrays";
import { dialogBoxCreate } from "../ui/React/DialogBox";
export function killWorkerScript(runningScriptObj: RunningScript, hostname: string, rerenderUi?: boolean): boolean;
export function killWorkerScript(workerScript: WorkerScript): boolean;
@ -67,6 +68,16 @@ function killWorkerScriptByPid(pid: number, rerenderUi = true): boolean {
function stopAndCleanUpWorkerScript(workerScript: WorkerScript, rerenderUi = true): void {
workerScript.env.stopFlag = true;
killNetscriptDelay(workerScript);
if (typeof workerScript.atExit === "function") {
try {
workerScript.atExit();
} catch (e: any) {
dialogBoxCreate(
`Error trying to call atExit for script ${workerScript.name} on ${workerScript.hostname} ${workerScript.scriptRef.args} ${e}`,
);
}
workerScript.atExit = undefined;
}
removeWorkerScript(workerScript, rerenderUi);
}

@ -86,6 +86,7 @@ import { INetscriptStockMarket, NetscriptStockMarket } from "./NetscriptFunction
import { dialogBoxCreate } from "./ui/React/DialogBox";
import { SnackbarEvents } from "./ui/React/Snackbar";
import { Locations } from "./Locations/Locations";
const defaultInterpreter = new Interpreter("", () => undefined);
@ -2211,6 +2212,19 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
},
/* Singularity Functions */
goToLocation: function (locationName: any): boolean {
const location = Object.values(Locations).find((l) => l.name === locationName);
if (!location) {
workerScript.log("goToLocation", `No location named ${locationName}`);
return false;
}
if (Player.city !== location.city) {
workerScript.log("goToLocation", `No location named ${locationName} in ${Player.city}`);
return false;
}
Router.toLocation(location);
return true;
},
universityCourse: function (universityName: any, className: any): any {
updateDynamicRam("universityCourse", getRamCost("universityCourse"));
checkSingularityAccess("universityCourse", 1);
@ -3263,6 +3277,13 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
corporation: corporation,
formulas: formulas,
atExit: function (f: any): void {
if (typeof f !== "function") {
throw makeRuntimeErrorMsg("atExit", "argument should be function");
}
workerScript.atExit = f;
},
flags: function (data: any): any {
data = toNative(data);
// We always want the help flag.

@ -469,11 +469,7 @@ export function startWorkerScript(runningScript: RunningScript, server: BaseServ
* @param {Server} server - Server on which the script is to be run
* returns {boolean} indicating whether or not the workerScript was successfully added
*/
export function createAndAddWorkerScript(
runningScriptObj: RunningScript,
server: BaseServer,
parent?: WorkerScript,
): boolean {
function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseServer, parent?: WorkerScript): boolean {
// Update server's ram usage
let threads = 1;
if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {

@ -1,3 +0,0 @@
import { EventEmitter } from "../utils/EventEmitter";
export const PlayerEvents = new EventEmitter<[]>();

@ -1,100 +0,0 @@
import * as React from "react";
export const SleeveFaq = (
<>
<strong>
<u>How do Duplicate Sleeves work?</u>
</strong>
<br />
Duplicate Sleeves are essentially clones. You can use them to perform any work type action, such as working for a
company/faction or committing a crime. Having sleeves perform these tasks earns you money, experience, and
reputation.
<br />
<br />
Sleeves are their own individuals, which means they each have their own experience and stats.
<br />
<br />
When a sleeve earns experience, it earns experience for itself, the player's original 'consciousness', as well as
all of the player's other sleeves.
<br />
<br />
<strong>
<u>What is Synchronization (Sync)?</u>
</strong>
<br />
Synchronization is a measure of how aligned your consciousness is with that of your Duplicate Sleeves. It is a
numerical value between 1 and 100, and it affects how much experience is earned when the sleeve is performing a
task.
<br />
<br />
Let N be the sleeve's synchronization. When the sleeve earns experience by performing a task, both the sleeve and
the player's original host consciousness earn N% of the amount of experience normally earned by the task. All of the
player's other sleeves earn ((N/100)^2 * 100)% of the experience.
<br />
<br />
Synchronization can be increased by assigning sleeves to the 'Synchronize' task.
<br />
<br />
<strong>
<u>What is Shock?</u>
</strong>
<br />
Sleeve shock is a measure of how much trauma the sleeve has due to being placed in a new body. It is a numerical
value between 0 and 99, where 99 indicates full shock and 0 indicates no shock. Shock affects the amount of
experience earned by the sleeve.
<br />
<br />
Sleeve shock slowly decreases over time. You can further increase the rate at which it decreases by assigning
sleeves to the 'Shock Recovery' task.
<br />
<br />
<strong>
<u>Why can't I work for this company or faction?</u>
</strong>
<br />
Only one of your sleeves can work for a given company/faction a time. To clarify further, if you have two sleeves
they can work for two different companies, but they cannot both work for the same company.
<br />
<br />
<strong>
<u>Why did my Sleeve stop working?</u>
</strong>
<br />
Sleeves are subject to the same time restrictions as you. This means that they automatically stop working at a
company after 8 hours, and stop working for a faction after 20 hours.
<br />
<br />
<strong>
<u>How do I buy Augmentations for my Sleeves?</u>
</strong>
<br />
Your Sleeve needs to have a Shock of 0 in order for you to buy Augmentations for it.
<br />
<br />
<strong>
<u>Why can't I buy the X Augmentation for my sleeve?</u>
</strong>
<br />
Certain Augmentations, like Bladeburner-specific ones and NeuroFlux Governor, are not available for sleeves.
<br />
<br />
<strong>
<u>Do sleeves get reset when installing Augmentations or switching BitNodes?</u>
</strong>
<br />
Sleeves are reset when switching BitNodes, but not when installing Augmentations.
<br />
<br />
<strong>
<u>What is Memory?</u>
</strong>
<br />
Sleeve memory dictates what a sleeve's synchronization will be when its reset by switching BitNodes. For example, if
a sleeve has a memory of 25, then when you switch BitNodes its synchronization will initially be set to 25, rather
than 1.
<br />
<br />
Memory can only be increased by purchasing upgrades from The Covenant. It is a persistent stat, meaning it never
gets resets back to 1. The maximum possible value for a sleeve's memory is 100.
</>
);

@ -24,7 +24,7 @@ function bitFlumeRequirements() {
};
}
export interface IProgramCreationParams {
interface IProgramCreationParams {
key: string;
name: string;
create: IProgramCreate | null;

@ -1,7 +1,7 @@
export type Position = {
interface Position {
row: number;
column: number;
};
}
class PositionTracker {
positions: Map<string, Position>;

@ -197,7 +197,7 @@ export function initSymbolToStockMap(): void {
}
}
export function stockMarketCycle(): void {
function stockMarketCycle(): void {
for (const name in StockMarket) {
const stock = StockMarket[name];
if (!(stock instanceof Stock)) {

@ -1,14 +1,6 @@
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
export function getStockMarketAccountCost(): number {
return CONSTANTS.WSEAccountCost;
}
export function getStockMarketTixApiCost(): number {
return CONSTANTS.TIXAPICost;
}
export function getStockMarket4SDataCost(): number {
return CONSTANTS.MarketData4SCost * BitNodeMultipliers.FourSigmaMarketDataCost;
}

@ -15,7 +15,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
import { EventEmitter } from "../../utils/EventEmitter";
type txFn = (stock: Stock, shares: number) => boolean;
export type placeOrderFn = (
type placeOrderFn = (
stock: Stock,
shares: number,
price: number,

@ -39,8 +39,8 @@ enum SelectorOrderType {
Stop = "Stop Order",
}
export type txFn = (stock: Stock, shares: number) => boolean;
export type placeOrderFn = (
type txFn = (stock: Stock, shares: number) => boolean;
type placeOrderFn = (
stock: Stock,
shares: number,
price: number,

@ -47,7 +47,7 @@ function LongPosition(props: IProps): React.ReactElement {
</Box>
<Typography>Shares: {numeralWrapper.formatShares(stock.playerShares)}</Typography>
<Typography>
Average Price: <Money money={stock.playerAvgPx} /> (Total Cost: <Money money={totalCost} />
Average Price: <Money money={stock.playerAvgPx} /> (Total Cost: <Money money={totalCost} />)
</Typography>
<Typography>
Profit: <Money money={gains} /> ({numeralWrapper.formatPercentage(percentageGains)})

@ -16,8 +16,8 @@ import { PositionTypes } from "../data/PositionTypes";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { EventEmitter } from "../../utils/EventEmitter";
export type txFn = (stock: Stock, shares: number) => boolean;
export type placeOrderFn = (
type txFn = (stock: Stock, shares: number) => boolean;
type placeOrderFn = (
stock: Stock,
shares: number,
price: number,

@ -35,7 +35,7 @@ export function removeTrailingSlash(s: string): string {
* Checks whether a string is a valid filename. Only used for the filename itself,
* not the entire filepath
*/
export function isValidFilename(filename: string): boolean {
function isValidFilename(filename: string): boolean {
// Allows alphanumerics, hyphens, underscores, and percentage signs
// Must have a file extension
const regex = /^[.a-zA-Z0-9_-]+[.][a-zA-Z0-9]+(?:-\d+(?:\.\d*)?%-INC)?$/;
@ -48,7 +48,7 @@ export function isValidFilename(filename: string): boolean {
* Checks whether a string is a valid directory name. Only used for the directory itself,
* not an entire path
*/
export function isValidDirectoryName(name: string): boolean {
function isValidDirectoryName(name: string): boolean {
// Allows alphanumerics, hyphens, underscores, and percentage signs.
// Name can begin with a single period, but otherwise cannot have any
const regex = /^.?[a-zA-Z0-9_-]+$/;

@ -12,7 +12,7 @@ export type SolverFunc = (data: any, answer: string) => boolean;
Requires the 'data' of a Contract as input */
export type DescriptionFunc = (data: any) => string;
export interface ICodingContractTypeMetadata {
interface ICodingContractTypeMetadata {
desc: DescriptionFunc;
difficulty: number;
gen: GeneratorFunc;

@ -10,11 +10,6 @@ export interface IMap<T> {
[key: string]: T;
}
/**
* Performs some action, with no returned value.
*/
export type Action = () => void;
/**
* Contains a method to initialize itself to a known state.
*/

@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { KEY } from "../../utils/helpers/keyCodes";
import { CodingContract, CodingContractType, CodingContractTypes } from "../../CodingContracts";
import { CodingContract, CodingContractTypes } from "../../CodingContracts";
import { CopyableText } from "./CopyableText";
import { Modal } from "./Modal";
import { EventEmitter } from "../../utils/EventEmitter";
@ -49,7 +49,7 @@ export function CodingContractModal(): React.ReactElement {
setProps(null);
}
const contractType: CodingContractType = CodingContractTypes[props.c.type];
const contractType = CodingContractTypes[props.c.type];
const description = [];
for (const [i, value] of contractType.desc(props.c.data).split("\n").entries())
description.push(<span key={i} dangerouslySetInnerHTML={{ __html: value + "<br />" }}></span>);

@ -1,32 +0,0 @@
/**
* React component for a popup content container
*
* Takes in a prop for rendering the content inside the popup
*/
import React, { useEffect } from "react";
interface IProps<T> {
content: (props: T) => React.ReactElement;
id: string;
props: T;
removePopup: () => void;
}
export function Popup<T>(props: IProps<T>): React.ReactElement {
function keyDown(event: KeyboardEvent): void {
if (event.key === "Escape") props.removePopup();
}
useEffect(() => {
document.addEventListener("keydown", keyDown);
return () => {
document.removeEventListener("keydown", keyDown);
};
});
return (
<div className={"popup-box-content"} id={`${props.id}-content`}>
{React.createElement(props.content, props.props)}
</div>
);
}

@ -4,7 +4,7 @@
type cbFn = (...args: any[]) => any;
export interface ISubscriber {
interface ISubscriber {
/**
* Callback function that will be run when an event is emitted
*/

@ -1,6 +1,6 @@
/* Generic Reviver, toJSON, and fromJSON functions used for saving and loading objects */
export interface IReviverValue {
interface IReviverValue {
ctor: string;
data: any;
}

@ -1,13 +1,6 @@
import { EqualityFunc } from "../types";
import { isString } from "./helpers/isString";
// Netburner String helper functions
// Replaces the character at an index with a new character
function replaceAt(base: string, index: number, character: string): string {
return base.substr(0, index) + character + base.substr(index + character.length);
}
/*
Converts a date representing time in milliseconds to a string with the format H hours M minutes and S seconds
e.g. 10000 -> "10 seconds"
@ -92,20 +85,6 @@ function formatNumber(num: number, numFractionDigits = 0): string {
});
}
// Checks if a string contains HTML elements
function isHTML(str: string): boolean {
const element: HTMLDivElement = document.createElement("div");
element.innerHTML = str;
const c: NodeListOf<Node & ChildNode> = element.childNodes;
for (let i: number = c.length - 1; i >= 0; i--) {
if (c[i].nodeType === 1) {
return true;
}
}
return false;
}
// Generates a random alphanumeric string with N characters
function generateRandomString(n: number): string {
let str = "";
@ -118,12 +97,4 @@ function generateRandomString(n: number): string {
return str;
}
export {
convertTimeMsToTimeElapsedString,
longestCommonStart,
containsAllStrings,
formatNumber,
isHTML,
generateRandomString,
replaceAt,
};
export { convertTimeMsToTimeElapsedString, longestCommonStart, containsAllStrings, formatNumber, generateRandomString };

@ -4,9 +4,7 @@ const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const UnusedWebpackPlugin = require("unused-webpack-plugin");
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const DeadCodePlugin = require("webpack-deadcode-plugin");
module.exports = (env, argv) => {
const isDevServer = (env || {}).devServer === true;
@ -107,14 +105,6 @@ module.exports = (env, argv) => {
},
},
}),
new UnusedWebpackPlugin({
// Source directories
directories: [path.join(__dirname, "src"), path.join(__dirname, "utils")],
// Exclude patterns
exclude: ["*.test.js"],
// Root directory (optional)
root: __dirname,
}),
// In dev mode, use a faster method of create sourcemaps
// while keeping lines/columns accurate
isDevServer &&
@ -132,10 +122,6 @@ module.exports = (env, argv) => {
module: true,
}),
isFastRefresh && new ReactRefreshWebpackPlugin(),
new DeadCodePlugin({
patterns: ["src/**/*.(js|jsx|css|ts|tsx)"],
exclude: ["**/*.(stories|spec).(js|jsx)"],
}),
].filter(Boolean),
target: "web",
entry: entry,