Migrated Corporation UI implementation to use React

This commit is contained in:
danielyxie 2019-03-13 15:17:30 -07:00
parent f3dbdad011
commit 3e10f5de6d
37 changed files with 6699 additions and 5142 deletions

3
.babelrc Normal file

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-react"]
}

@ -56,11 +56,13 @@
.cmpy-mgmt-industry-left-panel,
.cmpy-mgmt-industry-right-panel {
display: inline-block;
width: 45%;
height: 100%;
top: 10px;
overflow-y: auto;
overflow-x: auto;
overflow: visible;
padding: 2px;
top: 10px;
width: 45%;
}
.cmpy-mgmt-industry-overview-panel {
@ -115,13 +117,18 @@
background-color: #333;
}
/* Upgrades */
/* Corporation Upgrades */
.cmpy-mgmt-upgrade-container {
border: 1px solid #fff;
width: 60%;
margin: 4px;
}
.cmpy-mgmt-upgrade-header {
margin: 6px;
padding: 6px;
}
.cmpy-mgmt-upgrade-div {
display: inline-block;
border: 1px solid #fff;
@ -136,10 +143,19 @@
background-color: #333;
}
/* Industry Upgrades */
.industry-purchases-and-upgrades-header {
font-size: 14px;
margin: 2px;
padding: 2px;
}
/* Advertising */
.cmpy-mgmt-advertising-info {
font-size: $defaultFontSize * 0.75;
}
/* Research */
#corporation-research-popup-box-content {
overflow-x: visible !important;
}

@ -7,6 +7,11 @@ buy and sell stocks in order to make money.
The WSE can be found in the 'City' tab, and is accessible in every city.
Automating the Stock Market
^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can write scripts to perform automatic and algorithmic trading on the Stock Market.
See :ref:`netscript_tixapi` for more details.
Positions: Long vs Short
^^^^^^^^^^^^^^^^^^^^^^^^
When making a transaction on the stock market, there are two types of positions:

@ -6,9 +6,9 @@ Changelog
v0.44.1 - 3/4/2019
------------------
* Duplicate Sleeve changes:
** You can now purchase Augmentations for your Duplicate Sleeves
** Sleeves are now assigned to Shock Recovery task by default
** Shock Recovery and Synchronize tasks are now twice as effective
* You can now purchase Augmentations for your Duplicate Sleeves
* Sleeves are now assigned to Shock Recovery task by default
* Shock Recovery and Synchronize tasks are now twice as effective
* Changed documentation so that Netscript functions are own their own pages. Sorry if this is annoying, it was necessary for properly cross-referencing
* Officially deprecated the Wiki (the fandom site). Use the 'readthedocs' Documentation instead

@ -5,7 +5,7 @@ Netscript
Netscript is the programming language used in the world of Bitburner.
When you write scripts in Bitburner, they are written in the Netscript language.
Netscript is simply a subset of `JavaScript <https://developer.mozilla.org/en-US/docs/Web/JavaScript>`_,.
Netscript is simply a subset of `JavaScript <https://developer.mozilla.org/en-US/docs/Web/JavaScript>`_.
This means that Netscript's syntax is
identical to that of JavaScript, but it does not implement some of the features
that JavaScript has.

526
package-lock.json generated

@ -4,6 +4,347 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/code-frame": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
"dev": true,
"requires": {
"@babel/highlight": "7.0.0"
}
},
"@babel/core": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz",
"integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==",
"dev": true,
"requires": {
"@babel/code-frame": "7.0.0",
"@babel/generator": "7.3.4",
"@babel/helpers": "7.3.1",
"@babel/parser": "7.3.4",
"@babel/template": "7.2.2",
"@babel/traverse": "7.3.4",
"@babel/types": "7.3.4",
"convert-source-map": "1.6.0",
"debug": "4.1.1",
"json5": "2.1.0",
"lodash": "4.17.11",
"resolve": "1.5.0",
"semver": "5.5.0",
"source-map": "0.5.7"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "2.1.1"
}
},
"json5": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
"integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
"dev": true,
"requires": {
"minimist": "1.2.0"
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/generator": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz",
"integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==",
"dev": true,
"requires": {
"@babel/types": "7.3.4",
"jsesc": "2.5.2",
"lodash": "4.17.11",
"source-map": "0.5.7",
"trim-right": "1.0.1"
},
"dependencies": {
"jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"@babel/helper-builder-react-jsx": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz",
"integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==",
"dev": true,
"requires": {
"@babel/types": "7.3.4",
"esutils": "2.0.2"
}
},
"@babel/helper-function-name": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
"integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "7.0.0",
"@babel/template": "7.2.2",
"@babel/types": "7.3.4"
}
},
"@babel/helper-get-function-arity": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
"integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
"dev": true,
"requires": {
"@babel/types": "7.3.4"
}
},
"@babel/helper-plugin-utils": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
"integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
"dev": true
},
"@babel/helper-split-export-declaration": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz",
"integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==",
"dev": true,
"requires": {
"@babel/types": "7.3.4"
}
},
"@babel/helpers": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz",
"integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==",
"dev": true,
"requires": {
"@babel/template": "7.2.2",
"@babel/traverse": "7.3.4",
"@babel/types": "7.3.4"
}
},
"@babel/highlight": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
"dev": true,
"requires": {
"chalk": "2.4.2",
"esutils": "2.0.2",
"js-tokens": "4.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "1.9.1"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "3.2.1",
"escape-string-regexp": "1.0.5",
"supports-color": "5.4.0"
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
}
}
},
"@babel/parser": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz",
"integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==",
"dev": true
},
"@babel/plugin-syntax-jsx": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz",
"integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "7.0.0"
}
},
"@babel/plugin-transform-react-display-name": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz",
"integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "7.0.0"
}
},
"@babel/plugin-transform-react-jsx": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz",
"integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==",
"dev": true,
"requires": {
"@babel/helper-builder-react-jsx": "7.3.0",
"@babel/helper-plugin-utils": "7.0.0",
"@babel/plugin-syntax-jsx": "7.2.0"
}
},
"@babel/plugin-transform-react-jsx-self": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz",
"integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "7.0.0",
"@babel/plugin-syntax-jsx": "7.2.0"
}
},
"@babel/plugin-transform-react-jsx-source": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz",
"integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "7.0.0",
"@babel/plugin-syntax-jsx": "7.2.0"
}
},
"@babel/preset-react": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz",
"integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "7.0.0",
"@babel/plugin-transform-react-display-name": "7.2.0",
"@babel/plugin-transform-react-jsx": "7.3.0",
"@babel/plugin-transform-react-jsx-self": "7.2.0",
"@babel/plugin-transform-react-jsx-source": "7.2.0"
}
},
"@babel/template": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz",
"integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==",
"dev": true,
"requires": {
"@babel/code-frame": "7.0.0",
"@babel/parser": "7.3.4",
"@babel/types": "7.3.4"
}
},
"@babel/traverse": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz",
"integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==",
"dev": true,
"requires": {
"@babel/code-frame": "7.0.0",
"@babel/generator": "7.3.4",
"@babel/helper-function-name": "7.1.0",
"@babel/helper-split-export-declaration": "7.0.0",
"@babel/parser": "7.3.4",
"@babel/types": "7.3.4",
"debug": "4.1.1",
"globals": "11.3.0",
"lodash": "4.17.11"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "2.1.1"
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
}
}
},
"@babel/types": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
"integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
"dev": true,
"requires": {
"esutils": "2.0.2",
"lodash": "4.17.11",
"to-fast-properties": "2.0.0"
},
"dependencies": {
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
}
}
},
"@mrmlnc/readdir-enhanced": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@ -25,6 +366,28 @@
"resolved": "https://registry.npmjs.org/@types/numeral/-/numeral-0.0.25.tgz",
"integrity": "sha512-ShHzHkYD+Ldw3eyttptCpUhF1/mkInWwasQkCNXZHOsJMJ/UMa8wXrxSrTJaVk0r4pLK/VnESVM0wFsfQzNEKQ=="
},
"@types/prop-types": {
"version": "15.7.0",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.0.tgz",
"integrity": "sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg=="
},
"@types/react": {
"version": "16.8.6",
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.6.tgz",
"integrity": "sha512-bN9qDjEMltmHrl0PZRI4IF2AbB7V5UlRfG+OOduckVnRQ4VzXVSzy/1eLAh778IEqhTnW0mmgL9yShfinNverA==",
"requires": {
"@types/prop-types": "15.7.0",
"csstype": "2.6.2"
}
},
"@types/react-dom": {
"version": "16.8.2",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.8.2.tgz",
"integrity": "sha512-MX7n1wq3G/De15RGAAqnmidzhr2Y9O/ClxPxyqaNg96pGyeXUYPSvujgzEVpLo9oIP4Wn1UETl+rxTN02KEpBw==",
"requires": {
"@types/react": "16.8.6"
}
},
"@webassemblyjs/ast": {
"version": "1.5.12",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.5.12.tgz",
@ -642,6 +1005,83 @@
"js-tokens": "3.0.2"
}
},
"babel-loader": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz",
"integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==",
"dev": true,
"requires": {
"find-cache-dir": "2.0.0",
"loader-utils": "1.1.0",
"mkdirp": "0.5.1",
"util.promisify": "1.0.0"
},
"dependencies": {
"find-cache-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz",
"integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==",
"dev": true,
"requires": {
"commondir": "1.0.1",
"make-dir": "1.2.0",
"pkg-dir": "3.0.0"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "3.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "3.0.0",
"path-exists": "3.0.0"
}
},
"p-limit": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
"dev": true,
"requires": {
"p-try": "2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "2.2.0"
}
},
"p-try": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
"integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==",
"dev": true
},
"pkg-dir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
"integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
"dev": true,
"requires": {
"find-up": "3.0.0"
}
}
}
},
"bail": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.3.tgz",
@ -2034,6 +2474,15 @@
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"dev": true
},
"convert-source-map": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
"dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
@ -2309,6 +2758,11 @@
}
}
},
"csstype": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.2.tgz",
"integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow=="
},
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@ -5261,8 +5715,7 @@
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"dev": true
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-yaml": {
"version": "3.6.1",
@ -5940,6 +6393,14 @@
"integrity": "sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA==",
"dev": true
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "3.0.2"
}
},
"loud-rejection": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
@ -6800,8 +7261,7 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-copy": {
"version": "0.1.0",
@ -8192,6 +8652,16 @@
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"requires": {
"loose-envify": "1.4.0",
"object-assign": "4.1.1",
"react-is": "16.8.3"
}
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -8402,6 +8872,33 @@
"integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=",
"dev": true
},
"react": {
"version": "16.8.3",
"resolved": "https://registry.npmjs.org/react/-/react-16.8.3.tgz",
"integrity": "sha512-3UoSIsEq8yTJuSu0luO1QQWYbgGEILm+eJl2QN/VLDi7hL+EN18M3q3oVZwmVzzBJ3DkM7RMdRwBmZZ+b4IzSA==",
"requires": {
"loose-envify": "1.4.0",
"object-assign": "4.1.1",
"prop-types": "15.7.2",
"scheduler": "0.13.3"
}
},
"react-dom": {
"version": "16.8.3",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.3.tgz",
"integrity": "sha512-ttMem9yJL4/lpItZAQ2NTFAbV7frotHk5DZEHXUOws2rMmrsvh1Na7ThGT0dTzUIl6pqTOi5tYREfL8AEna3lA==",
"requires": {
"loose-envify": "1.4.0",
"object-assign": "4.1.1",
"prop-types": "15.7.2",
"scheduler": "0.13.3"
}
},
"react-is": {
"version": "16.8.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz",
"integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA=="
},
"readable-stream": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz",
@ -9179,6 +9676,15 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
"scheduler": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz",
"integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==",
"requires": {
"loose-envify": "1.4.0",
"object-assign": "4.1.1"
}
},
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
@ -10892,6 +11398,12 @@
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
"dev": true
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
"dev": true
},
"to-object-path": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
@ -10962,6 +11474,12 @@
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
"dev": true
},
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true
},
"trim-trailing-lines": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.1.tgz",

