mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-22 15:43:49 +01:00
Migrated Corporation UI implementation to use React
This commit is contained in:
parent
f3dbdad011
commit
3e10f5de6d
3
.babelrc
Normal file
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
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
2343
src/Corporation/Corporation.jsx
Normal file
2343
src/Corporation/Corporation.jsx
Normal file
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;
|
||||
@ -38,14 +40,15 @@ export class Research {
|
||||
this.name = p.name;
|
||||
this.cost = p.cost;
|
||||
this.desc = p.desc;
|
||||
if (p.advertisingMult) { this.advertisingMult = p.advertisingMult; }
|
||||
if (p.employeeChaMult) { this.employeeChaMult = p.employeeChaMult; }
|
||||
if (p.employeeCreMult) { this.employeeCreMult = p.employeeCreMult; }
|
||||
if (p.employeeEffMult) { this.employeeEffMult = p.employeeEffMult; }
|
||||
if (p.employeeIntMult) { this.employeeIntMult = p.employeeIntMult; }
|
||||
if (p.productionMult) { this.productionMult = p.productionMult; }
|
||||
if (p.salesMult) { this.salesMult = p.salesMult; }
|
||||
if (p.sciResearchMult) { this.sciResearchMult = p.sciResearchMult; }
|
||||
if (p.storageMult) { this.storageMult = p.storageMult; }
|
||||
if (p.advertisingMult) { this.advertisingMult = p.advertisingMult; }
|
||||
if (p.employeeChaMult) { this.employeeChaMult = p.employeeChaMult; }
|
||||
if (p.employeeCreMult) { this.employeeCreMult = p.employeeCreMult; }
|
||||
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");
|
||||
}
|
||||
|
100
src/Corporation/Warehouse.ts
Normal file
100
src/Corporation/Warehouse.ts
Normal file
@ -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,
|
||||
},
|
||||
];
|
||||
|
22
src/Corporation/ui/BaseReactComponent.js
Normal file
22
src/Corporation/ui/BaseReactComponent.js
Normal file
@ -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() {}
|
||||
}
|
56
src/Corporation/ui/CityTabs.jsx
Normal file
56
src/Corporation/ui/CityTabs.jsx
Normal file
@ -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;
|
||||
}
|
||||
}
|
1478
src/Corporation/ui/CorporationUIEventHandler.js
Normal file
1478
src/Corporation/ui/CorporationUIEventHandler.js
Normal file
File diff suppressed because it is too large
Load Diff
80
src/Corporation/ui/HeaderTabs.jsx
Normal file
80
src/Corporation/ui/HeaderTabs.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
34
src/Corporation/ui/Industry.jsx
Normal file
34
src/Corporation/ui/Industry.jsx
Normal file
@ -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>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
557
src/Corporation/ui/IndustryOffice.jsx
Normal file
557
src/Corporation/ui/IndustryOffice.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
261
src/Corporation/ui/IndustryOverview.jsx
Normal file
261
src/Corporation/ui/IndustryOverview.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
486
src/Corporation/ui/IndustryWarehouse.jsx
Normal file
486
src/Corporation/ui/IndustryWarehouse.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
35
src/Corporation/ui/LevelableUpgrade.jsx
Normal file
35
src/Corporation/ui/LevelableUpgrade.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
91
src/Corporation/ui/MainPanel.jsx
Normal file
91
src/Corporation/ui/MainPanel.jsx
Normal file
@ -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();
|
||||
}
|
||||
}
|
323
src/Corporation/ui/Overview.jsx
Normal file
323
src/Corporation/ui/Overview.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
17
src/Corporation/ui/Root.jsx
Normal file
17
src/Corporation/ui/Root.jsx
Normal file
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
96
src/Corporation/ui/Routing.ts
Normal file
96
src/Corporation/ui/Routing.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
29
src/Corporation/ui/UnlockUpgrade.jsx
Normal file
29
src/Corporation/ui/UnlockUpgrade.jsx
Normal file
@ -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",
|
||||
]
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user