@ -7,6 +7,8 @@
},
"dependencies": {
"@types/numeral": "0.0.25",
"@types/react": "^16.8.6",
"@types/react-dom": "^16.8.2",
"acorn": "^5.0.0",
"acorn-dynamic-import": "^2.0.0",
"ajv": "^5.1.5",
@ -31,6 +33,8 @@
"memory-fs": "~0.4.1",
"normalize.css": "^8.0.0",
"numeral": "2.0.6",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"sprintf-js": "^1.1.1",
"tapable": "^1.0.0",
"uglifyjs-webpack-plugin": "^1.2.5",
@ -39,6 +43,9 @@
},
"description": "A cyberpunk-themed incremental game",
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.5",
"beautify-lint": "^1.0.3",
"benchmark": "^2.1.1",
"bundle-loader": "~0.5.0",

@ -281,17 +281,17 @@ export let CONSTANTS: IMap<any> = {
LatestUpdate:
`
v0.44.1
* Duplicate Sleeve changes:
** You can now purchase Augmentations for your Duplicate Sleeves
** Sleeves are now assigned to Shock Recovery task by default
** Shock Recovery and Synchronize tasks are now twice as effective
* Changed documentation so that Netscript functions are own their own pages. Sorry if this is annoying, it was necessary for properly cross-referencing
* Officially deprecated the Wiki (the fandom site). Use the 'readthedocs' Documentation instead
* Bug Fix: 'rm' Terminal and Netscript commands now work on non-program files that have '.exe' in the name (by Github user MasonD)
* Bug Fix: The 'Find All Valid Math Expressions' Coding Contract should now properly ignore whitespace in answers
* Bug Fix: The 'Merge Overlapping Intervals' Coding Contract should now properly accept 2D arrays when being attempted through Netscript
v0.45.0
* Corporation changes:
** Decreased the time of a full market cycle from 15 seconds to 10 seconds.
** This means that each Corporation 'state' will now only take 2 seconds, rather than 3
** Increased initial salaries for newly-hired employees
** Increased the cost multiplier for upgrading office size (the cost will increase faster)
** The stats of your employees now has a slightly larger effect on production & sales
** Added several new Research upgrades
** Reduced the amount of Scientific Research needed to unlock the Hi-Tech R&D Laboratory from 10k to 5k
** Energy Material requirement of the Software industry reduced from 1 to 0.5
** Industries now have a maximum number of allowed products, starting at 3. This can be increased through research.
`
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,5 +1,6 @@
import { ResearchTree } from "./ResearchTree";
import { getBaseResearchTreeCopy } from "./data/BaseResearchTree";
import { getBaseResearchTreeCopy,
getProductIndustryResearchTreeCopy } from "./data/BaseResearchTree";
import { numeralWrapper } from "../ui/numeralFormat";
@ -112,15 +113,15 @@ export let IndustryResearchTrees: IIndustryMap<ResearchTree> = {
Agriculture: getBaseResearchTreeCopy(),
Fishing: getBaseResearchTreeCopy(),
Mining: getBaseResearchTreeCopy(),
Food: getBaseResearchTreeCopy(),
Tobacco: getBaseResearchTreeCopy(),
Food: getProductIndustryResearchTreeCopy(),
Tobacco: getProductIndustryResearchTreeCopy(),
Chemical: getBaseResearchTreeCopy(),
Pharmaceutical: getBaseResearchTreeCopy(),
Computer: getBaseResearchTreeCopy(),
Robotics: getBaseResearchTreeCopy(),
Software: getBaseResearchTreeCopy(),
Healthcare: getBaseResearchTreeCopy(),
RealEstate: getBaseResearchTreeCopy(),
Pharmaceutical: getProductIndustryResearchTreeCopy(),
Computer: getProductIndustryResearchTreeCopy(),
Robotics: getProductIndustryResearchTreeCopy(),
Software: getProductIndustryResearchTreeCopy(),
Healthcare: getProductIndustryResearchTreeCopy(),
RealEstate: getProductIndustryResearchTreeCopy(),
}
export function resetIndustryResearchTrees() {

@ -12,7 +12,6 @@ export class Material {
return Generic_fromJSON(Material, value.data);
}
// Name of material
name: string = "InitName";
@ -64,6 +63,10 @@ export class Material {
prdman: any[] = [false, 0]; // Production
sllman: any[] = [false, 0]; // Sale
// Flags that signal whether automatic sale pricing through Market TA is enabled
marketTa1: boolean = false;
marketTa2: boolean = false;
constructor(params: IConstructorParams = {}) {
if (params.name) { this.name = params.name; }
this.init();

@ -8,6 +8,7 @@ export interface IConstructorParams {
employeeEffMult?: number;
employeeIntMult?: number;
productionMult?: number;
productProductionMult?: number;
salesMult?: number;
sciResearchMult?: number;
storageMult?: number;
@ -30,6 +31,7 @@ export class Research {
employeeEffMult: number = 1;
employeeIntMult: number = 1;
productionMult: number = 1;
productProductionMult: number = 1;
salesMult: number = 1;
sciResearchMult: number = 1;
storageMult: number = 1;
@ -44,6 +46,7 @@ export class Research {
if (p.employeeEffMult) { this.employeeEffMult = p.employeeEffMult; }
if (p.employeeIntMult) { this.employeeIntMult = p.employeeIntMult; }
if (p.productionMult) { this.productionMult = p.productionMult; }
if (p.productProductionMult) { this.productProductionMult = p.productProductionMult; }
if (p.salesMult) { this.salesMult = p.salesMult; }
if (p.sciResearchMult) { this.sciResearchMult = p.sciResearchMult; }
if (p.storageMult) { this.storageMult = p.storageMult; }

@ -185,6 +185,10 @@ export class ResearchTree {
return this.getMultiplierHelper("productionMult");
}
getProductProductionMultiplier(): number {
return this.getMultiplierHelper("productProductionMult");
}
getSalesMultiplier(): number {
return this.getMultiplierHelper("salesMult");
}

@ -0,0 +1,100 @@
import { Material } from "./Material";
import { MaterialSizes } from "./MaterialSizes";
import { IMap } from "../types";
import { numeralWrapper } from "../ui/numeralFormat";
import { Generic_fromJSON,
Generic_toJSON,
Reviver } from "../../utils/JSONReviver";
interface IConstructorParams {
loc?: string;
size?: number;
}
interface IParent {
getStorageMultiplier(): number;
}
export class Warehouse {
// Initiatizes a Warehouse object from a JSON save state.
static fromJSON(value: any): Warehouse {
return Generic_fromJSON(Warehouse, value.data);
}
// Text that describes how the space in this Warehouse is being used
// Used to create a tooltip in the UI
breakdown: string = "";
// Warehouse's level, which affects its maximum size
level: number = 0;
// City that this Warehouse is in
loc: string;
// Map of Materials held by this Warehouse
materials: IMap<Material>;
// Maximum amount warehouse can hold
size: number;
// Amount of space currently used by warehouse
sizeUsed: number = 0;
// Whether Smart Supply is enabled for this Industry (the Industry that this Warehouse is for)
smartSupplyEnabled: boolean = false;
// Stores the amount of product to be produced. Used for Smart Supply unlock.
// The production tracked by smart supply is always based on the previous cycle,
// so it will always trail the "true" production by 1 cycle
smartSupplyStore: number = 0;
constructor(params: IConstructorParams = {}) {
this.loc = params.loc ? params.loc : "";
this.size = params.size ? params.size : 0;
this.materials = {
Water: new Material({name: "Water"}),
Energy: new Material({name: "Energy"}),
Food: new Material({name: "Food"}),
Plants: new Material({name: "Plants"}),
Metal: new Material({name: "Metal"}),
Hardware: new Material({name: "Hardware"}),
Chemicals: new Material({name: "Chemicals"}),
Drugs: new Material({name: "Drugs"}),
Robots: new Material({name: "Robots"}),
AICores: new Material({name: "AI Cores"}),
RealEstate: new Material({name: "Real Estate"})
}
}
// Re-calculate how much space is being used by this Warehouse
updateMaterialSizeUsed() {
this.sizeUsed = 0;
this.breakdown = "";
for (const matName in this.materials) {
var mat = this.materials[matName];
if (MaterialSizes.hasOwnProperty(matName)) {
this.sizeUsed += (mat.qty * MaterialSizes[matName]);
if (mat.qty > 0) {
this.breakdown += (matName + ": " + numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0") + "<br>");
}
}
}
if (this.sizeUsed > this.size) {
console.warn("Warehouse size used greater than capacity, something went wrong");
}
}
updateSize(corporation: IParent, industry: IParent) {
this.size = (this.level * 100)
* corporation.getStorageMultiplier()
* industry.getStorageMultiplier();
}
// Serialize the current object to a JSON save state.
toJSON(): any {
return Generic_toJSON("Warehouse", this);
}
}
Reviver.constructors.Warehouse = Warehouse;

@ -14,14 +14,14 @@ function makeNode(name: string): Node {
return new Node({ text: research.name, cost: research.cost });
}
export function getBaseResearchTreeCopy(): ResearchTree {
const baseResearchTree: ResearchTree = new ResearchTree();
// Creates the Nodes for the BaseResearchTree.
// Return the Root Node
function createBaseResearchTreeNodes(): Node {
const rootNode: Node = makeNode("Hi-Tech R&D Laboratory");
const autoBrew: Node = makeNode("AutoBrew");
const autoParty: Node = makeNode("AutoPartyManager");
const autoDrugs: Node = makeNode("Automatic Drug Administration");
const bulkPurchasing: Node = makeNode("Bulk Purchasing");
const cph4: Node = makeNode("CPH4 Injections");
const drones: Node = makeNode("Drones");
const dronesAssembly: Node = makeNode("Drones - Assembly");
@ -47,13 +47,39 @@ export function getBaseResearchTreeCopy(): ResearchTree {
rootNode.addChild(autoBrew);
rootNode.addChild(autoParty);
rootNode.addChild(autoDrugs);
rootNode.addChild(bulkPurchasing);
rootNode.addChild(drones);
rootNode.addChild(joywire);
rootNode.addChild(marketta1);
rootNode.addChild(overclock);
rootNode.addChild(scAssemblers);
baseResearchTree.setRoot(rootNode);
return rootNode;
}
export function getBaseResearchTreeCopy(): ResearchTree {
const baseResearchTree: ResearchTree = new ResearchTree();
baseResearchTree.setRoot(createBaseResearchTreeNodes());
return baseResearchTree;
}
// Base Research Tree for Industry's that make products
export function getProductIndustryResearchTreeCopy(): ResearchTree {
const researchTree: ResearchTree = new ResearchTree();
const root = createBaseResearchTreeNodes();
const upgradeFulcrum = makeNode("uPgrade: Fulcrum");
const upgradeCapacity1 = makeNode("uPgrade: Capacity.I");
const upgradeCapacity2 = makeNode("uPgrade: Capacity.II");
const upgradeDashboard = makeNode("uPgrade: Dashboard");
upgradeCapacity1.addChild(upgradeCapacity2);
upgradeFulcrum.addChild(upgradeCapacity1);
upgradeFulcrum.addChild(upgradeDashboard);
root.addChild(upgradeFulcrum);
researchTree.setRoot(root);
return researchTree;
}

@ -24,6 +24,12 @@ export const researchMetadata: IConstructorParams[] = [
desc: "Research how to automatically administer performance-enhacing drugs to all of " +
"your employees. This unlocks Drug-related Research.",
},
{
name: "Bulk Purchasing",
cost: 5e3,
desc: "Research the art of buying materials in bulk. This allows you to purchase " +
"any amount of a material instantly.",
},
{
name: "CPH4 Injections",
cost: 25e3,
@ -64,7 +70,7 @@ export const researchMetadata: IConstructorParams[] = [
},
{
name: "Hi-Tech R&D Laboratory",
cost: 10e3,
cost: 5e3,
desc: "Construct a cutting edge facility dedicated to advanced research and " +
"and development. This allows you to spend Scientific Research " +
"on powerful upgrades. It also globally increases Scientific Research " +
@ -118,7 +124,38 @@ export const researchMetadata: IConstructorParams[] = [
"control confidence and enthusiasm. This research increases the max " +
"morale of all employees by 10.",
},
{
name: "sudo.Assist",
cost: 15e3,
desc: "Develop a virtual assistant AI to handle and manage administrative " +
"issues for your corporation.",
},
{
name: "uPgrade: Capacity.I",
cost: 20e3,
desc: "Expand the industry's capacity for designing and manufacturing its " +
"various products. This increases the industry's maximum number of products " +
"by 1 (from 3 to 4).",
},
{
name: "uPgrade: Capacity.II",
cost: 30e3,
desc: "Expand the industry's capacity for designing and manufacturing its " +
"various products. This increases the industry's maximum number of products " +
"by 1 (from 4 to 5).",
},
{
name: "uPgrade: Dashboard",
cost: 5e3,
desc: "Improve the software used to manage the industry's production line " +
"for its various products. This allows you to manage the production and " +
"sale of a product before it's finished being designed.",
},
{
name: "uPgrade: Fulcrum",
cost: 10e3,
desc: "Streamline the manufacturing of this industry's various products. " +
"This research increases the production of your products by 5%",
productProductionMult: 1.05,
},
];

@ -0,0 +1,22 @@
// Base class for React Components for Corporation UI
// Contains a few helper functions that let derived classes easily
// access Corporation properties
import React from "react";
const Component = React.Component;
export class BaseReactComponent extends Component {
corp() {
return this.props.corp;
}
eventHandler() {
return this.props.eventHandler;
}
routing() {
return this.props.routing;
}
render() {}
}

@ -0,0 +1,56 @@
// React Components for the Corporation UI's City navigation tabs
// These allow player to navigate between different cities for each industry
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
export class CityTabs extends BaseReactComponent {
constructor(props) {
// An object with [key = city name] and [value = click handler]
// needs to be passed into the constructor as the "onClicks" property.
// We'll make sure that that happens here
if (props.onClicks == null) {
throw new Error(`CityTabs component constructed without onClick handlers`);
}
if (props.city == null) {
throw new Error(`CityTabs component constructed without 'city' property`)
}
super(props);
}
renderTab(props) {
let className = "cmpy-mgmt-city-tab";
if (props.current) {
className += " current";
}
return (
<button className={className} onClick={props.onClick} key={props.key}>
{props.key}
</button>
)
}
render() {
const tabs = [];
// Tabs for each city
for (const cityName in this.props.onClicks) {
tabs.push(this.renderTab({
current: this.props.city === cityName,
key: cityName,
onClick: this.props.onClicks[cityName],
}));
}
// Tab to "Expand into new City"
const newCityOnClick = this.eventHandler().createNewCityPopup.bind(this.eventHandler());
tabs.push(this.renderTab({
current: false,
key: "Expand into new City",
onClick: newCityOnClick,
}));
return tabs;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,80 @@
// React Components for the Corporation UI's navigation tabs
// These are the tabs at the top of the UI that let you switch to different
// divisions, see an overview of your corporation, or create a new industry
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { overviewPage } from "./Routing";
function HeaderTab(props) {
let className = "cmpy-mgmt-header-tab";
if (props.current) {
className += " current";
}
return (
<button className={className} onClick={props.onClick}>
{props.text}
</button>
)
}
export class HeaderTabs extends BaseReactComponent {
renderTab(props) {
return (
<HeaderTab
current={props.current}
key={props.key}
onClick={props.onClick}
text={props.text}
/>
)
}
render() {
const overviewOnClick = () => {
this.routing().routeToOverviewPage();
this.corp().rerender();
}
const divisionOnClicks = {};
for (const division of this.corp().divisions) {
const name = division.name;
const onClick = () => {
this.routing().routeTo(name);
this.corp().rerender();
}
divisionOnClicks[name] = onClick;
}
return (
<div>
{
this.renderTab({
current: this.routing().isOnOverviewPage(),
key: "overview",
onClick: overviewOnClick,
text: this.corp().name,
})
}
{
this.corp().divisions.map((division) => {
return this.renderTab({
current: this.routing().isOn(division.name),
key: division.name,
onClick: divisionOnClicks[division.name],
text: division.name,
});
})
}
{
this.renderTab({
onClick: this.eventHandler().createNewIndustryPopup.bind(this.eventHandler()),
text: "Expand into new Industry"
})
}
</div>
)
}
}

@ -0,0 +1,34 @@
// React Component for managing the Corporation's Industry UI
// This Industry component does NOT include the city tabs at the top
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { IndustryOffice } from "./IndustryOffice";
import { IndustryOverview } from "./IndustryOverview";
import { IndustryWarehouse } from "./IndustryWarehouse";
export class Industry extends BaseReactComponent {
constructor(props) {
if (props.currentCity == null) {
throw new Error(`Industry component constructed without 'city' prop`);
}
super(props);
}
render() {
return (
<div>
<div className={"cmpy-mgmt-industry-left-panel"}>
<IndustryOverview {...this.props} />
<IndustryOffice {...this.props} />
</div>
<div className={"cmpy-mgmt-industry-right-panel"}>
<IndustryWarehouse {...this.props} />
</div>
</div>
)
}
}

@ -0,0 +1,557 @@
// React Component for displaying an Industry's OfficeSpace information
// (bottom-left panel in the Industry UI)
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { OfficeSpace } from "../Corporation";
import { EmployeePositions } from "../EmployeePositions";
import { numeralWrapper } from "../../ui/numeralFormat";
import { getSelectText } from "../../../utils/uiHelpers/getSelectData";
export class IndustryOffice extends BaseReactComponent {
constructor(props) {
super(props);
this.state = {
employeeManualAssignMode: false,
employee: null, // Reference to employee being referenced if in Manual Mode
numEmployees: 0,
numOperations: 0,
numEngineers: 0,
numBusiness: 0,
numManagement: 0,
numResearch: 0,
numUnassigned: 0,
numTraining: 0,
}
this.updateEmployeeCount(); // This function validates division and office refs
}
updateEmployeeCount() {
const division = this.routing().currentDivision;
if (division == null) {
throw new Error(`Routing does not hold reference to the current Industry`);
}
const office = division.offices[this.props.currentCity];
if (!(office instanceof OfficeSpace)) {
throw new Error(`Current City (${this.props.currentCity}) for UI does not have an OfficeSpace object`);
}
// Calculate how many NEW emplyoees we need to account for
const currentNumEmployees = office.employees.length;
const newEmployees = currentNumEmployees - this.state.numEmployees;
// Record the number of employees in each position, for NEW employees only
for (let i = this.state.numEmployees; i < office.employees.length; ++i) {
switch (office.employees[i].pos) {
case EmployeePositions.Operations:
++this.state.numOperations;
break;
case EmployeePositions.Engineer:
++this.state.numEngineers;
break;
case EmployeePositions.Business:
++this.state.numBusiness;
break;
case EmployeePositions.Management:
++this.state.numManagement;
break;
case EmployeePositions.RandD:
++this.state.numResearch;
break;
case EmployeePositions.Unassigned:
++this.state.numUnassigned;
break;
case EmployeePositions.Training:
++this.state.numTraining;
break;
default:
console.error("Unrecognized employee position: " + office.employees[i].pos);
break;
}
}
this.state.numEmployees = currentNumEmployees;
}
// Renders the "Employee Management" section of the Office UI
renderEmployeeManagement() {
this.updateEmployeeCount();
if (this.state.employeeManualAssignMode) {
return this.renderManualEmployeeManagement();
} else {
return this.renderAutomaticEmployeeManagement();
}
}
renderAutomaticEmployeeManagement() {
const division = this.routing().currentDivision; // Validated in constructor
const office = division.offices[this.props.currentCity]; // Validated in constructor
const vechain = (this.corp().unlockUpgrades[4] === 1); // Has Vechain upgrade
const switchModeOnClick = () => {
this.state.employeeManualAssignMode = true;
this.corp().rerender();
}
// Calculate average morale, happiness, and energy. Also salary
// TODO is this efficient?
let totalMorale = 0, totalHappiness = 0, totalEnergy = 0, totalSalary = 0;
for (let i = 0; i < office.employees.length; ++i) {
totalMorale += office.employees[i].mor;
totalHappiness += office.employees[i].hap;
totalEnergy += office.employees[i].ene;
totalSalary += office.employees[i].sal;
}
let avgMorale = 0, avgHappiness = 0, avgEnergy = 0;
if (office.employees.length > 0) {
avgMorale = totalMorale / office.employees.length;
avgHappiness = totalHappiness / office.employees.length;
avgEnergy = totalEnergy / office.employees.length;
}
// Helper functions for (re-)assigning employees to different positions
const assignEmployee = (to) => {
if (this.state.numUnassigned >= 0) {
console.warn("Cannot assign employee. No unassigned employees available");
return;
}
switch (to) {
case EmployeePositions.Operations:
++this.state.numOperations;
break;
case EmployeePositions.Engineer:
++this.state.numEngineers;
break;
case EmployeePositions.Business:
++this.state.numBusiness;
break;
case EmployeePositions.Management:
++this.state.numManagement;
break;
case EmployeePositions.RandD:
++this.state.numResearch;
break;
case EmployeePositions.Unassigned:
++this.state.numUnassigned;
break;
case EmployeePositions.Training:
++this.state.numTraining;
break;
default:
console.error("Unrecognized employee position: " + to);
break;
}
--this.state.numUnassigned;
office.assignEmployeeToJob(to);
this.corp().rerender();
}
const unassignEmployee = (from) => {
function logWarning(pos) {
console.warn(`Cannot unassign from ${pos} because there is nobody assigned to that position`);
}
switch (from) {
case EmployeePositions.Operations:
if (this.state.numOperations <= 0) { return logWarning(EmployeePositions.Operations); }
--this.state.numOperations;
break;
case EmployeePositions.Engineer:
if (this.state.numEngineers <= 0) { return logWarning(EmployeePositions.Operations); }
--this.state.numEngineers;
break;
case EmployeePositions.Business:
if (this.state.numBusiness <= 0) { return logWarning(EmployeePositions.Operations); }
--this.state.numBusiness;
break;
case EmployeePositions.Management:
if (this.state.numManagement <= 0) { return logWarning(EmployeePositions.Operations); }
--this.state.numManagement;
break;
case EmployeePositions.RandD:
if (this.state.numResearch <= 0) { return logWarning(EmployeePositions.Operations); }
--this.state.numResearch;
break;
case EmployeePositions.Unassigned:
console.warn(`Tried to unassign from the Unassigned position`);
break;
case EmployeePositions.Training:
if (this.state.numTraining <= 0) { return logWarning(EmployeePositions.Operations); }
--this.state.numTraining;
break;
default:
console.error("Unrecognized employee position: " + from);
break;
}
++this.state.numUnassigned;
office.unassignEmployeeFromJob(from);
this.corp().rerender();
}
const positionHeaderStyle = {
fontSize: "15px",
margin: "5px 0px 5px 0px",
width: "50%",
}
const assignButtonClass = this.state.numUnassigned > 0 ? "std-button" : "a-link-button-inactive";
const operationAssignButtonOnClick = () => {
assignEmployee(EmployeePositions.Operations);
this.corp().rerender();
}
const operationUnassignButtonOnClick = () => {
unassignEmployee(EmployeePositions.Operations);
this.corp().rerender();
}
const operationUnassignButtonClass = this.state.numOperations > 0 ? "std-button" : "a-link-button-inactive";
const engineerAssignButtonOnClick = () => {
assignEmployee(EmployeePositions.Engineer);
this.corp().rerender();
}
const engineerUnassignButtonOnClick = () => {
unassignEmployee(EmployeePositions.Engineer);
this.corp().rerender();
}
const engineerUnassignButtonClass = this.state.numEngineers > 0 ? "std-button" : "a-link-button-inactive";
const businessAssignButtonOnClick = () => {
assignEmployee(EmployeePositions.Business);
this.corp().rerender();
}
const businessUnassignButtonOnClick = () => {
unassignEmployee(EmployeePositions.Business);
this.corp().rerender();
}
const businessUnassignButtonClass = this.state.numBusiness > 0 ? "std-button" : "a-link-button-inactive";
const managementAssignButtonOnClick = () => {
assignEmployee(EmployeePositions.Management);
this.corp().rerender();
}
const managementUnassignButtonOnClick = () => {
unassignEmployee(EmployeePositions.Management);
this.corp().rerender();
}
const managementUnassignButtonClass = this.state.numManagement > 0 ? "std-button" : "a-link-button-inactive";
const rndAssignButtonOnClick = () => {
assignEmployee(EmployeePositions.RandD);
this.corp().rerender();
}
const rndUnassignButtonOnClick = () => {
unassignEmployee(EmployeePositions.RandD);
this.corp().rerender();
}
const rndUnassignButtonClass = this.state.numResearch > 0 ? "std-button" : "a-link-button-inactive";
const trainingAssignButtonOnClick = () => {
assignEmployee(EmployeePositions.Training);
this.corp().rerender();
}
const trainingUnassignButtonOnClick = () => {
unassignEmployee(EmployeePositions.Training);
this.corp().rerender();
}
const trainingUnassignButtonClass = this.state.numTraining > 0 ? "std-button" : "a-link-button-inactive";
return (
<div>
<button className={"std-button tooltip"} onClick={switchModeOnClick}>
Switch to Manual Mode
<span className={"tooltiptext"}>
Switch to Manual Assignment Mode, which allows you to
specify which employees should get which jobs
</span>
</button>
<p><strong>Unassigned Employees: {this.state.numUnassigned}</strong></p>
<br />
<p>Avg Employee Morale: {numeralWrapper.format(avgMorale, "0.000")}</p>
<p>Avg Happiness Morale: {numeralWrapper.format(avgHappiness, "0.000")}</p>
<p>Avg Energy Morale: {numeralWrapper.format(avgEnergy, "0.000")}</p>
<p>Total Employee Salary: {numeralWrapper.formatMoney(totalSalary)}</p>
{
vechain &&
<div>
<p className={"tooltip"}>
Material Production: {numeralWrapper.format(division.getOfficeProductivity(office), "0.000")}
<span className={"tooltiptext"}>
The base amount of material this office can produce. Does not include
production multipliers from upgrades and materials. This value is based off
the productivity of your Operations, Engineering, and Management employees
</span>
</p><br />
<p className={"tooltip"}>
Product Production: {numeralWrapper.format(division.getOfficeProductivity(office, {forProduct:true}), "0.000")}
<span className={"tooltiptext"}>
The base amount of any given Product this office can produce. Does not include
production multipliers from upgrades and materials. This value is based off
the productivity of your Operations, Engineering, and Management employees
</span>
</p><br />
<p className={"tooltip"}>
Business Multiplier: x" ${numeralWrapper.format(division.getBusinessFactor(office), "0.000")}
<span className={"tooltiptext"}>
The effect this office's 'Business' employees has on boosting sales
</span>
</p><br />
</div>
}
<h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Operations}
<span className={"tooltiptext"}>
Manages supply chain operations. Improves production.
</span>
</h2>
<button className={assignButtonClass} onClick={operationAssignButtonOnClick}>+</button>
<button className={operationUnassignButtonClass} onClick={operationUnassignButtonOnClick}>-</button>
<br />
<h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Engineer}
<span className={"tooltiptext"}>
Develops and maintains products and production systems. Improves production.
</span>
</h2>
<button className={assignButtonClass} onClick={engineerAssignButtonOnClick}>+</button>
<button className={engineerUnassignButtonClass} onClick={engineerUnassignButtonOnClick}>-</button>
<br />
<h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Business}
<span className={"tooltiptext"}>
Handles sales and finances. Improves sales.
</span>
</h2>
<button className={assignButtonClass} onClick={businessAssignButtonOnClick}>+</button>
<button className={businessUnassignButtonClass} onClick={businessUnassignButtonOnClick}>-</button>
<br />
<h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Management}
<span className={"tooltiptext"}>
Leads and oversees employees and office operations. Improves production.
</span>
</h2>
<button className={assignButtonClass} onClick={managementAssignButtonOnClick}>+</button>
<button className={managementUnassignButtonClass} onClick={managementUnassignButtonOnClick}>-</button>
<br />
<h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.RandD}
<span className={"tooltiptext"}>
Research new innovative ways to improve the company. Generates Scientific Research
</span>
</h2>
<button className={assignButtonClass} onClick={rndAssignButtonOnClick}>+</button>
<button className={rndUnassignButtonClass} onClick={rndUnassignButtonOnClick}>-</button>
<br />
<h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Training}
<span className={"tooltiptext"}>
Set employee to training, which will increase some of their stats. Employees in training do not affect any company operations.
</span>
</h2>
<button className={assignButtonClass} onClick={trainingAssignButtonOnClick}>+</button>
<button className={trainingUnassignButtonClass} onClick={trainingUnassignButtonOnClick}>-</button>
</div>
)
}
renderManualEmployeeManagement() {
const corp = this.corp();
const division = this.routing().currentDivision; // Validated in constructor
const office = division.offices[this.props.currentCity]; // Validated in constructor
const switchModeOnClick = () => {
this.state.employeeManualAssignMode = false;
this.corp().rerender();
}
const employeeInfoDivStyle = {
color: "white",
margin: "4px",
padding: "4px",
}
// Employee Selector
const employees = [];
for (let i = 0; i < office.employees.length; ++i) {
employees.push(<option key={office.employees[i].name}>{office.employees[i].name}</option>)
}
const employeeSelectorOnChange = (e) => {
const name = getSelectText(e.target);
for (let i = 0; i < office.employees.length; ++i) {
if (name === office.employees[i].name) {
this.state.employee = office.employees[i];
}
}
}
const employeeSelectorStyle = {
backgroundColor: "black",
color: "white",
margin: "4px",
padding: "4px",
}
// Employee Positions Selector
const employeePositions = [];
const positionNames = Object.values(EmployeePositions);
for (let i = 0; i < positionNames.length; ++i) {
employeePositions.push(<option key={positionNames[i]}>{positionNames[i]}</option>);
}
const employeePositionSelectorOnChange = (e) => {
const pos = getSelectText(e.target);
this.state.employee.pos = pos;
}
// Numeraljs formatter
const nf = "0.000";
// Employee stats (after applying multipliers)
const emp = this.state.employee;
const effCre = emp ? emp.cre * corp.getEmployeeCreMultiplier() * division.getEmployeeCreMultiplier() : 0;
const effCha = emp ? emp.cha * corp.getEmployeeChaMultiplier() * division.getEmployeeChaMultiplier() : 0;
const effInt = emp ? emp.int * corp.getEmployeeIntMultiplier() * division.getEmployeeIntMultiplier() : 0;
const effEff = emp ? emp.eff * corp.getEmployeeEffMultiplier() * division.getEmployeeEffMultiplier() : 0;
return (
<div>
<button className={"std-button tooltip"} onClick={switchModeOnClick}>
Switch to Auto Mode
<span className={"tooltiptext"}>
Switch to Automatic Assignment Mode, which will automatically
assign employees to your selected jobs. You simply have to select
the number of assignments for each job
</span>
</button>
<div style={employeeInfoDivStyle}>
{
this.state.employee != null &&
<p>
Morale: {numeralWrapper.format(this.state.employee.mor, nf)}
<br />
Happiness: {numeralWrapper.format(this.state.employee.hap, nf)}
<br />
Energy: {numeralWrapper.format(this.state.employee.ene, nf)}
<br />
Age: {numeralWrapper.format(this.state.employee.age, nf)}
<br />
Intelligence: {numeralWrapper.format(effInt, nf)}
<br />
Charisma: {numeralWrapper.format(effCha, nf)}
<br />
Experience: {numeralWrapper.format(this.state.employee.exp, nf)}
<br />
Creativity: {numeralWrapper.format(effCre, nf)}
<br />
Efficiency: {numeralWrapper.format(effEff, nf)}
<br />
Salary: {numeralWrapper.formatMoney(this.state.employee.sal)}
</p>
}
{
this.state.employee != null &&
<select onChange={employeePositionSelectorOnChange}>
{employeePositions}
</select>
}
</div>
<select style={employeeSelectorStyle} onChange={employeeSelectorOnChange}>
{employees}
</select>
</div>
)
}
render() {
const corp = this.corp();
const division = this.routing().currentDivision; // Validated in constructor
const office = division.offices[this.props.currentCity]; // Validated in constructor
const buttonStyle = {
fontSize: "13px",
}
// Hire Employee button
let hireEmployeeButtonClass = "std-button tooltip";
if (office.employees.length === 0) {
hireEmployeeButtonClass += " flashing-button";
}
const hireEmployeeButtonOnClick = () => {
office.findEmployees({ corporation: corp, industry: division });
}
// Autohire employee button
const autohireEmployeeButtonOnClick = () => {
office.hireRandomEmployee({ corporation: corp, industry: division });
this.corp().rerender();
}
// Upgrade Office Size Button
const upgradeOfficeSizeOnClick = this.eventHandler().createUpgradeOfficeSizePopup.bind(this.eventHandler(), office);
// Throw Office Party
const throwOfficePartyOnClick = this.eventHandler().createThrowOfficePartyPopup.bind(this.eventHandler(), office);
return (
<div className={"cmpy-mgmt-employee-panel"}>
<h1>Office Space</h1>
<p>Size: {office.employees.length} / {office.size} employees</p>
<button className={hireEmployeeButtonClass} onClick={hireEmployeeButtonOnClick} style={buttonStyle}>
Hire Employee
{
office.employees.length === 0 &&
<span className={"tooltiptext"}>
You'll need to hire some employees to get your operations started!
It's recommended to have at least one employee in every position
</span>
}
</button>
<button className={"std-button tooltip"} onClick={autohireEmployeeButtonOnClick} style={buttonStyle}>
Autohire Employee
<span className={"tooltiptext"}>
Automatically hires an employee and gives him/her a random name
</span>
</button>
<br />
<button className={"std-button tooltip"} onClick={upgradeOfficeSizeOnClick} style={buttonStyle}>
Upgrade size
<span className={"tooltiptext"}>
Upgrade the office's size so that it can hold more employees!
</span>
</button>
{
!division.hasResearch("AutoPartyManager") &&
<button className={"std-button tooltip"} onClick={throwOfficePartyOnClick} style={buttonStyle}>
Throw Party
<span className={"tooltiptext"}>
"Throw an office party to increase your employee's morale and happiness"
</span>
</button>
}
<br />
{this.renderEmployeeManagement()}
</div>
)
}
}

@ -0,0 +1,261 @@
// React Component for displaying an Industry's overview information
// (top-left panel in the Industry UI)
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { OfficeSpace } from "../Corporation";
import { Industries } from "../IndustryData";
import { IndustryUpgrades } from "../IndustryUpgrades";
import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox";
export class IndustryOverview extends BaseReactComponent {
renderMakeProductButton() {
const corp = this.corp();
const division = this.routing().currentDivision; // Validated inside render()
var createProductButtonText, createProductPopupText;
switch(division.type) {
case Industries.Food:
createProductButtonText = "Build Restaurant";
createProductPopupText = "Build and manage a new restaurant!"
break;
case Industries.Tobacco:
createProductButtonText = "Create Product";
createProductPopupText = "Create a new tobacco product!";
break;
case Industries.Pharmaceutical:
createProductButtonText = "Create Drug";
createProductPopupText = "Design and develop a new pharmaceutical drug!";
break;
case Industries.Computer:
case "Computer":
createProductButtonText = "Create Product";
createProductPopupText = "Design and manufacture a new computer hardware product!";
break;
case Industries.Robotics:
createProductButtonText = "Design Robot";
createProductPopupText = "Design and create a new robot or robotic system!";
break;
case Industries.Software:
createProductButtonText = "Develop Software";
createProductPopupText = "Develop a new piece of software!";
break;
case Industries.Healthcare:
createProductButtonText = "Build Hospital";
createProductPopupText = "Build and manage a new hospital!";
break;
case Industries.RealEstate:
createProductButtonText = "Develop Property";
createProductPopupText = "Develop a new piece of real estate property!";
break;
default:
createProductButtonText = "Create Product";
createProductPopupText = "Create a new product!";
return "";
}
createProductPopupText += "<br><br>To begin developing a product, " +
"first choose the city in which it will be designed. The stats of your employees " +
"in the selected city affect the properties of the finished product, such as its " +
"quality, performance, and durability.<br><br>" +
"You can also choose to invest money in the design and marketing of " +
"the product. Investing money in its design will result in a superior product. " +
"Investing money in marketing the product will help the product's sales.";
const hasMaxProducts = division.hasMaximumNumberProducts();
const className = hasMaxProducts ? "a-link-button-inactive tooltip" : "std-button";
const onClick = this.eventHandler().createMakeProductPopup.bind(this.eventHandler(), createProductPopupText, division);
const buttonStyle = {
margin: "6px",
display: "inline-block",
}
return (
<button className={className} onClick={onClick} style={buttonStyle}>
{createProductButtonText}
{
hasMaxProducts &&
<span className={"tooltiptext"}>
You have reached the maximum number of products: {division.getMaximumNumberProducts()}
</span>
}
</button>
)
}
renderText() {
const corp = this.corp();
const division = this.routing().currentDivision; // Validated inside render()
const vechain = (corp.unlockUpgrades[4] === 1);
const profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber();
const genInfo = `Industry: ${division.type} (Corp Funds: ${numeralWrapper.formatMoney(corp.funds.toNumber())})`;
const awareness = `Awareness: ${numeralWrapper.format(division.awareness, "0.000")}`;
const popularity = `Popularity: ${numeralWrapper.format(division.popularity, "0.000")}`;
let advertisingInfo = false;
let advertisingTooltip;
const advertisingFactors = division.getAdvertisingFactors();
const awarenessFac = advertisingFactors[1];
const popularityFac = advertisingFactors[2];
const ratioFac = advertisingFactors[3];
const totalAdvertisingFac = advertisingFactors[0];
if (vechain) { advertisingInfo = true; }
const revenue = `Revenue: ${numeralWrapper.formatMoney(division.lastCycleRevenue.toNumber())} / s`;
const expenses = `Expenses: ${numeralWrapper.formatMoney(division.lastCycleExpenses.toNumber())} /s`;
const profitStr = `Profit: ${numeralWrapper.formatMoney(profit)} / s`;
const productionMultHelpTipOnClick = () => {
dialogBoxCreate("Owning Hardware, Robots, AI Cores, and Real Estate " +
"can boost your Industry's production. The effect these " +
"materials have on your production varies between Industries. " +
"For example, Real Estate may be very effective for some Industries, " +
"but ineffective for others.<br><br>" +
"This division's production multiplier is calculated by summing " +
"the individual production multiplier of each of its office locations. " +
"This production multiplier is applied to each office. Therefore, it is " +
"beneficial to expand into new cities as this can greatly increase the " +
"production multiplier of your entire Division.");
}
return (
<div>
{genInfo}
<br /> <br />
{awareness} <br />
{popularity} <br />
{
(advertisingInfo !== false) &&
<p className={"tooltip"}>Advertising Multiplier: {numeralWrapper.format(totalAdvertisingFac, "0.000")}
<span className={"tooltiptext cmpy-mgmt-advertising-info"}>
Total multiplier for this industrys sales due to its awareness and popularity
<br />
Awareness Bonus: x{formatNumber(Math.pow(awarenessFac, 0.85), 3)}
<br />
Popularity Bonus: x{formatNumber(Math.pow(popularityFac, 0.85), 3)}
<br />
Ratio Multiplier: x{formatNumber(Math.pow(ratioFac, 0.85), 3)}
</span>
</p>
}
{advertisingInfo}
<br /><br />
{revenue} <br />
{expenses} <br />
{profitStr}
<br /> <br />
<p className={"tooltip"}>
Production Multiplier: {numeralWrapper.format(division.prodMult, "0.00")}
<span className={"tooltiptext"}>
Production gain from owning production-boosting materials
such as hardware, Robots, AI Cores, and Real Estate
</span>
</p>
<div className={"help-tip"} onClick={productionMultHelpTipOnClick}>?</div>
<br /> <br />
<p className={"tooltip"}>
Scientific Research: {numeralWrapper.format(division.sciResearch.qty, "0.000")}
<span className={"tooltiptext"}>
Scientific Research increases the quality of the materials and
products that you produce.
</span>
</p>
<button className={"help-tip"} onClick={division.createResearchBox}>
Research
</button>
<div className={"help-tip"} onClick={division.createResearchBox.bind(division)}>?</div>
</div>
)
}
renderUpgrades() {
const corp = this.corp();
const division = this.routing().currentDivision; // Validated inside render()
const office = division.offices[this.props.currentCity];
if (!(office instanceof OfficeSpace)) {
throw new Error(`Current City (${this.props.currentCity}) for UI does not have an OfficeSpace object`);
}
const upgrades = [];
for (const index in IndustryUpgrades) {
const upgrade = IndustryUpgrades[index];
// AutoBrew research disables the Coffee upgrade
if (division.hasResearch("AutoBrew") && upgrade[4] === "Coffee") { continue; }
const i = upgrade[0];
const baseCost = upgrade[1];
const priceMult = upgrade[2];
let cost = 0;
switch (i) {
case 0: //Coffee, cost is static per employee
cost = office.employees.length * baseCost;
break;
default:
cost = baseCost * Math.pow(priceMult, division.upgrades[i]);
break;
}
const onClick = () => {
if (corp.funds.lt(cost)) {
dialogBoxCreate("Insufficient funds");
} else {
corp.funds = corp.funds.minus(cost);
division.upgrade(upgrade, {
corporation: corp,
office: office,
});
// corp.displayDivisionContent(division, city);
corp.rerender();
}
}
upgrades.push(this.renderUpgrade({
onClick: onClick,
text: `${upgrade[4]} - ${numeralWrapper.formatMoney(cost)}`,
tooltip: upgrade[5],
}));
}
return upgrades;
}
renderUpgrade(props) {
return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} onClick={props.onClick} key={props.text}>
{props.text}
{
props.tooltip != null &&
<span className={"tooltiptext"}>{props.tooltip}</span>
}
</div>
)
}
render() {
const division = this.routing().currentDivision;
if (division == null) {
throw new Error(`Routing does not hold reference to the current Industry`);
}
const makeProductButton = this.renderMakeProductButton();
return (
<div className={"cmpy-mgmt-industry-overview-panel"}>
{this.renderText()}
<br />
<u className={"industry-purchases-and-upgrades-header"}>Purchases & Upgrades</u><br />
{this.renderUpgrades()} <br />
{
division.makesProducts &&
{makeProductButton}
}
</div>
)
}
}

@ -0,0 +1,486 @@
// React Component for displaying an Industry's warehouse information
// (right-side panel in the Industry UI)
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { Material } from "../Material";
import { Product } from "../Product";
import { Warehouse,
WarehouseInitialCost,
WarehouseUpgradeBaseCost } from "../Corporation";
import { numeralWrapper } from "../../ui/numeralFormat";
import { isString } from "../../../utils/helpers/isString";
// Creates the UI for a single Product type
function ProductComponent(props) {
const corp = props.corp;
const division = props.division;
const warehouse = props.warehouse;
const product = props.product;
const eventHandler = props.eventHandler;
const nf = "0.000"; // Numeraljs formatter
const hasUpgradeDashboard = division.hasResearch("uPgrade: Dashboard");
// Total product gain = production - sale
const totalGain = totalGain = product.data[city][1] - product.data[city][2];
// Sell button
const sellButtonText = product.sllman[city][1] === -1
? "Sell (" + numeralWrapper.format(product.data[city][2], nf) + "/MAX)"
: "Sell (" + numeralWrapper.format(product.data[city][2], nf) + "/" + numeralWrapper.format(product.sllman[city][1], nf) + ")";
if (product.sCost) {
if (isString(product.sCost)) {
sellButtonText += (" @ " + product.sCost);
} else {
sellButtonText += (" @ " + numeralWrapper.format(product.sCost, "$0.000a"));
}
}
const sellButtonOnClick = eventHandler.createSellProductPopup.bind(eventHandler, product);
// Limit Production button
const limitProductionButtonText = "Limit Production";
if (product.prdman[city][0]) {
limitProductionButtonText += " (" + numeralWrapper.format(product.prdman[city][1], nf) + ")";
}
const limitProductionButtonOnClick = eventHandler.createLimitProductProdutionPopup.bind(eventHandler, product);
// Discontinue Button
const discontinueButtonOnClick = eventHandler.createDiscontinueProductPopup.bind(eventHandler, product);
// Unfinished Product
if (!product.fin) {
if (hasUpgradeDashboard) {
return (
<div className={"cmpy-mgmt-warehouse-product-div"}>
<p>Designing {product.name}...</p>
<p>{numeralWrapper.format(product.prog, "0.00")}% complete</p>
<br />
<div>
<button className={"std-button"} onClick={sellButtonOnClick}>
{sellButtonText}
</button><br />
<button className={"std-button"} onClick={limitProductionButtonOnClick}>
{limitProductionButtonText}
</button>
<button className={"std-button"} onClick={discontinueButtonOnClick}>
Discontinue
</button>
</div>
</div>
)
} else {
return (
<div className={"cmpy-mgmt-warehouse-product-div"}>
<p>Designing {product.name}...</p>
<p>{numeralWrapper.format(product.prog, "0.00")}% complete</p>
</div>
);
}
}
return (
<div className={"cmpy-mgmt-warehouse-product-div"} key={props.key}>
<p className={"tooltip"}>
{product.name}: {numeralWrapper.format(product.data[city][0], nf)} ({numeralWrapper.format(totalGain, nf)}/s)
<span className={"tooltiptext"}>
Prod: {numeralWrapper.format(product.data[city][1], nf)}/s
<br />
Sell: {numeralWrapper.format(product.data[city][2], nf)} /s
</span>
</p>
<p className={"tooltip"}>
Rating: {numeralWrapper.format(product.rat, nf)}
<span className={"tooltiptext"}>
Quality: {numeralWrapper.format(product.qlt, nf)} <br />
Performance: {numeralWrapper.format(product.per, nf)} <br />
Durability: {numeralWrapper.format(product.dur, nf)} <br />
Reliability: {numeralWrapper.format(product.rel, nf)} <br />
Aesthetics: {numeralWrapper.format(product.aes, nf)} <br />
Features: {numeralWrapper.format(product.fea, nf)}
{
corp.unlockUpgrades[2] === 1 && <br />
}
{
corp.unlockUpgrades[2] === 1 &&
"Demand: " + numeralWrapper.format(product.dmd, nf)
}
{
corp.unlockUpgrades[3] === 1 && <br />
}
{
corp.unlockUpgrades[3] === 1 &&
"Competition: " + numeralWrapper.format(product.cmp, nf)
}
</span>
</p>
<p className={"tooltip"}>
Est. Production Cost: {numeralWrapper.formatMoney(product.pCost / ProductProductionCostRatio)}
<span className={"tooltiptext"}>
An estimate of the material cost it takes to create this Product.
</span>
</p>
<p className={"tooltip"}>
Est. Market Price: {numeralWrapper.formatMoney(product.pCost + product.rat / product.mku)}
<span className={"tooltiptext"}>
An estimate of how much consumers are willing to pay for this product.
Setting the sale price above this may result in less sales. Setting the sale price below this may result
in more sales.
</span>
</p>
<div>
<button className={"std-button"} onClick={sellButtonOnClick}>
{sellButtonText}
</button><br />
<button className={"std-button"} onClick={limitProductionButtonOnClick}>
{limitProductionButtonText}
</button>
<button className={"std-button"} onClick={discontinueButtonOnClick}>
Discontinue
</button>
</div>
</div>
)
}
// Creates the UI for a single Material type
function MaterialComponent(props) {
const corp = props.corp;
const division = props.division;
const warehouse = props.warehouse;
const mat = props.mat;
const eventHandler = props.eventHandler;
// Numeraljs formatter
const nf = "0.000";
// Total gain or loss of this material (per second)
const totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp;
// Competition and demand info, if they're unlocked
let cmpAndDmdText = "";
if (corp.unlockUpgrades[2] === 1) {
cmpAndDmdText += "<br>Demand: " + numeralWrapper.format(mat.dmd, nf);
}
if (corp.unlockUpgrades[3] === 1) {
cmpAndDmdText += "<br>Competition: " + numeralWrapper.format(mat.cmp, nf);
}
// Flag that determines whether this industry is "new" and the current material should be
// marked with flashing-red lights
const tutorial = division.newInd && Object.keys(division.reqMats).includes(mat.name) &&
mat.buy === 0 && mat.imp === 0;
// Purchase material button
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nf)})`;
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division);
// Export material button
const exportButtonOnClick = eventHandler.createExportMaterialPopup.bind(eventHandler, mat);
// Sell material button
let sellButtonText;
if (mat.sllman[0]) {
sellButtonText = (mat.sllman[1] === -1 ? "Sell (" + numeralWrapper.format(mat.sll, nf) + "/MAX)" :
"Sell (" + numeralWrapper.format(mat.sll, nf) + "/" + numeralWrapper.format(mat.sllman[1], nf) + ")");
if (mat.sCost) {
if (isString(mat.sCost)) {
var sCost = mat.sCost.replace(/MP/g, mat.bCost);
sellButtonText += " @ $" + numeralWrapper.format(eval(sCost), "0.00");
} else {
sellButtonText += " @ $" + numeralWrapper.format(mat.sCost, "0.00");
}
}
} else {
sellButtonText = "Sell (0.000/0.000)";
}
const sellButtonOnClick = eventHandler.createSellMaterialPopup.bind(eventHandler, mat);
// Market TA button
const marketTaButtonOnClick = eventHandler.createMarketTaPopup.bind(eventHandler, mat, division);
return (
<div className={"cmpy-mgmt-warehouse-material-div"} key={props.key}>
<div style={{display: "inline-block"}}>
<p className={"tooltip"}>
{mat.name}: {numeralWrapper.format(mat.qty, nf)} ({numeralWrapper.format(totalGain, nf)}/s)
<span className={"tooltiptext"}>
Buy: {numeralWrapper.format(mat.buy, nf)} <br />
Prod: {numeralWrapper.format(mat.prd, nf)} <br />
Sell: {numeralWrapper.format(mat.sll, nf)} <br />
Export: {numeralWrapper.format(mat.totalExp, nf)} <br />
Import: {numeralWrapper.format(mat.imp, nf)}
{
corp.unlockUpgrades[2] === 1 && <br />
}
{
corp.unlockUpgrades[2] === 1 &&
"Demand: " + numeralWrapper.format(mat.dmd, nf)
}
{
corp.unlockUpgrades[3] === 1 && <br />
}
{
corp.unlockUpgrades[3] === 1 &&
"Competition: " + numeralWrapper.format(mat.cmp, nf)
}
</span>
</p><br />
<p className={"tooltip"}>
MP: {numeralWrapper.formatMoney(mat.bCost)}
<span className={"tooltiptext"}>
Market Price: The price you would pay if you were to buy this material on the market
</span>
</p> <br />
<p className={"tooltip"}>
Quality: {numeralWrapper.format(mat.qlt, "0.00")}
<span className={"tooltiptext"}>
The quality of your material. Higher quality will lead to more sales
</span>
</p>
</div>
<div style={{display: "inline-block"}}>
<button className={purchaseButtonClass} onClick={purchaseButtonOnClick}>
{purchaseButtonText}
{
tutorial &&
<span className={"tooltiptext"}>
Purchase your required materials to get production started!
</span>
}
</button>
{
corp.unlockUpgrades[0] === 1 &&
<button className={"std-button"} onClick={exportButtonOnClick}>
Export
</button>
}
<br />
<button className={"std-button"} onClick={sellButtonOnClick}>
{sellButtonText}
</button>
{
division.hasResearch("Market-TA.I") &&
<button className={"std-button"} onClick={marketTaButtonOnClick}>
Market-TA
</button>
}
</div>
</div>
)
}
export class IndustryWarehouse extends BaseReactComponent {
renderWarehouseUI() {
const corp = this.corp();
const division = this.routing().currentDivision; // Validated in render()
const warehouse = division.warehouses[this.props.currentCity]; // Validated in render()
// General Storage information at the top
const sizeUsageStyle = {
color: warehouse.sizeUsed >= warehouse.size ? "red" : "white",
margin: "5px",
}
// Upgrade Warehouse size button
const sizeUpgradeCost = WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
const canAffordUpgrade = (corp.funds.gt(sizeUpgradeCost));
const upgradeWarehouseClass = canAffordUpgrade ? "std-button" : "a-link-button-inactive";
const upgradeWarehouseOnClick = () => {
++warehouse.level;
warehouse.updateSize(corp, division);
corp.funds = corp.funds.minus(sizeUpgradeCost);
warehouse.createUI(parentRefs);
return;
}
// Industry material Requirements
let generalReqsText = "This Industry uses [" + Object.keys(division.reqMats).join(", ") +
"] in order to ";
if (division.prodMats.length > 0) {
generalReqsText += "produce [" + division.prodMats.join(", ") + "] ";
if (division.makesProducts) {
generalReqsText += " and " + division.getProductDescriptionText();
}
} else if (division.makesProducts) {
generalReqsText += (division.getProductDescriptionText() + ".");
}
const ratioLines = [];
for (const matName in division.reqMats) {
if (division.reqMats.hasOwnProperty(matName)) {
const text = [" *", division.reqMats[matName], matName].join(" ");
ratioLines.push((
<div key={matName}>
<p>{text}</p>
</div>
));
}
}
let createdItemsText = "in order to create ";
if (division.prodMats.length > 0) {
createdItemsText += "one of each produced Material (" + division.prodMats.join(", ") + ") ";
if (division.makesProducts) {
createdItemsText += "or to create one of its Products";
}
} else if (division.makesProducts) {
createdItemsText += "one of its Products";
}
// Current State:
let stateText;
switch(division.state) {
case "START":
stateText = "Current state: Preparing...";
break;
case "PURCHASE":
stateText = "Current state: Purchasing materials...";
break;
case "PRODUCTION":
stateText = "Current state: Producing materials and/or products...";
break;
case "SALE":
stateText = "Current state: Selling materials and/or products...";
break;
case "EXPORT":
stateText = "Current state: Exporting materials and/or products...";
break;
default:
console.error(`Invalid state: ${division.state}`);
break;
}
// Smart Supply Checkbox
const smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox";
const smartSupplyOnChange = (e) => {
warehouse.smartSupplyEnabled = e.target.value;
}
// Materials that affect Production multiplier
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate"];
// Returns a boolean indicating whether the given material is relevant for the
// current industry.
function isRelevantMaterial(matName) {
if (Object.keys(division.reqMats).includes(matName)) { return true; }
if (division.prodMats.includes(matName)) { return true; }
if (prodMultiplierMats.includes(matName)) { return true; }
return false;
}
// Create React components for materials
const mats = [];
for (const matName in warehouse.materials) {
if (warehouse.materials[matName] instanceof Material) {
// Only create UI for materials that are relevant for the industry
if (isRelevantMaterial(matName)) {
mats.push(MaterialComponent({
corp: corp,
division: division,
eventHandler: this.eventHandler(),
key: matName,
mat: warehouse.materials[matName],
warehouse: warehouse,
}));
}
}
}
// Create React components for products
const products = [];
if (division.makesProducts && Object.keys(division.products).length > 0) {
for (const productName in division.products) {
if (division.products[productName] instanceof Product) {
products.push({
corp: corp,
division: division,
eventHandler: this.eventHandler(),
key: productName,
product: division.products[productName],
warehouse: warehouse,
})
}
}
}
return (
<div className={"cmpy-mgmt-warehouse-panel"}>
<p className={"tooltip"} style={sizeUsageStyle}>
Storage: {numeralWrapper.format(warehouse.sizeUsed, "0.000")} / {numeralWrapper.format(warehouse.size, "0.000")}
<span className={"tooltiptext"}>
{warehouse.breakdown}
</span>
</p>
<button className={upgradeWarehouseClass} onClick={upgradeWarehouseOnClick}>
Upgrade Warehouse Size - {numeralWrapper.formatMoney(sizeUpgradeCost)}
</button>
<p>{generalReqsText}. The exact requirements for production are:</p><br />
{ratioLines}<br />
<p>{createdItemsText}</p>
<p>
To get started with production, purchase your required materials
or import them from another of your company's divisions.
</p><br />
<p>{stateText}</p>
{
corp.unlockUpgrades[1] &&
<div>
<label style={{color: "white"}} for={smartSupplyCheckboxId}>
Enable Smart Supply
</label>
<input type={"checkbox"}
id={smartSupplyCheckboxId}
onChange={smartSupplyOnChange}
value={warehouse.smartSupplyEnabled}
/>
</div>
}
{mats}
{products}
</div>
)
}
render() {
const corp = this.corp();
const division = this.routing().currentDivision;
if (division == null) {
throw new Error(`Routing does not hold reference to the current Industry`);
}
const warehouse = division.warehouses[this.props.currentCity];
const newWarehouseOnClick = this.eventHandler().purchaseWarehouse.bind(this.eventHandler(), division, this.props.currentCity);
if (warehouse instanceof Warehouse) {
return this.renderWarehouseUI();
} else {
return (
<button className={"std-button"} onClick={newWarehouseOnClick}>
Purchase Warehouse ({numeralWrapper.formatMoney(WarehouseInitialCost)})
</button>
)
}
}
}

@ -0,0 +1,35 @@
// React components for the levelable upgrade buttons on the overview panel
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox";
export class LevelableUpgrade extends BaseReactComponent {
render() {
const data = this.props.upgradeData;
const level = this.props.upgradeLevel;
const baseCost = data[1];
const priceMult = data[2];
const cost = baseCost * Math.pow(priceMult, level);
const text = `${data[4]} - ${numeralWrapper.formatMoney(cost)}`
const tooltip = data[5];
const onClick = () => {
if (this.corp().funds.lt(cost)) {
dialogBoxCreate("Insufficient funds");
} else {
this.corp().upgrade(data);
//this.corp().displayCorporationOverviewContent();
}
}
return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{"width" : "45%"}} onClick={onClick}>
{text}
<span className={"tooltiptext"}>{tooltip}</span>
</div>
)
}
}

@ -0,0 +1,91 @@
// React Component for the element that contains the actual info/data
// for the Corporation UI. This panel lies below the header tabs and will
// be filled with whatever is needed based on the routing/navigation
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { CityTabs } from "./CityTabs";
import { Industry } from "./Industry";
import { Overview } from "./Overview";
import { overviewPage } from "./Routing";
import { Cities } from "../../Locations/Cities";
export class MainPanel extends BaseReactComponent {
constructor(props) {
super(props);
this.state = {
division: "",
city: Cities.Sector12,
}
}
// Determines what UI content to render based on routing
renderContent() {
if (this.routing().isOnOverviewPage()) {
// Corporation overview Content
return this.renderOverviewPage();
} else {
// Division content
// First, check if we're at a new division. If so, we need to reset the city to Sector-12
// Otherwise, just switch the 'city' state
const currentDivision = this.routing().current();
if (currentDivision !== this.state.division) {
this.state.division = currentDivision;
this.state.city = Cities.Sector12;
}
return this.renderDivisionPage();
}
}
renderOverviewPage() {
return (
<div id="cmpy-mgmt-panel">
<Overview {...this.props} />
</div>
)
}
renderDivisionPage() {
// Note: Division is the same thing as Industry...I wasn't consistent with naming
const division = this.routing().currentDivision;
if (division == null) {
throw new Error(`Routing does not hold reference to the current Industry`);
}
// City tabs
const onClicks = {};
for (const cityName in division.offices) {
onClicks[cityName] = () => {
this.state.city = cityName;
this.corp().rerender();
}
}
const cityTabs = (
<CityTabs
{...this.props}
city={this.state.city}
onClicks={onClicks}
/>
)
// Rest of Industry UI
const industry = (
<Industry {...this.props} currentCity={this.state.city} />
)
return (
<div id="cmpy-mgmt-panel">
{cityTabs}
{industry}
</div>
)
}
render() {
return this.renderContent();
}
}

@ -0,0 +1,323 @@
// React Component for displaying Corporation Overview info
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { LevelableUpgrade } from "./LevelableUpgrade";
import { UnlockUpgrade } from "./UnlockUpgrade";
import { BribeThreshold } from "../Corporation";
import { CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
import { CorporationUpgrades } from "../data/CorporationUpgrades";
import { CONSTANTS } from "../../Constants";
import { numeralWrapper } from "../../ui/numeralFormat";
export class Overview extends BaseReactComponent {
// Generic Function for Creating a button
createButton(props) {
let className = props.class ? props.class : "std-button";
const displayStyle = props.display ? props.display : "block";
const hasTooltip = (props.tooltip != null);
if (hasTooltip) {
className += " tooltip";
}
return (
<a className={className} onClick={props.onClick} style={{display: {displayStyle}}}>
{props.text}
{
hasTooltip &&
<span className={"tooltiptext"}>
{props.tooltip}
</span>
}
</a>
)
}
// Returns a string with general information about Corporation
getOverviewText() {
// Formatted text for profit
var profit = this.corp().revenue.minus(this.corp().expenses).toNumber(),
profitStr = profit >= 0 ? numeralWrapper.formatMoney(profit) : "-" + numeralWrapper.format(-1 * profit, "$0.000a");
// Formatted text for dividend information, if applicable
let dividendStr = "";
if (this.corp().dividendPercentage > 0 && profit > 0) {
const totalDividends = (this.corp().dividendPercentage / 100) * profit;
const retainedEarnings = profit - totalDividends;
const dividendsPerShare = totalDividends / this.corp().totalShares;
const playerEarnings = this.corp().numShares * dividendsPerShare;
dividendStr = `Retained Profits (after dividends): ${numeralWrapper.format(retainedEarnings, "$0.000a")} / s<br><br>` +
`Dividend Percentage: ${numeralWrapper.format(this.corp().dividendPercentage / 100, "0%")}<br>` +
`Dividends per share: ${numeralWrapper.format(dividendsPerShare, "$0.000a")} / s<br>` +
`Your earnings as a shareholder (Pre-Tax): ${numeralWrapper.format(playerEarnings, "$0.000a")} / s<br>` +
`Dividend Tax Rate: ${this.corp().dividendTaxPercentage}%<br>` +
`Your earnings as a shareholder (Post-Tax): ${numeralWrapper.format(playerEarnings * (1 - (this.corp().dividendTaxPercentage / 100)), "$0.000a")} / s<br>`;
}
let txt = "Total Funds: " + numeralWrapper.format(this.corp().funds.toNumber(), '$0.000a') + "<br>" +
"Total Revenue: " + numeralWrapper.format(this.corp().revenue.toNumber(), "$0.000a") + " / s<br>" +
"Total Expenses: " + numeralWrapper.format(this.corp().expenses.toNumber(), "$0.000a") + "/ s<br>" +
"Total Profits: " + profitStr + " / s<br>" +
dividendStr +
"Publicly Traded: " + (this.corp().public ? "Yes" : "No") + "<br>" +
"Owned Stock Shares: " + numeralWrapper.format(this.corp().numShares, '0.000a') + "<br>" +
"Stock Price: " + (this.corp().public ? "$" + numeralWrapper.formatMoney(this.corp().sharePrice) : "N/A") + "<br>" +
"<p class='tooltip'>Total Stock Shares: " + numeralWrapper.format(this.corp().totalShares, "0.000a") +
"<span class='tooltiptext'>" +
`Outstanding Shares: ${numeralWrapper.format(this.corp().issuedShares, "0.000a")}<br>` +
`Private Shares: ${numeralWrapper.format(this.corp().totalShares - this.corp().issuedShares - this.corp().numShares, "0.000a")}` +
"</span></p><br><br>";
const storedTime = this.corp().storedCycles * CONSTANTS.MilliPerCycle / 1000;
if (storedTime > 15) {
txt += `Bonus Time: ${storedTime} seconds<br><br>`;
}
let prodMult = this.corp().getProductionMultiplier(),
storageMult = this.corp().getStorageMultiplier(),
advMult = this.corp().getAdvertisingMultiplier(),
empCreMult = this.corp().getEmployeeCreMultiplier(),
empChaMult = this.corp().getEmployeeChaMultiplier(),
empIntMult = this.corp().getEmployeeIntMultiplier(),
empEffMult = this.corp().getEmployeeEffMultiplier(),
salesMult = this.corp().getSalesMultiplier(),
sciResMult = this.corp().getScientificResearchMultiplier();
if (prodMult > 1) {txt += "Production Multiplier: " + numeralWrapper.format(prodMult, "0.000") + "<br>";}
if (storageMult > 1) {txt += "Storage Multiplier: " + numeralWrapper.format(storageMult, "0.000") + "<br>";}
if (advMult > 1) {txt += "Advertising Multiplier: " + numeralWrapper.format(advMult, "0.000") + "<br>";}
if (empCreMult > 1) {txt += "Empl. Creativity Multiplier: " + numeralWrapper.format(empCreMult, "0.000") + "<br>";}
if (empChaMult > 1) {txt += "Empl. Charisma Multiplier: " + numeralWrapper.format(empChaMult, "0.000") + "<br>";}
if (empIntMult > 1) {txt += "Empl. Intelligence Multiplier: " + numeralWrapper.format(empIntMult, "0.000") + "<br>";}
if (empEffMult > 1) {txt += "Empl. Efficiency Multiplier: " + numeralWrapper.format(empEffMult, "0.000") + "<br>";}
if (salesMult > 1) {txt += "Sales Multiplier: " + numeralWrapper.format(salesMult, "0.000") + "<br>";}
if (sciResMult > 1) {txt += "Scientific Research Multiplier: " + numeralWrapper.format(sciResMult, "0.000") + "<br>";}
return txt;
}
// Render the buttons that lie below the overview text.
// These are mainly for things such as managing finances/stock
renderButtons() {
// Create a "Getting Started Guide" button that lets player view the
// handbook and adds it to the players home computer
const getStarterGuideOnClick = this.corp().getStarterGuide.bind(this.corp());
const getStarterGuideBtn = this.createButton({
class: "a-link-button",
display: "inline-block",
onClick: getStarterGuideOnClick,
text: "Getting Started Guide",
tooltip: "Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " +
"This is a .lit file that guides you through the beginning of setting up a Corporation and " +
"provides some tips/pointers for helping you get started with managing it.",
});
// Create a "Bribe Factions" button if your Corporation is powerful enough.
// This occurs regardless of whether you're public or private
const canBribe = (this.corp().determineValuation() >= BribeThreshold);
const bribeFactionsOnClick = this.eventHandler().createBribeFactionsPopup.bind(this.eventHandler());
const bribeFactionsClass = (canBribe ? "a-link-button" : "a-link-button-inactive");
const bribeFactionsBtn = this.createButton({
class: bribeFactionsClass,
display: "inline-block",
onClick: bribeFactionsOnClick,
text: "Bribe Factions",
tooltip: (canBribe
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
: "Your Corporation is not powerful enough to bribe Faction leaders"),
});
const generalBtns = {
bribeFactions: bribeFactionsBtn,
getStarterGuide: getStarterGuideBtn,
};
if (this.corp().public) {
return this.renderPublicButtons(generalBtns);
} else {
return this.renderPrivateButtons(generalBtns);
}
}
// Render the buttons for when your Corporation is still private
renderPrivateButtons(generalBtns) {
const fundingAvailable = (this.corp().fundingRound < 4);
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
const findInvestorsTooltip = fundingAvailable ? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company" : null;
const findInvestorsOnClick = this.corp().getInvestment.bind(this.corp());
const goPublicOnClick = this.corp().goPublic.bind(this.corp());
const findInvestorsBtn = this.createButton({
class: findInvestorsClassName,
onClick: findInvestorsOnClick,
style: "inline-block",
text: "Find Investors",
tooltip: findInvestorsTooltip
});
const goPublicBtn = this.createButton({
class: "std-button",
onClick: goPublicOnClick,
style: "inline-block",
text: "Go Public",
tooltip: "Become a publicly traded and owned entity. Going public " +
"involves issuing shares for an IPO. Once you are a public " +
"company, your shares will be traded on the stock market."
});
return (
<div>
{generalBtns.getStarterGuide}
{findInvestorsBtn}
{goPublicBtn}
<br />
{generalBtns.bribeFactions}
</div>
)
}
// Render the buttons for when your Corporation has gone public
renderPublicButtons(generalBtns) {
const corp = this.corp();
const sellSharesOnClick = this.eventHandler().createSellSharesPopup.bind(this.eventHandler());
const sellSharesOnCd = (corp.shareSaleCooldown > 0);
const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button";
const sellSharesTooltip = sellSharesOnCd
? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown)
: "Sell your shares in the company. The money earned from selling your " +
"shares goes into your personal account, not the Corporation's. " +
"This is one of the only ways to profit from your business venture."
const sellSharesBtn = this.createButton({
class: sellSharesClass,
display: "inline-block",
onClick: sellSharesOnClick,
text: "Sell Shares",
tooltip: sellSharesTooltip,
});
const buybackSharesOnClick = this.eventHandler().createBuybackSharesPopup.bind(this.eventHandler());
const buybackSharesBtn = this.createButton({
class: "std-button",
display: "inline-block",
onClick: buybackSharesOnClick,
text: "Buyback shares",
tooltip: "Buy back shares you that previously issued or sold at market price.",
});
const issueNewSharesOnClick = this.eventHandler().createIssueNewSharesPopup.bind(this.eventHandler());
const issueNewSharesOnCd = (corp.issueNewSharesCooldown > 0);
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
const issueNewSharesTooltip = issueNewSharesOnCd
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
: "Issue new equity shares to raise capital.";
const issueNewSharesBtn = this.createButton({
class: issueNewSharesClass,
display: "inline-block",
onClick: issueNewSharesOnClick,
text: "Issue New Shares",
tooltip: issueNewSharesTooltip,
});
const issueDividendsOnClick = this.eventHandler().createIssueDividendsPopup.bind(this.eventHandler());
const issueDividendsBtn = this.createButton({
class: "std-button",
display: "inline-block",
onClick: issueDividendsOnClick,
text: "Issue Dividends",
tooltip: "Manage the dividends that are paid out to shareholders (including yourself)",
});
return (
<div>
{generalBtns.getStarterGuide}
{sellSharesBtn}
{buybackSharesBtn}
<br />
{issueNewSharesBtn}
{issueDividendsBtn}
<br />
{generalBtns.bribeFactions}
</div>
)
}
// Render the UI for Corporation upgrades
renderUpgrades() {
// Don't show upgrades
if (this.corp().divisions.length <= 0) { return; }
// Create an array of all Unlocks
const unlockUpgrades = [];
Object.values(CorporationUnlockUpgrades).forEach((unlockData) => {
if (this.corp().unlockUpgrades[unlockData[0]] === 0) {
unlockUpgrades.push(this.renderUnlockUpgrade(unlockData));
}
});
// Create an array of properties of all unlocks
const levelableUpgradeProps = [];
for (let i = 0; i < this.corp().upgrades.length; ++i) {
const upgradeData = CorporationUpgrades[i];
const level = this.corp().upgrades[i];
levelableUpgradeProps.push({
upgradeData: upgradeData,
upgradeLevel: level,
});
}
return (
<div className={"cmpy-mgmt-upgrade-container"}>
<h1 className={"cmpy-mgmt-upgrade-header"}> Unlocks </h1>
{unlockUpgrades}
<h1 className={"cmpy-mgmt-upgrade-header"}> Upgrades </h1>
{
levelableUpgradeProps.map((data) => {
return this.renderLevelableUpgrade(data);
})
}
</div>
)
}
renderUnlockUpgrade(data) {
return (
<UnlockUpgrade
{...this.props}
upgradeData={data}
key={data[0]}
/>
)
}
renderLevelableUpgrade(data) {
return (
<LevelableUpgrade
{...this.props}
upgradeData={data.upgradeData}
upgradeLevel={data.upgradeLevel}
key={data.upgradeData[0]}
/>
)
}
render() {
return (
<div>
<p dangerouslySetInnerHTML={{__html: this.getOverviewText()}}></p>
{this.renderButtons()}
<br />
{this.renderUpgrades()}
</div>
)
}
}

@ -0,0 +1,17 @@
// Root React Component for the Corporation UI
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { HeaderTabs } from "./HeaderTabs";
import { MainPanel } from "./MainPanel";
export class CorporationRoot extends BaseReactComponent {
render() {
return (
<div>
<HeaderTabs {...this.props} />
<MainPanel {...this.props} />
</div>
)
}
}

@ -0,0 +1,96 @@
import { IMap } from "../../types";
export const overviewPage: string = "Overview";
// Interfaces for whatever's required to sanitize routing with Corporation Data
interface IOfficeSpace {
}
interface IDivision {
name: string;
offices: IMap<IOfficeSpace>
}
interface ICorporation {
divisions: IDivision[];
}
/**
* Keeps track of what content is currently being displayed for the Corporation UI
*/
export class CorporationRouting {
private currentPage: string = overviewPage;
// Stores a reference to the Corporation instance
private corp: ICorporation;
// Stores a reference to the Division instance that the routing is currently on
// This will be null if routing is on the overview page
currentDivision: IDivision | null = null;
constructor(corp: ICorporation) {
this.corp = corp;
}
current(): string {
return this.currentPage;
}
/**
* Checks that the specified page has a valid value
*/
isValidPage(page: string): boolean {
if (page === overviewPage) { return true; }
for (const division of this.corp.divisions) {
if (division.name === page) { return true; }
}
return false;
}
/**
* Returns a boolean indicating whether or not the player is on the given page
*/
isOn(page: string): boolean {
if (!this.isValidPage(page)) { return false; }
return page === this.currentPage;
}
isOnOverviewPage(): boolean {
return this.currentPage === overviewPage;
}
/**
* Routes to the specified page
*/
routeTo(page: string): void {
if (!this.isValidPage(page)) { return; }
this.currentDivision = null;
if (page !== overviewPage) {
// Iterate through Corporation data to get a reference to the current division
for (let i = 0; i < this.corp.divisions.length; ++i) {
if (this.corp.divisions[i].name === page) {
this.currentDivision = this.corp.divisions[i];
};
}
// 'currentDivision' should not be null, since the routing is either on
// the overview page or a division page
if (this.currentDivision == null) {
console.warn(`Routing could not find division ${page}`);
}
}
this.currentPage = page;
}
routeToOverviewPage(): void {
this.currentPage = overviewPage;
this.currentDivision = null;
}
}

@ -0,0 +1,29 @@
// React Components for the Unlock upgrade buttons on the overview page
import React from "react";
import { BaseReactComponent } from "./BaseReactComponent";
import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox";
export class UnlockUpgrade extends BaseReactComponent {
render() {
const data = this.props.upgradeData;
const text = `${data[2]} - ${numeralWrapper.formatMoney(data[1])}`;
const tooltip = data[3];
const onClick = () => {
if (this.corp().funds.lt(data[1])) {
dialogBoxCreate("Insufficient funds");
} else {
this.corp().unlock(data);
//this.corp().displayCorporationOverviewContent();
}
}
return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{"width" : "45%"}} onClick={onClick}>
{text}
<span className={"tooltiptext"}>{tooltip}</span>
</div>
)
}
}

@ -44,6 +44,7 @@ import { AllServers,
import { Server } from "./Server/Server";
import { GetServerByHostname,
getServer,
getServerOnNetwork,
numCycleForGrowth,
processSingleServerGrowth } from "./Server/ServerHelpers";
import { getPurchaseServerCost,

@ -26,10 +26,10 @@ import {Player} from "./Player";
import { AllServers,
AddToAllServers,
initForeignServers,
prestigeAllServers } from "./Server/AllServers";
import { Server } from "./Server/Server"
import { initForeignServers,
prestigeHomeComputer } from "./Server/ServerHelpers";
import { prestigeHomeComputer } from "./Server/ServerHelpers";
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
import { SpecialServerIps,
SpecialServerIpsMap,

@ -208,6 +208,7 @@ CodeMirror.defineMode("netscript", function(config, parserConfig) {
"getSkillNames": atom,
"startAction": atom,
"stopBladeburnerAction": atom,
"getCurrentAction": atom,
"getActionTime": atom,
"getActionEstimatedSuccessChance": atom,
"getActionCountRemaining": atom,

@ -53,9 +53,9 @@ import { getCurrentEditor,
loadAllRunningScripts,
scriptEditorInit,
updateScriptEditorContent } from "./Script/ScriptHelpers";
import { AllServers } from "./Server/AllServers";
import { AllServers,
initForeignServers } from "./Server/AllServers";
import { Server } from "./Server/Server";
import { initForeignServers } from "./Server/ServerHelpers";
import {Settings} from "./Settings/Settings";
import { initSourceFiles, SourceFiles } from "./SourceFile";
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
@ -458,8 +458,8 @@ const Engine = {
if (Player.corporation instanceof Corporation) {
Engine.hideAllContent();
document.getElementById("character-overview-wrapper").style.visibility = "hidden";
Player.corporation.createUI();
routing.navigateTo(Page.Corporation);
Player.corporation.createUI();
}
},
@ -943,9 +943,7 @@ const Engine = {
}
if (Engine.Counters.updateDisplaysMed <= 0) {
if (routing.isOn(Page.Corporation)) {
Player.corporation.updateUIContent();
} else if (routing.isOn(Page.CharacterInfo)) {
if (routing.isOn(Page.CharacterInfo)) {
Engine.updateCharacterInfo();
}
Engine.Counters.updateDisplaysMed = 9;

@ -1,6 +1,7 @@
{
"compilerOptions": {
"baseUrl" : ".",
"jsx": "react",
"lib" : ["es2016", "dom"],
"module": "commonjs",
"target": "es6",

@ -84,6 +84,13 @@ module.exports = (env, argv) => {
loader: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.(jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.s?css$/,
use: [
@ -125,7 +132,8 @@ module.exports = (env, argv) => {
extensions: [
".tsx",
".ts",
".js"
".js",
".jsx",
]
}
};