mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-27 01:53:48 +01:00
merge base
This commit is contained in:
commit
9c23fc89d1
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.DS_Store
|
||||
.history
|
||||
.vscode
|
||||
Changelog.txt
|
||||
Netburner.txt
|
||||
|
16
dist/bitburner.d.ts
vendored
16
dist/bitburner.d.ts
vendored
@ -1773,6 +1773,18 @@ export declare interface Grafting {
|
||||
*/
|
||||
getAugmentationGraftTime(augName: string): number;
|
||||
|
||||
/**
|
||||
* Retrieves a list of Augmentations that can be grafted.
|
||||
* @remarks
|
||||
* RAM cost: 5 GB
|
||||
*
|
||||
* Note that this function returns a list of currently graftable Augmentations,
|
||||
* based off of the Augmentations that you already own.
|
||||
*
|
||||
* @returns An array of graftable Augmentations.
|
||||
*/
|
||||
getGraftableAugmentations(): string[];
|
||||
|
||||
/**
|
||||
* Begins grafting the named aug. You must be in New Tokyo to use this.
|
||||
* @remarks
|
||||
@ -2911,9 +2923,11 @@ export declare interface NS {
|
||||
* Returns the security increase that would occur if a grow with this many threads happened.
|
||||
*
|
||||
* @param threads - Amount of threads that will be used.
|
||||
* @param hostname - Optional. Hostname of the target server. The number of threads is limited to the number needed to hack the servers maximum amount of money.
|
||||
* @param cores - Optional. The number of cores of the server that would run grow.
|
||||
* @returns The security increase.
|
||||
*/
|
||||
growthAnalyzeSecurity(threads: number): number;
|
||||
growthAnalyzeSecurity(threads: number, hostname?: string, cores?: number): number;
|
||||
|
||||
/**
|
||||
* Suspends the script for n milliseconds.
|
||||
|
4
dist/main.bundle.js
vendored
4
dist/main.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/main.bundle.js.map
vendored
2
dist/main.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
40
dist/vendor.bundle.js
vendored
40
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/vendor.bundle.js.map
vendored
2
dist/vendor.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
@ -66,7 +66,7 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# The short X.Y version.
|
||||
version = '1.6'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.6.3'
|
||||
release = '1.6.4'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -1,453 +0,0 @@
|
||||
:root {
|
||||
--dark-text-color: #0c0;
|
||||
--dark-link-color: #090;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.wy-nav-content-wrap {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-nav-content {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.section {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.rst-content .highlighted {
|
||||
background: #333;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: #17181c;
|
||||
}
|
||||
|
||||
.highlight .nn {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.highlight .nb {
|
||||
color: #8bb8df;
|
||||
}
|
||||
|
||||
.highlight .kn,
|
||||
.highlight .kc,
|
||||
.highlight .k {
|
||||
color: #41c2ea;
|
||||
}
|
||||
|
||||
.highlight .s1,
|
||||
.highlight .s2 {
|
||||
color: #b3e87f;
|
||||
}
|
||||
|
||||
.highlight .nt {
|
||||
color: #ccb350;
|
||||
}
|
||||
|
||||
.highlight .c1 {
|
||||
color: #686868;
|
||||
}
|
||||
|
||||
.rst-content div[class^="highlight"] {
|
||||
border-color: #1a1a1a;
|
||||
}
|
||||
|
||||
.icon,
|
||||
.icon-home {
|
||||
color: var(--dark-link-color);
|
||||
}
|
||||
|
||||
.wy-nav-content a,
|
||||
.wy-nav-content a:visited {
|
||||
color: var(--dark-link-color) !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn-neutral {
|
||||
background-color: #17181c !important;
|
||||
}
|
||||
|
||||
.btn-neutral:hover {
|
||||
background-color: #101114 !important;
|
||||
}
|
||||
|
||||
.btn-neutral:visited {
|
||||
color: #c1c1c1 !important;
|
||||
}
|
||||
|
||||
.btn {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: #bdbdbd;
|
||||
}
|
||||
|
||||
.wy-nav-side {
|
||||
background-color: #000;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
.wy-menu-vertical > a {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current > a,
|
||||
.wy-menu-vertical li.on a {
|
||||
background-color: #000;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.toctree-l1.current > a,
|
||||
.wy-menu-vertical li.current a {
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.wy-menu-vertical header,
|
||||
.wy-menu-vertical p.caption {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
html.writer-html4 .rst-content dl:not(.docutils) > dt,
|
||||
html.writer-html5
|
||||
.rst-content
|
||||
dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)
|
||||
> dt {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current a {
|
||||
color: #090;
|
||||
}
|
||||
.wy-menu-vertical a {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.current a:hover {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.wy-menu-vertical a:hover,
|
||||
.wy-menu-vertical li.current > a:hover,
|
||||
.wy-menu-vertical li.on a:hover {
|
||||
background-color: #000;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.toctree-l2.current > a,
|
||||
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-side-nav-search {
|
||||
background-color: #000;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-side-nav-search .wy-dropdown > a,
|
||||
.wy-side-nav-search > a {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-side-nav-search input[type="text"] {
|
||||
border-left: 0px;
|
||||
border-right: 0px;
|
||||
border-top: 0px;
|
||||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
border-bottom-color: #0c0;
|
||||
background-color: #333;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.theme-switcher {
|
||||
background-color: #0b0c0d;
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
writer-html4 .rst-content dl:not(.docutils) > dt,
|
||||
writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt {
|
||||
background-color: #0b0b0b;
|
||||
color: #007dce;
|
||||
border-color: #282828;
|
||||
}
|
||||
|
||||
.rst-content code,
|
||||
.rst-content tt {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt,
|
||||
writer-html5
|
||||
.rst-content
|
||||
dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)
|
||||
dl:not(.field-list)
|
||||
> dt {
|
||||
background-color: #0f0f0f;
|
||||
color: #959595;
|
||||
border-color: #2b2b2b;
|
||||
}
|
||||
|
||||
.rst-content code,
|
||||
.rst-content tt,
|
||||
code {
|
||||
background-color: #2d2d2d;
|
||||
border-color: #1c1c1c;
|
||||
}
|
||||
|
||||
.rst-content code.xref,
|
||||
.rst-content tt.xref,
|
||||
a .rst-content code,
|
||||
a .rst-content tt {
|
||||
color: #cecece;
|
||||
}
|
||||
|
||||
.rst-content .hint,
|
||||
.rst-content .important,
|
||||
.rst-content .tip,
|
||||
.rst-content .wy-alert-success.admonition,
|
||||
.rst-content .wy-alert-success.admonition-todo,
|
||||
.rst-content .wy-alert-success.attention,
|
||||
.rst-content .wy-alert-success.caution,
|
||||
.rst-content .wy-alert-success.danger,
|
||||
.rst-content .wy-alert-success.error,
|
||||
.rst-content .wy-alert-success.note,
|
||||
.rst-content .wy-alert-success.seealso,
|
||||
.rst-content .wy-alert-success.warning,
|
||||
.wy-alert.wy-alert-success {
|
||||
background-color: #00392e;
|
||||
}
|
||||
|
||||
.rst-content .hint .admonition-title,
|
||||
.rst-content .hint .wy-alert-title,
|
||||
.rst-content .important .admonition-title,
|
||||
.rst-content .important .wy-alert-title,
|
||||
.rst-content .tip .admonition-title,
|
||||
.rst-content .tip .wy-alert-title,
|
||||
.rst-content .wy-alert-success.admonition-todo .admonition-title,
|
||||
.rst-content .wy-alert-success.admonition-todo .wy-alert-title,
|
||||
.rst-content .wy-alert-success.admonition .admonition-title,
|
||||
.rst-content .wy-alert-success.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-success.attention .admonition-title,
|
||||
.rst-content .wy-alert-success.attention .wy-alert-title,
|
||||
.rst-content .wy-alert-success.caution .admonition-title,
|
||||
.rst-content .wy-alert-success.caution .wy-alert-title,
|
||||
.rst-content .wy-alert-success.danger .admonition-title,
|
||||
.rst-content .wy-alert-success.danger .wy-alert-title,
|
||||
.rst-content .wy-alert-success.error .admonition-title,
|
||||
.rst-content .wy-alert-success.error .wy-alert-title,
|
||||
.rst-content .wy-alert-success.note .admonition-title,
|
||||
.rst-content .wy-alert-success.note .wy-alert-title,
|
||||
.rst-content .wy-alert-success.seealso .admonition-title,
|
||||
.rst-content .wy-alert-success.seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-success.warning .admonition-title,
|
||||
.rst-content .wy-alert-success.warning .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-success .admonition-title,
|
||||
.wy-alert.wy-alert-success .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-success .wy-alert-title {
|
||||
background-color: #006a56;
|
||||
}
|
||||
|
||||
.rst-content .note,
|
||||
.rst-content .seealso,
|
||||
.rst-content .wy-alert-info.admonition,
|
||||
.rst-content .wy-alert-info.admonition-todo,
|
||||
.rst-content .wy-alert-info.attention,
|
||||
.rst-content .wy-alert-info.caution,
|
||||
.rst-content .wy-alert-info.danger,
|
||||
.rst-content .wy-alert-info.error,
|
||||
.rst-content .wy-alert-info.hint,
|
||||
.rst-content .wy-alert-info.important,
|
||||
.rst-content .wy-alert-info.tip,
|
||||
.rst-content .wy-alert-info.warning,
|
||||
.wy-alert.wy-alert-info {
|
||||
background-color: #002c4d;
|
||||
}
|
||||
|
||||
.rst-content .note .admonition-title,
|
||||
.rst-content .note .wy-alert-title,
|
||||
.rst-content .seealso .admonition-title,
|
||||
.rst-content .seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-info.admonition-todo .admonition-title,
|
||||
.rst-content .wy-alert-info.admonition-todo .wy-alert-title,
|
||||
.rst-content .wy-alert-info.admonition .admonition-title,
|
||||
.rst-content .wy-alert-info.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-info.attention .admonition-title,
|
||||
.rst-content .wy-alert-info.attention .wy-alert-title,
|
||||
.rst-content .wy-alert-info.caution .admonition-title,
|
||||
.rst-content .wy-alert-info.caution .wy-alert-title,
|
||||
.rst-content .wy-alert-info.danger .admonition-title,
|
||||
.rst-content .wy-alert-info.danger .wy-alert-title,
|
||||
.rst-content .wy-alert-info.error .admonition-title,
|
||||
.rst-content .wy-alert-info.error .wy-alert-title,
|
||||
.rst-content .wy-alert-info.hint .admonition-title,
|
||||
.rst-content .wy-alert-info.hint .wy-alert-title,
|
||||
.rst-content .wy-alert-info.important .admonition-title,
|
||||
.rst-content .wy-alert-info.important .wy-alert-title,
|
||||
.rst-content .wy-alert-info.tip .admonition-title,
|
||||
.rst-content .wy-alert-info.tip .wy-alert-title,
|
||||
.rst-content .wy-alert-info.warning .admonition-title,
|
||||
.rst-content .wy-alert-info.warning .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-info .admonition-title,
|
||||
.wy-alert.wy-alert-info .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-info .wy-alert-title {
|
||||
background-color: #004a7b;
|
||||
}
|
||||
|
||||
.rst-content dl:not(.docutils) dt {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.rst-content {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.rst-content .admonition-todo,
|
||||
.rst-content .attention,
|
||||
.rst-content .caution,
|
||||
.rst-content .warning,
|
||||
.rst-content .wy-alert-warning.admonition,
|
||||
.rst-content .wy-alert-warning.danger,
|
||||
.rst-content .wy-alert-warning.error,
|
||||
.rst-content .wy-alert-warning.hint,
|
||||
.rst-content .wy-alert-warning.important,
|
||||
.rst-content .wy-alert-warning.note,
|
||||
.rst-content .wy-alert-warning.seealso,
|
||||
.rst-content .wy-alert-warning.tip,
|
||||
.wy-alert.wy-alert-warning {
|
||||
background-color: #533500;
|
||||
}
|
||||
|
||||
.rst-content .admonition-todo .admonition-title,
|
||||
.rst-content .admonition-todo .wy-alert-title,
|
||||
.rst-content .attention .admonition-title,
|
||||
.rst-content .attention .wy-alert-title,
|
||||
.rst-content .caution .admonition-title,
|
||||
.rst-content .caution .wy-alert-title,
|
||||
.rst-content .warning .admonition-title,
|
||||
.rst-content .warning .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.admonition .admonition-title,
|
||||
.rst-content .wy-alert-warning.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.danger .admonition-title,
|
||||
.rst-content .wy-alert-warning.danger .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.error .admonition-title,
|
||||
.rst-content .wy-alert-warning.error .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.hint .admonition-title,
|
||||
.rst-content .wy-alert-warning.hint .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.important .admonition-title,
|
||||
.rst-content .wy-alert-warning.important .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.note .admonition-title,
|
||||
.rst-content .wy-alert-warning.note .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.seealso .admonition-title,
|
||||
.rst-content .wy-alert-warning.seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-warning.tip .admonition-title,
|
||||
.rst-content .wy-alert-warning.tip .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-warning .admonition-title,
|
||||
.wy-alert.wy-alert-warning .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-warning .wy-alert-title {
|
||||
background-color: #803b00;
|
||||
}
|
||||
|
||||
.rst-content .danger,
|
||||
.rst-content .error,
|
||||
.rst-content .wy-alert-danger.admonition,
|
||||
.rst-content .wy-alert-danger.admonition-todo,
|
||||
.rst-content .wy-alert-danger.attention,
|
||||
.rst-content .wy-alert-danger.caution,
|
||||
.rst-content .wy-alert-danger.hint,
|
||||
.rst-content .wy-alert-danger.important,
|
||||
.rst-content .wy-alert-danger.note,
|
||||
.rst-content .wy-alert-danger.seealso,
|
||||
.rst-content .wy-alert-danger.tip,
|
||||
.rst-content .wy-alert-danger.warning,
|
||||
.wy-alert.wy-alert-danger {
|
||||
background-color: #82231a;
|
||||
}
|
||||
|
||||
.rst-content .danger .admonition-title,
|
||||
.rst-content .danger .wy-alert-title,
|
||||
.rst-content .error .admonition-title,
|
||||
.rst-content .error .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.admonition-todo .admonition-title,
|
||||
.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.admonition .admonition-title,
|
||||
.rst-content .wy-alert-danger.admonition .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.attention .admonition-title,
|
||||
.rst-content .wy-alert-danger.attention .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.caution .admonition-title,
|
||||
.rst-content .wy-alert-danger.caution .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.hint .admonition-title,
|
||||
.rst-content .wy-alert-danger.hint .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.important .admonition-title,
|
||||
.rst-content .wy-alert-danger.important .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.note .admonition-title,
|
||||
.rst-content .wy-alert-danger.note .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.seealso .admonition-title,
|
||||
.rst-content .wy-alert-danger.seealso .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.tip .admonition-title,
|
||||
.rst-content .wy-alert-danger.tip .wy-alert-title,
|
||||
.rst-content .wy-alert-danger.warning .admonition-title,
|
||||
.rst-content .wy-alert-danger.warning .wy-alert-title,
|
||||
.rst-content .wy-alert.wy-alert-danger .admonition-title,
|
||||
.wy-alert.wy-alert-danger .rst-content .admonition-title,
|
||||
.wy-alert.wy-alert-danger .wy-alert-title {
|
||||
background-color: #b9372b;
|
||||
}
|
||||
|
||||
.wy-nav-top {
|
||||
background-color: #0b152d;
|
||||
}
|
||||
|
||||
.rst-content table.docutils thead,
|
||||
.rst-content table.field-list thead,
|
||||
.wy-table thead {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,
|
||||
.wy-table-backed,
|
||||
.wy-table-odd td,
|
||||
.wy-table-striped tr:nth-child(2n-1) td {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.rst-content table.docutils:not(.field-list) tr:nth-child(2n) td,
|
||||
.wy-table-backed,
|
||||
.wy-table-odd td,
|
||||
.wy-table-striped tr:nth-child(2n) td {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.rst-content table.docutils td,
|
||||
.wy-table-bordered-all td,
|
||||
writer-html5 .rst-content table.docutils th,
|
||||
.rst-content table.docutils,
|
||||
.wy-table-bordered-all {
|
||||
border-color: #262626;
|
||||
}
|
||||
|
||||
.rst-content table.docutils caption,
|
||||
.rst-content table.field-list caption,
|
||||
.wy-table caption {
|
||||
color: var(--dark-text-color);
|
||||
}
|
||||
|
||||
.wy-menu-vertical li.toctree-l3.current > a,
|
||||
.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.wy-side-nav-search > div.version {
|
||||
color: var(--dark-text-color);
|
||||
}
|
4
electron/package-lock.json
generated
4
electron/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bitburner",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.4",
|
||||
"dependencies": {
|
||||
"electron-config": "^2.0.0",
|
||||
"electron-log": "^4.4.4",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.4",
|
||||
"description": "A cyberpunk-themed programming incremental game",
|
||||
"main": "main.js",
|
||||
"author": "Daniel Xie & Olivier Gagnon",
|
||||
|
25
markdown/bitburner.grafting.getgraftableaugmentations.md
Normal file
25
markdown/bitburner.grafting.getgraftableaugmentations.md
Normal file
@ -0,0 +1,25 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Grafting](./bitburner.grafting.md) > [getGraftableAugmentations](./bitburner.grafting.getgraftableaugmentations.md)
|
||||
|
||||
## Grafting.getGraftableAugmentations() method
|
||||
|
||||
Retrieves a list of Augmentations that can be grafted.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getGraftableAugmentations(): string[];
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
string\[\]
|
||||
|
||||
An array of graftable Augmentations.
|
||||
|
||||
## Remarks
|
||||
|
||||
RAM cost: 5 GB
|
||||
|
||||
Note that this function returns a list of currently graftable Augmentations, based off of the Augmentations that you already own.
|
||||
|
@ -22,5 +22,6 @@ This API requires Source-File 10 to use.
|
||||
| --- | --- |
|
||||
| [getAugmentationGraftPrice(augName)](./bitburner.grafting.getaugmentationgraftprice.md) | Retrieve the grafting cost of an aug. |
|
||||
| [getAugmentationGraftTime(augName)](./bitburner.grafting.getaugmentationgrafttime.md) | Retrieves the time required to graft an aug. |
|
||||
| [getGraftableAugmentations()](./bitburner.grafting.getgraftableaugmentations.md) | Retrieves a list of Augmentations that can be grafted. |
|
||||
| [graftAugmentation(augName, focus)](./bitburner.grafting.graftaugmentation.md) | Begins grafting the named aug. You must be in New Tokyo to use this. |
|
||||
|
||||
|
@ -9,7 +9,7 @@ Calculate the security increase for a number of thread.
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
growthAnalyzeSecurity(threads: number): number;
|
||||
growthAnalyzeSecurity(threads: number, hostname?: string, cores?: number): number;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -17,6 +17,8 @@ growthAnalyzeSecurity(threads: number): number;
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| threads | number | Amount of threads that will be used. |
|
||||
| hostname | string | Optional. Hostname of the target server. The number of threads is limited to the number needed to hack the servers maximum amount of money. |
|
||||
| cores | number | Optional. The number of cores of the server that would run grow. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
@ -115,7 +115,7 @@ export async function main(ns) {
|
||||
| [getWeakenTime(host)](./bitburner.ns.getweakentime.md) | Get the execution time of a weaken() call. |
|
||||
| [grow(host, opts)](./bitburner.ns.grow.md) | Spoof money in a servers bank account, increasing the amount available. |
|
||||
| [growthAnalyze(host, growthAmount, cores)](./bitburner.ns.growthanalyze.md) | Calculate the number of grow thread needed to grow a server by a certain multiplier. |
|
||||
| [growthAnalyzeSecurity(threads)](./bitburner.ns.growthanalyzesecurity.md) | Calculate the security increase for a number of thread. |
|
||||
| [growthAnalyzeSecurity(threads, hostname, cores)](./bitburner.ns.growthanalyzesecurity.md) | Calculate the security increase for a number of thread. |
|
||||
| [hack(host, opts)](./bitburner.ns.hack.md) | Steal a servers money. |
|
||||
| [hackAnalyze(host)](./bitburner.ns.hackanalyze.md) | Get the part of money stolen with a single thread. |
|
||||
| [hackAnalyzeChance(host)](./bitburner.ns.hackanalyzechance.md) | Get the chance of successfully hacking a server. |
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bitburner",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.4",
|
||||
"hasInstallScript": true,
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"dependencies": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.4",
|
||||
"main": "electron-main.js",
|
||||
"author": {
|
||||
"name": "Daniel Xie & Olivier Gagnon"
|
||||
|
@ -431,9 +431,6 @@ export class Augmentation {
|
||||
// Name of Augmentation
|
||||
name = "";
|
||||
|
||||
// Whether the player owns this Augmentation
|
||||
owned = false;
|
||||
|
||||
// Array of names of all prerequisites
|
||||
prereqs: string[] = [];
|
||||
|
||||
|
@ -7,7 +7,6 @@ import { CONSTANTS } from "../Constants";
|
||||
import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { Player } from "../Player";
|
||||
import { prestigeAugmentation } from "../Prestige";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { clearObject } from "../utils/helpers/clearObject";
|
||||
@ -75,7 +74,7 @@ function initAugmentations(): void {
|
||||
}
|
||||
|
||||
function getBaseAugmentationPriceMultiplier(): number {
|
||||
return CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]];
|
||||
return CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][Player.sourceFileLvl(11)];
|
||||
}
|
||||
export function getGenericAugmentationPriceMultiplier(): number {
|
||||
return Math.pow(getBaseAugmentationPriceMultiplier(), Player.queuedAugmentations.length);
|
||||
@ -134,8 +133,6 @@ function resetAugmentation(aug: Augmentation): void {
|
||||
}
|
||||
|
||||
function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void {
|
||||
Augmentations[aug.name].owned = true;
|
||||
|
||||
const augObj = Augmentations[aug.name];
|
||||
|
||||
// Apply multipliers
|
||||
|
@ -7,7 +7,6 @@ import * as React from "react";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Player } from "../../Player";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Augmentations } from "../Augmentations";
|
||||
|
||||
@ -35,7 +34,7 @@ interface IBitNodeModifiedStatsProps {
|
||||
|
||||
function BitNodeModifiedStats(props: IBitNodeModifiedStatsProps): React.ReactElement {
|
||||
// If player doesn't have SF5 or if the property isn't affected by BitNode mults
|
||||
if (props.mult === 1 || SourceFileFlags[5] === 0)
|
||||
if (props.mult === 1 || Player.sourceFileLvl(5) === 0)
|
||||
return <Typography color={props.color}>{numeralWrapper.formatPercentage(props.base)}</Typography>;
|
||||
|
||||
return (
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { enterBitNode } from "../../RedPill";
|
||||
@ -128,12 +127,6 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
const destroyed = player.bitNodeN;
|
||||
const [destroySequence, setDestroySequence] = useState(!props.quick);
|
||||
|
||||
// Update NextSourceFileFlags
|
||||
const nextSourceFileFlags = SourceFileFlags.slice();
|
||||
if (!props.flume) {
|
||||
if (nextSourceFileFlags[destroyed] < 3) ++nextSourceFileFlags[destroyed];
|
||||
}
|
||||
|
||||
if (destroySequence) {
|
||||
return (
|
||||
<CinematicText
|
||||
@ -164,6 +157,15 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
const nextSourceFileLvl = (n: number): number => {
|
||||
const lvl = player.sourceFileLvl(n);
|
||||
if (n !== destroyed) {
|
||||
return lvl;
|
||||
}
|
||||
const max = n === 12 ? Infinity : 3;
|
||||
return Math.min(max, lvl + 1);
|
||||
};
|
||||
|
||||
if (Settings.DisableASCIIArt) {
|
||||
return (
|
||||
<>
|
||||
@ -176,7 +178,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
<BitNodePortal
|
||||
key={node.number}
|
||||
n={node.number}
|
||||
level={nextSourceFileFlags[node.number]}
|
||||
level={nextSourceFileLvl(node.number)}
|
||||
enter={enter}
|
||||
flume={props.flume}
|
||||
destroyedBitNode={destroyed}
|
||||
@ -215,6 +217,8 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const n = nextSourceFileLvl;
|
||||
return (
|
||||
// prettier-ignore
|
||||
<>
|
||||
@ -228,19 +232,19 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={n(13)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={n(10)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={n(11)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={n(9)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={n(12)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={n(7)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={n(8)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={n(5)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={n(6)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={n(1)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={n(2)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={n(3)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={n(4)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
|
||||
<br />
|
||||
|
@ -28,7 +28,6 @@ import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { calculateHospitalizationCost } from "../Hospital/Hospital";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { getTimestamp } from "../utils/helpers/getTimestamp";
|
||||
import { joinFaction } from "../Faction/FactionHelpers";
|
||||
@ -1920,7 +1919,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
if (Augmentations[AugmentationNames.BladesSimulacrum].owned === false && player.isWorking) {
|
||||
if (player.hasAugmentation(AugmentationNames.BladesSimulacrum) === false && player.isWorking) {
|
||||
if (this.action.type !== ActionTypes["Idle"]) {
|
||||
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
|
||||
if (this.automateEnabled) {
|
||||
|
@ -116,8 +116,8 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: number;
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
VersionString: "1.6.3",
|
||||
VersionNumber: 13,
|
||||
VersionString: "1.6.4",
|
||||
VersionNumber: 14,
|
||||
|
||||
// Speed (in ms) at which the main loop is updated
|
||||
_idleSpeed: 200,
|
||||
|
@ -51,29 +51,31 @@ export function NewIndustry(corporation: ICorporation, industry: string, name: s
|
||||
export function NewCity(corporation: ICorporation, division: IIndustry, city: string): void {
|
||||
if (corporation.funds < CorporationConstants.OfficeInitialCost) {
|
||||
throw new Error("You don't have enough company funds to open a new office!");
|
||||
} else {
|
||||
corporation.funds = corporation.funds - CorporationConstants.OfficeInitialCost;
|
||||
division.offices[city] = new OfficeSpace({
|
||||
loc: city,
|
||||
size: CorporationConstants.OfficeInitialSize,
|
||||
});
|
||||
}
|
||||
if (division.offices[city]) {
|
||||
throw new Error(`You have already expanded into ${city} for ${division.name}`);
|
||||
}
|
||||
corporation.funds = corporation.funds - CorporationConstants.OfficeInitialCost;
|
||||
division.offices[city] = new OfficeSpace({
|
||||
loc: city,
|
||||
size: CorporationConstants.OfficeInitialSize,
|
||||
});
|
||||
}
|
||||
|
||||
export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnlockUpgrade): void {
|
||||
if (corporation.funds < upgrade[1]) {
|
||||
if (corporation.funds < upgrade.price) {
|
||||
throw new Error("Insufficient funds");
|
||||
}
|
||||
if (corporation.unlockUpgrades[upgrade[0]] === 1) {
|
||||
throw new Error(`You have already unlocked the ${upgrade[2]} upgrade!`);
|
||||
if (corporation.unlockUpgrades[upgrade.index] === 1) {
|
||||
throw new Error(`You have already unlocked the ${upgrade.name} upgrade!`);
|
||||
}
|
||||
corporation.unlock(upgrade);
|
||||
}
|
||||
|
||||
export function LevelUpgrade(corporation: ICorporation, upgrade: CorporationUpgrade): void {
|
||||
const baseCost = upgrade[1];
|
||||
const priceMult = upgrade[2];
|
||||
const level = corporation.upgrades[upgrade[0]];
|
||||
const baseCost = upgrade.basePrice;
|
||||
const priceMult = upgrade.priceMult;
|
||||
const level = corporation.upgrades[upgrade.index];
|
||||
const cost = baseCost * Math.pow(priceMult, level);
|
||||
if (corporation.funds < cost) {
|
||||
throw new Error("Insufficient funds");
|
||||
@ -345,10 +347,17 @@ export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city:
|
||||
corp.funds = corp.funds - CorporationConstants.WarehouseInitialCost;
|
||||
}
|
||||
|
||||
export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse): void {
|
||||
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
|
||||
export function UpgradeWarehouseCost(warehouse: Warehouse, amt: number): number {
|
||||
return Array.from(Array(amt).keys()).reduce(
|
||||
(acc, index) => acc + CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1 + index),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse, amt = 1): void {
|
||||
const sizeUpgradeCost = UpgradeWarehouseCost(warehouse, amt);
|
||||
if (corp.funds < sizeUpgradeCost) return;
|
||||
++warehouse.level;
|
||||
warehouse.level += amt;
|
||||
warehouse.updateSize(corp, division);
|
||||
corp.funds = corp.funds - sizeUpgradeCost;
|
||||
}
|
||||
@ -416,7 +425,7 @@ export function MakeProduct(
|
||||
}
|
||||
|
||||
const product = new Product({
|
||||
name: productName.replace(/[<>]/g, ""), //Sanitize for HTMl elements
|
||||
name: productName.replace(/[<>]/g, "").trim(), //Sanitize for HTMl elements
|
||||
createCity: city,
|
||||
designCost: designInvest,
|
||||
advCost: marketingInvest,
|
||||
@ -488,12 +497,23 @@ export function CancelExportMaterial(divisionName: string, cityName: string, mat
|
||||
export function LimitProductProduction(product: Product, cityName: string, qty: number): void {
|
||||
if (qty < 0 || isNaN(qty)) {
|
||||
product.prdman[cityName][0] = false;
|
||||
product.prdman[cityName][1] = 0;
|
||||
} else {
|
||||
product.prdman[cityName][0] = true;
|
||||
product.prdman[cityName][1] = qty;
|
||||
}
|
||||
}
|
||||
|
||||
export function LimitMaterialProduction(material: Material, qty: number): void {
|
||||
if (qty < 0 || isNaN(qty)) {
|
||||
material.prdman[0] = false;
|
||||
material.prdman[1] = 0;
|
||||
} else {
|
||||
material.prdman[0] = true;
|
||||
material.prdman[1] = qty;
|
||||
}
|
||||
}
|
||||
|
||||
export function SetMaterialMarketTA1(material: Material, on: boolean): void {
|
||||
material.marketTa1 = on;
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ export class Corporation {
|
||||
upgrades: number[];
|
||||
upgradeMultipliers: number[];
|
||||
|
||||
avgProfit = 0;
|
||||
|
||||
state = new CorporationState();
|
||||
|
||||
constructor(params: IParams = {}) {
|
||||
@ -106,6 +108,8 @@ export class Corporation {
|
||||
this.expenses = this.expenses + ind.lastCycleExpenses;
|
||||
});
|
||||
const profit = this.revenue - this.expenses;
|
||||
this.avgProfit =
|
||||
(this.avgProfit * (CorporationConstants.AvgProfitLength - 1) + profit) / CorporationConstants.AvgProfitLength;
|
||||
const cycleProfit = profit * (marketCycles * CorporationConstants.SecsPerMarketCycle);
|
||||
if (isNaN(this.funds) || this.funds === Infinity || this.funds === -Infinity) {
|
||||
dialogBoxCreate(
|
||||
@ -160,7 +164,7 @@ export class Corporation {
|
||||
|
||||
determineValuation(): number {
|
||||
let val,
|
||||
profit = this.revenue - this.expenses;
|
||||
profit = this.avgProfit;
|
||||
if (this.public) {
|
||||
// Account for dividends
|
||||
if (this.dividendPercentage > 0) {
|
||||
@ -260,8 +264,8 @@ export class Corporation {
|
||||
|
||||
//One time upgrades that unlock new features
|
||||
unlock(upgrade: CorporationUnlockUpgrade): void {
|
||||
const upgN = upgrade[0],
|
||||
price = upgrade[1];
|
||||
const upgN = upgrade.index,
|
||||
price = upgrade.price;
|
||||
while (this.unlockUpgrades.length <= upgN) {
|
||||
this.unlockUpgrades.push(0);
|
||||
}
|
||||
@ -282,10 +286,10 @@ export class Corporation {
|
||||
|
||||
//Levelable upgrades
|
||||
upgrade(upgrade: CorporationUpgrade): void {
|
||||
const upgN = upgrade[0],
|
||||
basePrice = upgrade[1],
|
||||
priceMult = upgrade[2],
|
||||
upgradeAmt = upgrade[3]; //Amount by which the upgrade multiplier gets increased (additive)
|
||||
const upgN = upgrade.index,
|
||||
basePrice = upgrade.basePrice,
|
||||
priceMult = upgrade.priceMult,
|
||||
upgradeAmt = upgrade.benefit; //Amount by which the upgrade multiplier gets increased (additive)
|
||||
while (this.upgrades.length <= upgN) {
|
||||
this.upgrades.push(0);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ export const CorporationConstants: {
|
||||
AllMaterials: string[];
|
||||
FundingRoundShares: number[];
|
||||
FundingRoundMultiplier: number[];
|
||||
AvgProfitLength: number;
|
||||
} = {
|
||||
INITIALSHARES: 1e9, //Total number of shares you have at your company
|
||||
SHARESPERPRICEUPDATE: 1e6, //When selling large number of shares, price is dynamically updated for every batch of this amount
|
||||
@ -83,4 +84,6 @@ export const CorporationConstants: {
|
||||
],
|
||||
FundingRoundShares: [0.1, 0.35, 0.25, 0.2],
|
||||
FundingRoundMultiplier: [4, 3, 3, 2.5],
|
||||
|
||||
AvgProfitLength: 1,
|
||||
};
|
||||
|
@ -1,70 +1,100 @@
|
||||
import { IMap } from "../../types";
|
||||
export interface CorporationUnlockUpgrade {
|
||||
index: number;
|
||||
price: number;
|
||||
name: string;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
export type CorporationUnlockUpgrade = [number, number, string, string];
|
||||
export enum CorporationUnlockUpgradeIndex {
|
||||
Export = 0,
|
||||
SmartSupply = 1,
|
||||
MarketResearchDemand = 2,
|
||||
MarketDataCompetition = 3,
|
||||
VeChain = 4,
|
||||
ShadyAccounting = 5,
|
||||
GovernmentPartnership = 6,
|
||||
WarehouseAPI = 7,
|
||||
OfficeAPI = 8,
|
||||
}
|
||||
|
||||
// Corporation Unlock Upgrades
|
||||
// Upgrades for entire corporation, unlocks features, either you have it or you dont
|
||||
// The data structure is an array with the following format:
|
||||
// [index in Corporation feature upgrades array, price, name, description]
|
||||
export const CorporationUnlockUpgrades: IMap<CorporationUnlockUpgrade> = {
|
||||
export const CorporationUnlockUpgrades: Record<CorporationUnlockUpgradeIndex, CorporationUnlockUpgrade> = {
|
||||
//Lets you export goods
|
||||
"0": [
|
||||
0,
|
||||
20e9,
|
||||
"Export",
|
||||
"Develop infrastructure to export your materials to your other facilities. " +
|
||||
[CorporationUnlockUpgradeIndex.Export]: {
|
||||
index: 0,
|
||||
price: 20e9,
|
||||
name: "Export",
|
||||
desc:
|
||||
"Develop infrastructure to export your materials to your other facilities. " +
|
||||
"This allows you to move materials around between different divisions and cities.",
|
||||
],
|
||||
},
|
||||
|
||||
//Lets you buy exactly however many required materials you need for production
|
||||
"1": [
|
||||
1,
|
||||
25e9,
|
||||
"Smart Supply",
|
||||
"Use advanced AI to anticipate your supply needs. " +
|
||||
[CorporationUnlockUpgradeIndex.SmartSupply]: {
|
||||
index: 1,
|
||||
price: 25e9,
|
||||
name: "Smart Supply",
|
||||
desc:
|
||||
"Use advanced AI to anticipate your supply needs. " +
|
||||
"This allows you to purchase exactly however many materials you need for production.",
|
||||
],
|
||||
},
|
||||
|
||||
//Displays each material/product's demand
|
||||
"2": [
|
||||
2,
|
||||
5e9,
|
||||
"Market Research - Demand",
|
||||
"Mine and analyze market data to determine the demand of all resources. " +
|
||||
[CorporationUnlockUpgradeIndex.MarketResearchDemand]: {
|
||||
index: 2,
|
||||
price: 5e9,
|
||||
name: "Market Research - Demand",
|
||||
desc:
|
||||
"Mine and analyze market data to determine the demand of all resources. " +
|
||||
"The demand attribute, which affects sales, will be displayed for every material and product.",
|
||||
],
|
||||
},
|
||||
|
||||
//Display's each material/product's competition
|
||||
"3": [
|
||||
3,
|
||||
5e9,
|
||||
"Market Data - Competition",
|
||||
"Mine and analyze market data to determine how much competition there is on the market " +
|
||||
[CorporationUnlockUpgradeIndex.MarketDataCompetition]: {
|
||||
index: 3,
|
||||
price: 5e9,
|
||||
name: "Market Data - Competition",
|
||||
desc:
|
||||
"Mine and analyze market data to determine how much competition there is on the market " +
|
||||
"for all resources. The competition attribute, which affects sales, will be displayed for " +
|
||||
"every material and product.",
|
||||
],
|
||||
"4": [
|
||||
4,
|
||||
10e9,
|
||||
"VeChain",
|
||||
"Use AI and blockchain technology to identify where you can improve your supply chain systems. " +
|
||||
},
|
||||
[CorporationUnlockUpgradeIndex.VeChain]: {
|
||||
index: 4,
|
||||
price: 10e9,
|
||||
name: "VeChain",
|
||||
desc:
|
||||
"Use AI and blockchain technology to identify where you can improve your supply chain systems. " +
|
||||
"This upgrade will allow you to view a wide array of useful statistics about your " +
|
||||
"Corporation.",
|
||||
],
|
||||
"5": [
|
||||
5,
|
||||
500e12,
|
||||
"Shady Accounting",
|
||||
"Utilize unscrupulous accounting practices and pay off government officials to save money " +
|
||||
},
|
||||
[CorporationUnlockUpgradeIndex.ShadyAccounting]: {
|
||||
index: 5,
|
||||
price: 500e12,
|
||||
name: "Shady Accounting",
|
||||
desc:
|
||||
"Utilize unscrupulous accounting practices and pay off government officials to save money " +
|
||||
"on taxes. This reduces the dividend tax rate by 5%.",
|
||||
],
|
||||
"6": [
|
||||
6,
|
||||
2e15,
|
||||
"Government Partnership",
|
||||
"Help national governments further their agendas in exchange for lowered taxes. " +
|
||||
},
|
||||
[CorporationUnlockUpgradeIndex.GovernmentPartnership]: {
|
||||
index: 6,
|
||||
price: 2e15,
|
||||
name: "Government Partnership",
|
||||
desc:
|
||||
"Help national governments further their agendas in exchange for lowered taxes. " +
|
||||
"This reduces the dividend tax rate by 10%",
|
||||
],
|
||||
"7": [7, 50e9, "Warehouse API", "Enables the warehouse API."],
|
||||
"8": [8, 50e9, "Office API", "Enables the office API."],
|
||||
},
|
||||
[CorporationUnlockUpgradeIndex.WarehouseAPI]: {
|
||||
index: 7,
|
||||
price: 50e9,
|
||||
name: "Warehouse API",
|
||||
desc: "Enables the warehouse API.",
|
||||
},
|
||||
[CorporationUnlockUpgradeIndex.OfficeAPI]: {
|
||||
index: 8,
|
||||
price: 50e9,
|
||||
name: "Office API",
|
||||
desc: "Enables the office API.",
|
||||
},
|
||||
};
|
||||
|
@ -1,127 +1,153 @@
|
||||
import { IMap } from "../../types";
|
||||
export interface CorporationUpgrade {
|
||||
index: number;
|
||||
basePrice: number;
|
||||
priceMult: number;
|
||||
benefit: number;
|
||||
name: string;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
export type CorporationUpgrade = [number, number, number, number, string, string];
|
||||
export enum CorporationUpgradeIndex {
|
||||
SmartFactories = 0,
|
||||
SmartStorage = 1,
|
||||
DreamSense = 2,
|
||||
WilsonAnalytics = 3,
|
||||
NuoptimalNootropicInjectorImplants = 4,
|
||||
SpeechProcessorImplants = 5,
|
||||
NeuralAccelerators = 6,
|
||||
FocusWires = 7,
|
||||
ABCSalesBots = 8,
|
||||
ProjectInsight = 9,
|
||||
}
|
||||
|
||||
// Corporation Upgrades
|
||||
// Upgrades for entire corporation, levelable upgrades
|
||||
// The data structure is an array with the following format
|
||||
// [index in Corporation upgrades array, base price, price mult, benefit mult (additive), name, desc]
|
||||
export const CorporationUpgrades: IMap<CorporationUpgrade> = {
|
||||
export const CorporationUpgrades: Record<CorporationUpgradeIndex, CorporationUpgrade> = {
|
||||
//Smart factories, increases production
|
||||
"0": [
|
||||
0,
|
||||
2e9,
|
||||
1.06,
|
||||
0.03,
|
||||
"Smart Factories",
|
||||
"Advanced AI automatically optimizes the operation and productivity " +
|
||||
[CorporationUpgradeIndex.SmartFactories]: {
|
||||
index: CorporationUpgradeIndex.SmartFactories,
|
||||
basePrice: 2e9,
|
||||
priceMult: 1.06,
|
||||
benefit: 0.03,
|
||||
name: "Smart Factories",
|
||||
desc:
|
||||
"Advanced AI automatically optimizes the operation and productivity " +
|
||||
"of factories. Each level of this upgrade increases your global production by 3% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Smart warehouses, increases storage size
|
||||
"1": [
|
||||
1,
|
||||
2e9,
|
||||
1.06,
|
||||
0.1,
|
||||
"Smart Storage",
|
||||
"Advanced AI automatically optimizes your warehouse storage methods. " +
|
||||
[CorporationUpgradeIndex.SmartStorage]: {
|
||||
index: CorporationUpgradeIndex.SmartStorage,
|
||||
basePrice: 2e9,
|
||||
priceMult: 1.06,
|
||||
benefit: 0.1,
|
||||
name: "Smart Storage",
|
||||
desc:
|
||||
"Advanced AI automatically optimizes your warehouse storage methods. " +
|
||||
"Each level of this upgrade increases your global warehouse storage size by 10% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Advertise through dreams, passive popularity/ awareness gain
|
||||
"2": [
|
||||
2,
|
||||
4e9,
|
||||
1.1,
|
||||
0.001,
|
||||
"DreamSense",
|
||||
"Use DreamSense LCC Technologies to advertise your corporation " +
|
||||
[CorporationUpgradeIndex.DreamSense]: {
|
||||
index: CorporationUpgradeIndex.DreamSense,
|
||||
basePrice: 4e9,
|
||||
priceMult: 1.1,
|
||||
benefit: 0.001,
|
||||
name: "DreamSense",
|
||||
desc:
|
||||
"Use DreamSense LCC Technologies to advertise your corporation " +
|
||||
"to consumers through their dreams. Each level of this upgrade provides a passive " +
|
||||
"increase in awareness of all of your companies (divisions) by 0.004 / market cycle," +
|
||||
"and in popularity by 0.001 / market cycle. A market cycle is approximately " +
|
||||
"15 seconds.",
|
||||
],
|
||||
},
|
||||
|
||||
//Makes advertising more effective
|
||||
"3": [
|
||||
3,
|
||||
4e9,
|
||||
1.5,
|
||||
0.005,
|
||||
"Wilson Analytics",
|
||||
"Purchase data and analysis from Wilson, a marketing research " +
|
||||
[CorporationUpgradeIndex.WilsonAnalytics]: {
|
||||
index: CorporationUpgradeIndex.WilsonAnalytics,
|
||||
basePrice: 4e9,
|
||||
priceMult: 1.5,
|
||||
benefit: 0.005,
|
||||
name: "Wilson Analytics",
|
||||
desc:
|
||||
"Purchase data and analysis from Wilson, a marketing research " +
|
||||
"firm. Each level of this upgrades increases the effectiveness of your " +
|
||||
"advertising by 0.5% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Augmentation for employees, increases cre
|
||||
"4": [
|
||||
4,
|
||||
1e9,
|
||||
1.06,
|
||||
0.1,
|
||||
"Nuoptimal Nootropic Injector Implants",
|
||||
"Purchase the Nuoptimal Nootropic " +
|
||||
[CorporationUpgradeIndex.NuoptimalNootropicInjectorImplants]: {
|
||||
index: CorporationUpgradeIndex.NuoptimalNootropicInjectorImplants,
|
||||
basePrice: 1e9,
|
||||
priceMult: 1.06,
|
||||
benefit: 0.1,
|
||||
name: "Nuoptimal Nootropic Injector Implants",
|
||||
desc:
|
||||
"Purchase the Nuoptimal Nootropic " +
|
||||
"Injector augmentation for your employees. Each level of this upgrade " +
|
||||
"globally increases the creativity of your employees by 10% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Augmentation for employees, increases cha
|
||||
"5": [
|
||||
5,
|
||||
1e9,
|
||||
1.06,
|
||||
0.1,
|
||||
"Speech Processor Implants",
|
||||
"Purchase the Speech Processor augmentation for your employees. " +
|
||||
[CorporationUpgradeIndex.SpeechProcessorImplants]: {
|
||||
index: CorporationUpgradeIndex.SpeechProcessorImplants,
|
||||
basePrice: 1e9,
|
||||
priceMult: 1.06,
|
||||
benefit: 0.1,
|
||||
name: "Speech Processor Implants",
|
||||
desc:
|
||||
"Purchase the Speech Processor augmentation for your employees. " +
|
||||
"Each level of this upgrade globally increases the charisma of your employees by 10% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Augmentation for employees, increases int
|
||||
"6": [
|
||||
6,
|
||||
1e9,
|
||||
1.06,
|
||||
0.1,
|
||||
"Neural Accelerators",
|
||||
"Purchase the Neural Accelerator augmentation for your employees. " +
|
||||
[CorporationUpgradeIndex.NeuralAccelerators]: {
|
||||
index: CorporationUpgradeIndex.NeuralAccelerators,
|
||||
basePrice: 1e9,
|
||||
priceMult: 1.06,
|
||||
benefit: 0.1,
|
||||
name: "Neural Accelerators",
|
||||
desc:
|
||||
"Purchase the Neural Accelerator augmentation for your employees. " +
|
||||
"Each level of this upgrade globally increases the intelligence of your employees " +
|
||||
"by 10% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Augmentation for employees, increases eff
|
||||
"7": [
|
||||
7,
|
||||
1e9,
|
||||
1.06,
|
||||
0.1,
|
||||
"FocusWires",
|
||||
"Purchase the FocusWire augmentation for your employees. Each level " +
|
||||
[CorporationUpgradeIndex.FocusWires]: {
|
||||
index: CorporationUpgradeIndex.FocusWires,
|
||||
basePrice: 1e9,
|
||||
priceMult: 1.06,
|
||||
benefit: 0.1,
|
||||
name: "FocusWires",
|
||||
desc:
|
||||
"Purchase the FocusWire augmentation for your employees. Each level " +
|
||||
"of this upgrade globally increases the efficiency of your employees by 10% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Improves sales of materials/products
|
||||
"8": [
|
||||
8,
|
||||
1e9,
|
||||
1.07,
|
||||
0.01,
|
||||
"ABC SalesBots",
|
||||
"Always Be Closing. Purchase these robotic salesmen to increase the amount of " +
|
||||
[CorporationUpgradeIndex.ABCSalesBots]: {
|
||||
index: CorporationUpgradeIndex.ABCSalesBots,
|
||||
basePrice: 1e9,
|
||||
priceMult: 1.07,
|
||||
benefit: 0.01,
|
||||
name: "ABC SalesBots",
|
||||
desc:
|
||||
"Always Be Closing. Purchase these robotic salesmen to increase the amount of " +
|
||||
"materials and products you sell. Each level of this upgrade globally increases your sales " +
|
||||
"by 1% (additive).",
|
||||
],
|
||||
},
|
||||
|
||||
//Improves scientific research rate
|
||||
"9": [
|
||||
9,
|
||||
5e9,
|
||||
1.07,
|
||||
0.05,
|
||||
"Project Insight",
|
||||
"Purchase 'Project Insight', a R&D service provided by the secretive " +
|
||||
[CorporationUpgradeIndex.ProjectInsight]: {
|
||||
index: CorporationUpgradeIndex.ProjectInsight,
|
||||
basePrice: 5e9,
|
||||
priceMult: 1.07,
|
||||
benefit: 0.05,
|
||||
name: "Project Insight",
|
||||
desc:
|
||||
"Purchase 'Project Insight', a R&D service provided by the secretive " +
|
||||
"Fulcrum Technologies. Each level of this upgrade globally increases the amount of " +
|
||||
"Scientific Research you produce by 5% (additive).",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -8,8 +8,8 @@ import { EmployeePositions } from "../EmployeePositions";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { UpgradeOfficeSizeModal } from "./UpgradeOfficeSizeModal";
|
||||
import { ThrowPartyModal } from "./ThrowPartyModal";
|
||||
import { UpgradeOfficeSizeModal } from "./modals/UpgradeOfficeSizeModal";
|
||||
import { ThrowPartyModal } from "./modals/ThrowPartyModal";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
|
||||
|
@ -7,8 +7,8 @@ import { Industries } from "../IndustryData";
|
||||
import { IndustryUpgrades } from "../IndustryUpgrades";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import { MakeProductModal } from "./MakeProductModal";
|
||||
import { ResearchModal } from "./ResearchModal";
|
||||
import { MakeProductModal } from "./modals/MakeProductModal";
|
||||
import { ResearchModal } from "./modals/ResearchModal";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
import { StatsTable } from "../../ui/React/StatsTable";
|
||||
|
@ -6,7 +6,7 @@ import { CorporationConstants } from "../data/Constants";
|
||||
import { Material } from "../Material";
|
||||
import { Product } from "../Product";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { SmartSupplyModal } from "./SmartSupplyModal";
|
||||
import { SmartSupplyModal } from "./modals/SmartSupplyModal";
|
||||
import { ProductElem } from "./ProductElem";
|
||||
import { MaterialElem } from "./MaterialElem";
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
|
@ -20,13 +20,13 @@ interface IProps {
|
||||
export function LevelableUpgrade(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const data = props.upgrade;
|
||||
const level = corp.upgrades[data[0]];
|
||||
const level = corp.upgrades[data.index];
|
||||
|
||||
const baseCost = data[1];
|
||||
const priceMult = data[2];
|
||||
const baseCost = data.basePrice;
|
||||
const priceMult = data.priceMult;
|
||||
const cost = baseCost * Math.pow(priceMult, level);
|
||||
|
||||
const tooltip = data[5];
|
||||
const tooltip = data.desc;
|
||||
function onClick(): void {
|
||||
if (corp.funds < cost) return;
|
||||
try {
|
||||
@ -45,7 +45,7 @@ export function LevelableUpgrade(props: IProps): React.ReactElement {
|
||||
</Button>
|
||||
<Tooltip title={tooltip}>
|
||||
<Typography>
|
||||
{data[4]} - lvl {level}
|
||||
{data.name} - lvl {level}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
@ -5,10 +5,10 @@ import React, { useState } from "react";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { Material } from "../Material";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { ExportModal } from "./ExportModal";
|
||||
import { MaterialMarketTaModal } from "./MaterialMarketTaModal";
|
||||
import { SellMaterialModal } from "./SellMaterialModal";
|
||||
import { PurchaseMaterialModal } from "./PurchaseMaterialModal";
|
||||
import { ExportModal } from "./modals/ExportModal";
|
||||
import { MaterialMarketTaModal } from "./modals/MaterialMarketTaModal";
|
||||
import { SellMaterialModal } from "./modals/SellMaterialModal";
|
||||
import { PurchaseMaterialModal } from "./modals/PurchaseMaterialModal";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
@ -21,6 +21,7 @@ import Tooltip from "@mui/material/Tooltip";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
import { LimitMaterialProductionModal } from "./modals/LimitMaterialProductionModal";
|
||||
|
||||
interface IMaterialProps {
|
||||
warehouse: Warehouse;
|
||||
@ -37,6 +38,8 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
const [exportOpen, setExportOpen] = useState(false);
|
||||
const [sellMaterialOpen, setSellMaterialOpen] = useState(false);
|
||||
const [materialMarketTaOpen, setMaterialMarketTaOpen] = useState(false);
|
||||
const [limitProductionOpen, setLimitProductionOpen] = useState(false);
|
||||
|
||||
const warehouse = props.warehouse;
|
||||
const city = props.city;
|
||||
const mat = props.mat;
|
||||
@ -110,6 +113,12 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
sellButtonText = <>Sell (0.000/0.000)</>;
|
||||
}
|
||||
|
||||
// Limit Production button
|
||||
let limitMaterialButtonText = "Limit Material";
|
||||
if (mat.prdman[0]) {
|
||||
limitMaterialButtonText += " (" + numeralWrapper.format(mat.prdman[1], nf) + ")";
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "2fr 1fr", m: "5px" }}>
|
||||
@ -194,6 +203,14 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Button color={tutorial ? "error" : "primary"} onClick={() => setLimitProductionOpen(true)}>
|
||||
{limitMaterialButtonText}
|
||||
</Button>
|
||||
<LimitMaterialProductionModal
|
||||
material={mat}
|
||||
open={limitProductionOpen}
|
||||
onClose={() => setLimitProductionOpen(false)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
@ -2,18 +2,18 @@
|
||||
import React, { useState } from "react";
|
||||
import { LevelableUpgrade } from "./LevelableUpgrade";
|
||||
import { UnlockUpgrade } from "./UnlockUpgrade";
|
||||
import { BribeFactionModal } from "./BribeFactionModal";
|
||||
import { SellSharesModal } from "./SellSharesModal";
|
||||
import { BuybackSharesModal } from "./BuybackSharesModal";
|
||||
import { IssueDividendsModal } from "./IssueDividendsModal";
|
||||
import { IssueNewSharesModal } from "./IssueNewSharesModal";
|
||||
import { FindInvestorsModal } from "./FindInvestorsModal";
|
||||
import { GoPublicModal } from "./GoPublicModal";
|
||||
import { BribeFactionModal } from "./modals/BribeFactionModal";
|
||||
import { SellSharesModal } from "./modals/SellSharesModal";
|
||||
import { BuybackSharesModal } from "./modals/BuybackSharesModal";
|
||||
import { IssueDividendsModal } from "./modals/IssueDividendsModal";
|
||||
import { IssueNewSharesModal } from "./modals/IssueNewSharesModal";
|
||||
import { FindInvestorsModal } from "./modals/FindInvestorsModal";
|
||||
import { GoPublicModal } from "./modals/GoPublicModal";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { CorporationUnlockUpgrade, CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
|
||||
import { CorporationUpgrade, CorporationUpgrades } from "../data/CorporationUpgrades";
|
||||
import { CorporationUpgrade, CorporationUpgradeIndex, CorporationUpgrades } from "../data/CorporationUpgrades";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
@ -164,9 +164,9 @@ function Upgrades({ rerender }: IUpgradeProps): React.ReactElement {
|
||||
<Typography variant="h4">Unlocks</Typography>
|
||||
<Grid container>
|
||||
{Object.values(CorporationUnlockUpgrades)
|
||||
.filter((upgrade: CorporationUnlockUpgrade) => !corp.unlockUpgrades[upgrade[0]])
|
||||
.filter((upgrade: CorporationUnlockUpgrade) => !corp.unlockUpgrades[upgrade.index])
|
||||
.map((upgrade: CorporationUnlockUpgrade) => (
|
||||
<UnlockUpgrade rerender={rerender} upgradeData={upgrade} key={upgrade[0]} />
|
||||
<UnlockUpgrade rerender={rerender} upgradeData={upgrade} key={upgrade.index} />
|
||||
))}
|
||||
</Grid>
|
||||
</Paper>
|
||||
@ -174,9 +174,9 @@ function Upgrades({ rerender }: IUpgradeProps): React.ReactElement {
|
||||
<Typography variant="h4">Upgrades</Typography>
|
||||
<Grid container>
|
||||
{corp.upgrades
|
||||
.map((level: number, i: number) => CorporationUpgrades[i])
|
||||
.map((level: number, i: number) => CorporationUpgrades[i as CorporationUpgradeIndex])
|
||||
.map((upgrade: CorporationUpgrade) => (
|
||||
<LevelableUpgrade rerender={rerender} upgrade={upgrade} key={upgrade[0]} />
|
||||
<LevelableUpgrade rerender={rerender} upgrade={upgrade} key={upgrade.index} />
|
||||
))}
|
||||
</Grid>
|
||||
</Paper>
|
||||
|
@ -2,10 +2,11 @@ import React, { useState } from "react";
|
||||
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { Product } from "../Product";
|
||||
import { DiscontinueProductModal } from "./DiscontinueProductModal";
|
||||
import { LimitProductProductionModal } from "./LimitProductProductionModal";
|
||||
import { SellProductModal } from "./SellProductModal";
|
||||
import { ProductMarketTaModal } from "./ProductMarketTaModal";
|
||||
import { DiscontinueProductModal } from "./modals/DiscontinueProductModal";
|
||||
import { LimitProductProductionModal } from "./modals/LimitProductProductionModal";
|
||||
import { SellProductModal } from "./modals/SellProductModal";
|
||||
import { ProductMarketTaModal } from "./modals/ProductMarketTaModal";
|
||||
import { CancelProductModal } from "./modals/CancelProductModal";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
@ -32,6 +33,7 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
const [sellOpen, setSellOpen] = useState(false);
|
||||
const [limitOpen, setLimitOpen] = useState(false);
|
||||
const [discontinueOpen, setDiscontinueOpen] = useState(false);
|
||||
const [cancelOpen, setCancelOpen] = useState(false);
|
||||
const [marketTaOpen, setMarketTaOpen] = useState(false);
|
||||
const city = props.city;
|
||||
const product = props.product;
|
||||
@ -111,6 +113,13 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography>{numeralWrapper.format(product.prog, "0.00")}% complete</Typography>
|
||||
<Button onClick={() => setCancelOpen(true)}>Cancel</Button>
|
||||
<CancelProductModal
|
||||
product={product}
|
||||
rerender={props.rerender}
|
||||
open={cancelOpen}
|
||||
onClose={() => setCancelOpen(false)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@ -171,6 +180,13 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
<Typography>Est. Market Price: {numeralWrapper.formatMoney(product.pCost)}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Button onClick={() => setDiscontinueOpen(true)}>Discontinue</Button>
|
||||
<DiscontinueProductModal
|
||||
product={product}
|
||||
rerender={props.rerender}
|
||||
open={discontinueOpen}
|
||||
onClose={() => setDiscontinueOpen(false)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -186,14 +202,6 @@ export function ProductElem(props: IProductProps): React.ReactElement {
|
||||
open={limitOpen}
|
||||
onClose={() => setLimitOpen(false)}
|
||||
/>
|
||||
<Button onClick={() => setDiscontinueOpen(true)}>Discontinue</Button>
|
||||
|
||||
<DiscontinueProductModal
|
||||
product={product}
|
||||
rerender={props.rerender}
|
||||
open={discontinueOpen}
|
||||
onClose={() => setDiscontinueOpen(false)}
|
||||
/>
|
||||
{division.hasResearch("Market-TA.I") && (
|
||||
<>
|
||||
<Button onClick={() => setMarketTaOpen(true)}>Market-TA</Button>
|
||||
|
@ -20,9 +20,9 @@ interface IProps {
|
||||
export function UnlockUpgrade(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const data = props.upgradeData;
|
||||
const tooltip = data[3];
|
||||
const tooltip = data.desc;
|
||||
function onClick(): void {
|
||||
if (corp.funds < data[1]) return;
|
||||
if (corp.funds < data.price) return;
|
||||
try {
|
||||
UU(corp, props.upgradeData);
|
||||
} catch (err) {
|
||||
@ -34,11 +34,11 @@ export function UnlockUpgrade(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<Grid item xs={4}>
|
||||
<Box display="flex" alignItems="center" flexDirection="row-reverse">
|
||||
<Button disabled={corp.funds < data[1]} sx={{ mx: 1 }} onClick={onClick}>
|
||||
<MoneyCost money={data[1]} corp={corp} />
|
||||
<Button disabled={corp.funds < data.price} sx={{ mx: 1 }} onClick={onClick}>
|
||||
<MoneyCost money={data.price} corp={corp} />
|
||||
</Button>
|
||||
<Tooltip title={tooltip}>
|
||||
<Typography>{data[2]}</Typography>
|
||||
<Typography>{data.name}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import { Factions } from "../../../Faction/Factions";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
@ -1,14 +1,14 @@
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { BuyBackShares } from "../Actions";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { BuyBackShares } from "../../Actions";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
34
src/Corporation/ui/modals/CancelProductModal.tsx
Normal file
34
src/Corporation/ui/modals/CancelProductModal.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
|
||||
import { Product } from "../../Product";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
product: Product;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player cancel a product
|
||||
export function CancelProductModal(props: IProps): React.ReactElement {
|
||||
const division = useDivision();
|
||||
function cancel(): void {
|
||||
division.discontinueProduct(props.product);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Are you sure you want to do this? Canceling a product removes it completely and permanently. You will receive no
|
||||
money back by doing so
|
||||
</Typography>
|
||||
<Button onClick={cancel}>Cancel</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
6
src/Corporation/ui/CreateCorporationModal.tsx → src/Corporation/ui/modals/CreateCorporationModal.tsx
6
src/Corporation/ui/CreateCorporationModal.tsx → src/Corporation/ui/modals/CreateCorporationModal.tsx
@ -1,8 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
|
||||
import { Product } from "../Product";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useDivision } from "./Context";
|
||||
import { Product } from "../../Product";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Material } from "../Material";
|
||||
import { Export } from "../Export";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { ExportMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
import { isRelevantMaterial } from "./Helpers";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Material } from "../../Material";
|
||||
import { Export } from "../../Export";
|
||||
import { IIndustry } from "../../IIndustry";
|
||||
import { ExportMaterial } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
import { isRelevantMaterial } from "../Helpers";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
@ -1,13 +1,13 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { useCorporation } from "./Context";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Box from "@mui/material/Box";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
@ -1,13 +1,13 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { IssueDividends } from "../Actions";
|
||||
import { useCorporation } from "./Context";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { IssueDividends } from "../../Actions";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
@ -1,14 +1,14 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { useCorporation } from "./Context";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IEffectTextProps {
|
||||
shares: number | null;
|
53
src/Corporation/ui/modals/LimitMaterialProductionModal.tsx
Normal file
53
src/Corporation/ui/modals/LimitMaterialProductionModal.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { LimitMaterialProduction } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { Material } from "../../Material";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
material: Material;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player limit the production of a product
|
||||
export function LimitMaterialProductionModal(props: IProps): React.ReactElement {
|
||||
const [limit, setLimit] = useState<number | null>(null);
|
||||
|
||||
// reset modal internal state on modal close
|
||||
useEffect(() => {
|
||||
if (!props.open) {
|
||||
setLimit(null);
|
||||
}
|
||||
}, [props.open]);
|
||||
|
||||
function limitMaterialProduction(): void {
|
||||
let qty = limit;
|
||||
if (qty === null) qty = -1;
|
||||
LimitMaterialProduction(props.material, qty);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.key === KEY.ENTER) limitMaterialProduction();
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
if (event.target.value === "") setLimit(null);
|
||||
else setLimit(parseFloat(event.target.value));
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter a limit to the amount of this material you would like to produce per second. Leave the box empty to set no
|
||||
limit.
|
||||
</Typography>
|
||||
<TextField autoFocus={true} placeholder="Limit" type="number" onChange={onChange} onKeyDown={onKeyDown} />
|
||||
<Button onClick={limitMaterialProduction}>Limit production</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import { Product } from "../Product";
|
||||
import { LimitProductProduction } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Product } from "../../Product";
|
||||
import { LimitProductProduction } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
@ -18,6 +18,13 @@ interface IProps {
|
||||
export function LimitProductProductionModal(props: IProps): React.ReactElement {
|
||||
const [limit, setLimit] = useState<number | null>(null);
|
||||
|
||||
// reset modal internal state on modal close
|
||||
useEffect(() => {
|
||||
if (!props.open) {
|
||||
setLimit(null);
|
||||
}
|
||||
}, [props.open]);
|
||||
|
||||
function limitProductProduction(): void {
|
||||
let qty = limit;
|
||||
if (qty === null) qty = -1;
|
@ -1,15 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { Industries } from "../IndustryData";
|
||||
import { MakeProduct } from "../Actions";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Industries } from "../../IndustryData";
|
||||
import { MakeProduct } from "../../Actions";
|
||||
import { useCorporation, useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
8
src/Corporation/ui/MaterialMarketTaModal.tsx → src/Corporation/ui/modals/MaterialMarketTaModal.tsx
8
src/Corporation/ui/MaterialMarketTaModal.tsx → src/Corporation/ui/modals/MaterialMarketTaModal.tsx
@ -1,8 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Material } from "../Material";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useDivision } from "./Context";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { Material } from "../../Material";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
@ -1,8 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Product } from "../Product";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useDivision } from "./Context";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { Product } from "../../Product";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
88
src/Corporation/ui/PurchaseMaterialModal.tsx → src/Corporation/ui/modals/PurchaseMaterialModal.tsx
88
src/Corporation/ui/PurchaseMaterialModal.tsx → src/Corporation/ui/modals/PurchaseMaterialModal.tsx
@ -1,16 +1,16 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { Material } from "../Material";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { BulkPurchase, BuyMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { MaterialSizes } from "../../MaterialSizes";
|
||||
import { Warehouse } from "../../Warehouse";
|
||||
import { Material } from "../../Material";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { BulkPurchase, BuyMaterial } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation, useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IBulkPurchaseTextProps {
|
||||
warehouse: Warehouse;
|
||||
@ -18,37 +18,6 @@ interface IBulkPurchaseTextProps {
|
||||
amount: string;
|
||||
}
|
||||
|
||||
function BulkPurchaseText(props: IBulkPurchaseTextProps): React.ReactElement {
|
||||
const parsedAmt = parseFloat(props.amount);
|
||||
const cost = parsedAmt * props.mat.bCost;
|
||||
|
||||
const matSize = MaterialSizes[props.mat.name];
|
||||
const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize;
|
||||
|
||||
if (parsedAmt * matSize > maxAmount) {
|
||||
return (
|
||||
<>
|
||||
<Typography color={"error"}>Not enough warehouse space to purchase this amount</Typography>
|
||||
</>
|
||||
);
|
||||
} else if (isNaN(cost) || parsedAmt < 0) {
|
||||
return (
|
||||
<>
|
||||
<Typography color={"error"}>Invalid put for Bulk Purchase amount</Typography>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
Purchasing {numeralWrapper.format(parsedAmt, "0,0.00")} of {props.mat.name} will cost{" "}
|
||||
{numeralWrapper.formatMoney(cost)}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface IBPProps {
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
@ -58,6 +27,41 @@ interface IBPProps {
|
||||
function BulkPurchaseSection(props: IBPProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [buyAmt, setBuyAmt] = useState("");
|
||||
const [disabled, setDisabled] = useState(false);
|
||||
|
||||
function BulkPurchaseText(props: IBulkPurchaseTextProps): React.ReactElement {
|
||||
const parsedAmt = parseFloat(props.amount);
|
||||
const cost = parsedAmt * props.mat.bCost;
|
||||
|
||||
const matSize = MaterialSizes[props.mat.name];
|
||||
const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize;
|
||||
|
||||
if (parsedAmt > maxAmount) {
|
||||
setDisabled(true);
|
||||
return (
|
||||
<>
|
||||
<Typography color={"error"}>Not enough warehouse space to purchase this amount</Typography>
|
||||
</>
|
||||
);
|
||||
} else if (isNaN(cost) || parsedAmt < 0) {
|
||||
setDisabled(true);
|
||||
return (
|
||||
<>
|
||||
<Typography color={"error"}>Invalid input for Bulk Purchase amount</Typography>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
setDisabled(false);
|
||||
return (
|
||||
<>
|
||||
<Typography>
|
||||
Purchasing {numeralWrapper.format(parsedAmt, "0,0.00")} of {props.mat.name} will cost{" "}
|
||||
{numeralWrapper.formatMoney(cost)}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function bulkPurchase(): void {
|
||||
try {
|
||||
@ -90,7 +94,9 @@ function BulkPurchaseSection(props: IBPProps): React.ReactElement {
|
||||
placeholder="Bulk Purchase amount"
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<Button onClick={bulkPurchase}>Confirm Bulk Purchase</Button>
|
||||
<Button disabled={disabled} onClick={bulkPurchase}>
|
||||
Confirm Bulk Purchase
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { IndustryResearchTrees } from "../IndustryData";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Research } from "../Actions";
|
||||
import { Node } from "../ResearchTree";
|
||||
import { ResearchMap } from "../ResearchMap";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { IndustryResearchTrees } from "../../IndustryData";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { IIndustry } from "../../IIndustry";
|
||||
import { Research } from "../../Actions";
|
||||
import { Node } from "../../ResearchTree";
|
||||
import { ResearchMap } from "../../ResearchMap";
|
||||
import { Settings } from "../../../Settings/Settings";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Button from "@mui/material/Button";
|
@ -1,12 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Material } from "../Material";
|
||||
import { SellMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Material } from "../../Material";
|
||||
import { SellMaterial } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
function initialPrice(mat: Material): string {
|
||||
let val = mat.sCost ? mat.sCost + "" : "";
|
@ -1,15 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Product } from "../Product";
|
||||
import { SellProduct } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Product } from "../../Product";
|
||||
import { SellProduct } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
function initialPrice(product: Product): string {
|
||||
let val = product.sCost ? product.sCost + "" : "";
|
@ -1,16 +1,16 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { useCorporation } from "../Context";
|
||||
import { ICorporation } from "../../ICorporation";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { SellShares } from "../Actions";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { SellShares } from "../../Actions";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
@ -33,19 +33,22 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
function ProfitIndicator(props: { shares: number | null; corp: ICorporation }): React.ReactElement {
|
||||
if (props.shares === null) return <></>;
|
||||
let text = "";
|
||||
if (isNaN(props.shares) || props.shares <= 0) {
|
||||
return <>ERROR: Invalid value entered for number of shares to sell</>;
|
||||
text = `ERROR: Invalid value entered for number of shares to sell`;
|
||||
} else if (props.shares > corp.numShares) {
|
||||
return <>You don't have this many shares to sell!</>;
|
||||
text = `You don't have this many shares to sell!`;
|
||||
} else {
|
||||
const stockSaleResults = corp.calculateShareSale(props.shares);
|
||||
const profit = stockSaleResults[0];
|
||||
return (
|
||||
<>
|
||||
Sell {props.shares} shares for a total of {numeralWrapper.formatMoney(profit)}
|
||||
</>
|
||||
);
|
||||
text = `Sell ${props.shares} shares for a total of ${numeralWrapper.formatMoney(profit)}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography>
|
||||
<small>{text}</small>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
function sell(): void {
|
||||
@ -84,7 +87,6 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
The current price of your company's stock is {numeralWrapper.formatMoney(corp.sharePrice)}
|
||||
</Typography>
|
||||
<ProfitIndicator shares={shares} corp={corp} />
|
||||
<br />
|
||||
<TextField
|
||||
variant="standard"
|
||||
@ -97,6 +99,7 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
<Button disabled={disabled} onClick={sell} sx={{ mx: 1 }}>
|
||||
Sell shares
|
||||
</Button>
|
||||
<ProfitIndicator shares={shares} corp={corp} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { SetSmartSupply, SetSmartSupplyUseLeftovers } from "../Actions";
|
||||
import { Material } from "../Material";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useDivision } from "./Context";
|
||||
import { Warehouse } from "../../Warehouse";
|
||||
import { SetSmartSupply, SetSmartSupplyUseLeftovers } from "../../Actions";
|
||||
import { Material } from "../../Material";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useDivision } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
@ -1,16 +1,16 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { ThrowParty } from "../Actions";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
|
||||
import { OfficeSpace } from "../../OfficeSpace";
|
||||
import { ThrowParty } from "../../Actions";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Box from "@mui/material/Box";
|
||||
import { KEY } from "../../utils/helpers/keyCodes";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
14
src/Corporation/ui/UpgradeOfficeSizeModal.tsx → src/Corporation/ui/modals/UpgradeOfficeSizeModal.tsx
14
src/Corporation/ui/UpgradeOfficeSizeModal.tsx → src/Corporation/ui/modals/UpgradeOfficeSizeModal.tsx
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { UpgradeOfficeSize } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
import { numeralWrapper } from "../../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../../data/Constants";
|
||||
import { OfficeSpace } from "../../OfficeSpace";
|
||||
import { ICorporation } from "../../ICorporation";
|
||||
import { UpgradeOfficeSize } from "../../Actions";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { useCorporation } from "../Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
@ -17,7 +17,7 @@ export function DummyGrid(props: IProps): React.ReactElement {
|
||||
const ghostGrid = zeros([props.width, props.height]);
|
||||
return (
|
||||
<Box>
|
||||
<Table>
|
||||
<Table sx={{ width: props.width, height: props.height }}>
|
||||
<Grid
|
||||
width={props.width}
|
||||
height={props.height}
|
||||
|
@ -66,6 +66,7 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
user, Stat Fragments increase the efficacy of adjacent Stat Fragments by 10%, and do not need to be
|
||||
charged.
|
||||
</Typography>
|
||||
<br />
|
||||
|
||||
<DummyGrid
|
||||
width={4}
|
||||
@ -86,11 +87,12 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
]}
|
||||
/>
|
||||
<Typography sx={{ fontStyle: "italic" }}>
|
||||
This boost provides a bonus to the touching fragment
|
||||
This Booster Fragment provides a bonus to the adjacent Stat Fragment.
|
||||
</Typography>
|
||||
<br />
|
||||
|
||||
<DummyGrid
|
||||
width={4}
|
||||
width={3}
|
||||
height={4}
|
||||
fragments={[
|
||||
new ActiveFragment({
|
||||
@ -108,8 +110,10 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
]}
|
||||
/>
|
||||
<Typography sx={{ fontStyle: "italic" }}>
|
||||
Even though the booster touches many tiles, the bonus is only applied once.
|
||||
Even though the Booster Fragment touches the Stat Fragment in multiple places, the bonus is only
|
||||
applied once.
|
||||
</Typography>
|
||||
<br />
|
||||
|
||||
<DummyGrid
|
||||
width={4}
|
||||
@ -122,16 +126,17 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
fragment: Fragments.find((f) => f.id === 5) ?? Fragments[0],
|
||||
}),
|
||||
new ActiveFragment({
|
||||
x: 2,
|
||||
y: 0,
|
||||
x: 1,
|
||||
y: 1,
|
||||
rotation: 0,
|
||||
fragment: Fragments.find((f) => f.id === 105) ?? Fragments[0],
|
||||
}),
|
||||
]}
|
||||
/>
|
||||
<Typography sx={{ fontStyle: "italic" }}>
|
||||
Even though the booster touches many tiles, the bonus is only applied once.
|
||||
This Booster Fragment does nothing, as it is not touching a Stat Fragment.
|
||||
</Typography>
|
||||
<br />
|
||||
|
||||
<DummyGrid
|
||||
width={4}
|
||||
@ -158,10 +163,10 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
]}
|
||||
/>
|
||||
<Typography sx={{ fontStyle: "italic" }}>
|
||||
This booster provides bonus to all fragment it touches.
|
||||
This Booster Fragment provides a bonus to both Stat Fragments it's touching.
|
||||
</Typography>
|
||||
|
||||
<br />
|
||||
|
||||
<Typography>
|
||||
Stat Fragments are charged using the stanek.chargeFragment(rootX, rootY) NetScript API function. The
|
||||
charging process ordinarily takes 1000ms to complete, but only takes 200ms during bonus time. When the
|
||||
|
@ -10,6 +10,11 @@ import Button from "@mui/material/Button";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { MenuItem, SelectChangeEvent, TextField, Select } from "@mui/material";
|
||||
import { Bladeburner } from "../../Bladeburner/Bladeburner";
|
||||
import { GangConstants } from "../../Gang/data/Constants";
|
||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||
import { checkForMessagesToSend } from "../../Message/MessageHelpers";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
@ -18,6 +23,8 @@ interface IProps {
|
||||
|
||||
export function General(props: IProps): React.ReactElement {
|
||||
const [error, setError] = useState(false);
|
||||
const [corporationName, setCorporationName] = useState("");
|
||||
const [gangFaction, setGangFaction] = useState("");
|
||||
|
||||
function addMoney(n: number) {
|
||||
return function () {
|
||||
@ -45,6 +52,27 @@ export function General(props: IProps): React.ReactElement {
|
||||
props.router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
function createCorporation(): void {
|
||||
props.player.startCorporation(corporationName);
|
||||
}
|
||||
|
||||
function joinBladeburner(): void {
|
||||
props.player.bladeburner = new Bladeburner(props.player);
|
||||
}
|
||||
|
||||
function startGang(): void {
|
||||
const isHacking = gangFaction === FactionNames.NiteSec || gangFaction === FactionNames.TheBlackHand;
|
||||
props.player.startGang(gangFaction, isHacking);
|
||||
}
|
||||
|
||||
function setGangFactionDropdown(event: SelectChangeEvent<string>): void {
|
||||
setGangFaction(event.target.value);
|
||||
}
|
||||
|
||||
function checkMessages(): void {
|
||||
checkForMessagesToSend();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (error) throw new ReferenceError("Manually thrown error");
|
||||
}, [error]);
|
||||
@ -82,12 +110,29 @@ export function General(props: IProps): React.ReactElement {
|
||||
</Button>
|
||||
<Button onClick={upgradeRam}>+ RAM</Button>
|
||||
<br />
|
||||
<Typography>Corporation Name:</Typography>
|
||||
<TextField value={corporationName} onChange={(x) => setCorporationName(x.target.value)} />
|
||||
<Button onClick={createCorporation}>Create Corporation</Button>
|
||||
<br />
|
||||
<Typography>Gang Faction:</Typography>
|
||||
<Select value={gangFaction} onChange={setGangFactionDropdown}>
|
||||
{GangConstants.Names.map((factionName) => (
|
||||
<MenuItem key={factionName} value={factionName}>
|
||||
{factionName}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Button onClick={startGang}>Start Gang</Button>
|
||||
<br />
|
||||
<Button onClick={joinBladeburner}>Join BladeBurner</Button>
|
||||
<br />
|
||||
|
||||
<Button onClick={quickB1tFlum3}>Quick b1t_flum3.exe</Button>
|
||||
<Button onClick={b1tflum3}>Run b1t_flum3.exe</Button>
|
||||
<Button onClick={quickHackW0r1dD43m0n}>Quick w0rld_d34m0n</Button>
|
||||
<Button onClick={hackW0r1dD43m0n}>Hack w0rld_d34m0n</Button>
|
||||
<Button onClick={() => setError(true)}>Throw Error</Button>
|
||||
<Button onClick={checkMessages}>Check Messages</Button>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
);
|
||||
|
@ -62,7 +62,8 @@ export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
||||
console.error(`Invalid prereq Augmentation ${aug.prereqs[i]}`);
|
||||
continue;
|
||||
}
|
||||
if (prereqAug.owned === false) {
|
||||
|
||||
if (Player.hasAugmentation(prereqAug, true) === false) {
|
||||
hasPrereqs = false;
|
||||
|
||||
// Check if the aug is purchased
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from "react";
|
||||
import { IMap } from "../types";
|
||||
import { FactionNames } from "./data/FactionNames";
|
||||
import { use } from "../ui/Context";
|
||||
import { Option } from "./ui/Option";
|
||||
|
||||
interface FactionInfoParams {
|
||||
infoText?: JSX.Element;
|
||||
@ -10,6 +12,7 @@ interface FactionInfoParams {
|
||||
offerSecurityWork?: boolean;
|
||||
special?: boolean;
|
||||
keepOnInstall?: boolean;
|
||||
assignment?: () => React.ReactElement;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,6 +54,11 @@ export class FactionInfo {
|
||||
*/
|
||||
special: boolean;
|
||||
|
||||
/**
|
||||
* The data to display on the faction screen.
|
||||
*/
|
||||
assignment?: () => React.ReactElement;
|
||||
|
||||
constructor(params: FactionInfoParams) {
|
||||
this.infoText = params.infoText ?? <></>;
|
||||
this.enemies = params.enemies ?? [];
|
||||
@ -60,6 +68,7 @@ export class FactionInfo {
|
||||
|
||||
this.keep = params.keepOnInstall ?? false;
|
||||
this.special = params.special ?? false;
|
||||
this.assignment = params.assignment;
|
||||
}
|
||||
|
||||
offersWork(): boolean {
|
||||
@ -438,11 +447,21 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
),
|
||||
|
||||
special: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
const router = use.Router();
|
||||
return (
|
||||
<Option
|
||||
buttonText={"Open Bladeburner headquarters"}
|
||||
infoText={"You can gain reputation with bladeburner by completing contracts and operations."}
|
||||
onClick={() => router.toBladeburner()}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}),
|
||||
|
||||
// prettier-ignore
|
||||
[FactionNames.ChurchOfTheMachineGod]: new FactionInfo({
|
||||
infoText:(<>
|
||||
// prettier-ignore
|
||||
infoText:(<>
|
||||
{" `` "}<br />
|
||||
{" -odmmNmds: "}<br />
|
||||
{" `hNmo:..-omNh. "}<br />
|
||||
@ -472,11 +491,25 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
{" -smNNNNmdo- "}<br />
|
||||
{" `..` "}<br /><br />
|
||||
Many cultures predict an end to humanity in the near future, a final
|
||||
Armageddon that will end the world; but we disagree.
|
||||
<br /><br />Note that for this faction, reputation can
|
||||
only be gained by charging Stanek's gift.</>),
|
||||
special: true,
|
||||
keepOnInstall: true,
|
||||
Armageddon that will end the world; but we disagree.</>),
|
||||
offerHackingWork: false,
|
||||
offerFieldWork: false,
|
||||
offerSecurityWork: false,
|
||||
special: true,
|
||||
keepOnInstall: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
const router = use.Router();
|
||||
return (
|
||||
<Option
|
||||
buttonText={"Open Staneks Gift"}
|
||||
infoText={
|
||||
"Stanek's Gift is a powerful augmentation that powers up the stat you chose to boost." +
|
||||
"Gaining reputation with the Church of the Machine God can only be done by charging the gift."
|
||||
}
|
||||
onClick={() => router.toStaneksGift()}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}),
|
||||
// prettier-ignore
|
||||
[FactionNames.Infiltrators]: new FactionInfo({
|
||||
|
@ -31,6 +31,17 @@ const useStyles = makeStyles(() =>
|
||||
}),
|
||||
);
|
||||
|
||||
function DefaultAssignment(): React.ReactElement {
|
||||
return (
|
||||
<Typography>
|
||||
Perform work/carry out assignments for your faction to help further its cause! By doing so you will earn
|
||||
reputation for your faction. You will also gain reputation passively over time, although at a very slow rate.
|
||||
Earning reputation will allow you to purchase Augmentations through this faction, which are powerful upgrades that
|
||||
enhance your abilities.
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
export function Info(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
@ -44,6 +55,8 @@ export function Info(props: IProps): React.ReactElement {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const Assignment = props.factionInfo.assignment ?? DefaultAssignment;
|
||||
|
||||
const favorGain = props.faction.getFavorGain();
|
||||
const offersWork =
|
||||
props.factionInfo.offerFieldWork || props.factionInfo.offerSecurityWork || props.factionInfo.offerHackingWork;
|
||||
@ -97,18 +110,7 @@ export function Info(props: IProps): React.ReactElement {
|
||||
</Box>
|
||||
|
||||
<Typography>-------------------------</Typography>
|
||||
<Typography>
|
||||
{offersWork ? (
|
||||
<>
|
||||
Perform work/carry out assignments for your faction to help further its cause! By doing so you will earn
|
||||
reputation for your faction.{" "}
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
You will also gain reputation passively over time, although at a very slow rate. Earning reputation will allow
|
||||
you to purchase Augmentations through this faction, which are powerful upgrades that enhance your abilities.
|
||||
</Typography>
|
||||
<Assignment />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -252,6 +252,7 @@ export class Gang implements IGang {
|
||||
const total = Object.values(AllGangs)
|
||||
.map((g) => g.territory)
|
||||
.reduce((p, c) => p + c, 0);
|
||||
console.log(total);
|
||||
Object.values(AllGangs).forEach((g) => (g.territory /= total));
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,11 @@ import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTuto
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
import { Server } from "../Server/Server";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
|
||||
// Returns a boolean indicating whether the player has Hacknet Servers
|
||||
// (the upgraded form of Hacknet Nodes)
|
||||
export function hasHacknetServers(player: IPlayer): boolean {
|
||||
return player.bitNodeN === 9 || SourceFileFlags[9] > 0;
|
||||
return player.bitNodeN === 9 || player.sourceFileLvl(9) > 0;
|
||||
}
|
||||
|
||||
export function purchaseHacknet(player: IPlayer): number {
|
||||
|
@ -15,7 +15,7 @@ import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
import { Location } from "../Location";
|
||||
import { CreateCorporationModal } from "../../Corporation/ui/CreateCorporationModal";
|
||||
import { CreateCorporationModal } from "../../Corporation/ui/modals/CreateCorporationModal";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
@ -34,6 +34,7 @@ import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
import { ArcadeRoot } from "../../Arcade/ui/ArcadeRoot";
|
||||
import { FactionNames } from "../../Faction/data/FactionNames";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
|
||||
type IProps = {
|
||||
loc: Location;
|
||||
@ -316,7 +317,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return renderGrafting();
|
||||
}
|
||||
case LocationName.Sector12CityHall: {
|
||||
return <CreateCorporation />;
|
||||
return (BitNodeMultipliers.CorporationSoftCap < 0.15 && <></>) || <CreateCorporation />;
|
||||
}
|
||||
case LocationName.Sector12NSA: {
|
||||
return renderBladeburner();
|
||||
|
@ -1,31 +1,14 @@
|
||||
import { Reviver, Generic_toJSON, Generic_fromJSON } from "../utils/JSONReviver";
|
||||
import { MessageFilenames } from "./MessageHelpers";
|
||||
|
||||
export class Message {
|
||||
// Name of Message file
|
||||
filename = "";
|
||||
filename: MessageFilenames;
|
||||
|
||||
// The text contains in the Message
|
||||
msg = "";
|
||||
msg: string;
|
||||
|
||||
// Flag indicating whether this Message has been received by the player
|
||||
recvd = false;
|
||||
|
||||
constructor(filename = "", msg = "") {
|
||||
constructor(filename: MessageFilenames, msg: string) {
|
||||
this.filename = filename;
|
||||
this.msg = msg;
|
||||
this.recvd = false;
|
||||
}
|
||||
|
||||
// Serialize the current object to a JSON save state
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Message", this);
|
||||
}
|
||||
|
||||
// Initializes a Message Object from a JSON save state
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): Message {
|
||||
return Generic_fromJSON(Message, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.Message = Message;
|
||||
|
@ -5,23 +5,23 @@ import { Programs } from "../Programs/Programs";
|
||||
import { Player } from "../Player";
|
||||
import { Page } from "../ui/Router";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { Reviver } from "../utils/JSONReviver";
|
||||
import { FactionNames } from "../Faction/data/FactionNames";
|
||||
import { Server } from "../Server/Server";
|
||||
|
||||
//Sends message to player, including a pop up
|
||||
function sendMessage(msg: Message, forced = false): void {
|
||||
msg.recvd = true;
|
||||
if (forced || !Settings.SuppressMessages) {
|
||||
showMessage(msg.filename);
|
||||
}
|
||||
addMessageToServer(msg, "home");
|
||||
addMessageToServer(msg);
|
||||
}
|
||||
|
||||
function showMessage(name: string): void {
|
||||
function showMessage(name: MessageFilenames): void {
|
||||
const msg = Messages[name];
|
||||
if (!msg) throw new Error("trying to display unexistent message");
|
||||
if (!(msg instanceof Message)) throw new Error("trying to display unexistent message");
|
||||
const txt =
|
||||
"Message received from unknown sender: <br><br>" +
|
||||
"<i>" +
|
||||
@ -34,21 +34,27 @@ function showMessage(name: string): void {
|
||||
}
|
||||
|
||||
//Adds a message to a server
|
||||
function addMessageToServer(msg: Message, serverHostname: string): void {
|
||||
const server = GetServer(serverHostname);
|
||||
if (server == null) {
|
||||
console.warn(`Could not find server ${serverHostname}`);
|
||||
function addMessageToServer(msg: Message): void {
|
||||
//Short-circuit if the message has already been saved
|
||||
if (recvd(msg)) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < server.messages.length; ++i) {
|
||||
const other = server.messages[i];
|
||||
if (msg.filename === other) {
|
||||
return; //Already exists
|
||||
}
|
||||
const server = GetServer("home");
|
||||
if (server == null) {
|
||||
throw new Error("The home server doesn't exist. You done goofed.");
|
||||
}
|
||||
server.messages.push(msg.filename);
|
||||
}
|
||||
|
||||
//Returns whether the given message has already been received
|
||||
function recvd(msg: Message): boolean {
|
||||
const server = GetServer("home");
|
||||
if (server == null) {
|
||||
throw new Error("The home server doesn't exist. You done goofed.");
|
||||
}
|
||||
return server.messages.includes(msg.filename);
|
||||
}
|
||||
|
||||
//Checks if any of the 'timed' messages should be sent
|
||||
function checkForMessagesToSend(): void {
|
||||
if (Router.page() === Page.BitVerse) return;
|
||||
@ -60,46 +66,48 @@ function checkForMessagesToSend(): void {
|
||||
const cybersecTest = Messages[MessageFilenames.CyberSecTest];
|
||||
const nitesecTest = Messages[MessageFilenames.NiteSecTest];
|
||||
const bitrunnersTest = Messages[MessageFilenames.BitRunnersTest];
|
||||
const truthGazer = Messages[MessageFilenames.TruthGazer];
|
||||
const redpill = Messages[MessageFilenames.RedPill];
|
||||
|
||||
if (Player.hasAugmentation(AugmentationNames.TheRedPill)) {
|
||||
//Force the message if the player has never destroyed a BitNode
|
||||
sendMessage(redpill, Player.sourceFiles.length === 0);
|
||||
} else if (!jumper0.recvd && Player.hacking >= 25) {
|
||||
//Get the world daemon required hacking level
|
||||
const worldDaemon = GetServer(SpecialServers.WorldDaemon);
|
||||
if (!(worldDaemon instanceof Server)) {
|
||||
throw new Error("The world daemon is not a server???? Please un-break reality");
|
||||
}
|
||||
//If the daemon can be hacked, send the player icarus.msg
|
||||
if (Player.hacking >= worldDaemon.requiredHackingSkill) {
|
||||
sendMessage(redpill, Player.sourceFiles.length === 0);
|
||||
}
|
||||
//If the daemon cannot be hacked, send the player truthgazer.msg a single time.
|
||||
else if (!recvd(truthGazer)) {
|
||||
sendMessage(truthGazer);
|
||||
}
|
||||
} else if (!recvd(jumper0) && Player.hacking >= 25) {
|
||||
sendMessage(jumper0);
|
||||
const flightName = Programs.Flight.name;
|
||||
const homeComp = Player.getHomeComputer();
|
||||
if (!homeComp.programs.includes(flightName)) {
|
||||
homeComp.programs.push(flightName);
|
||||
}
|
||||
} else if (!jumper1.recvd && Player.hacking >= 40) {
|
||||
} else if (!recvd(jumper1) && Player.hacking >= 40) {
|
||||
sendMessage(jumper1);
|
||||
} else if (!cybersecTest.recvd && Player.hacking >= 50) {
|
||||
} else if (!recvd(cybersecTest) && Player.hacking >= 50) {
|
||||
sendMessage(cybersecTest);
|
||||
} else if (!jumper2.recvd && Player.hacking >= 175) {
|
||||
} else if (!recvd(jumper2) && Player.hacking >= 175) {
|
||||
sendMessage(jumper2);
|
||||
} else if (!nitesecTest.recvd && Player.hacking >= 200) {
|
||||
} else if (!recvd(nitesecTest) && Player.hacking >= 200) {
|
||||
sendMessage(nitesecTest);
|
||||
} else if (!jumper3.recvd && Player.hacking >= 350) {
|
||||
} else if (!recvd(jumper3) && Player.hacking >= 350) {
|
||||
sendMessage(jumper3);
|
||||
} else if (!jumper4.recvd && Player.hacking >= 490) {
|
||||
} else if (!recvd(jumper4) && Player.hacking >= 490) {
|
||||
sendMessage(jumper4);
|
||||
} else if (!bitrunnersTest.recvd && Player.hacking >= 500) {
|
||||
} else if (!recvd(bitrunnersTest) && Player.hacking >= 500) {
|
||||
sendMessage(bitrunnersTest);
|
||||
}
|
||||
}
|
||||
|
||||
function AddToAllMessages(msg: Message): void {
|
||||
Messages[msg.filename] = msg;
|
||||
}
|
||||
|
||||
let Messages: { [key: string]: Message } = {};
|
||||
|
||||
function loadMessages(saveString: string): void {
|
||||
Messages = JSON.parse(saveString, Reviver);
|
||||
}
|
||||
|
||||
enum MessageFilenames {
|
||||
export enum MessageFilenames {
|
||||
Jumper0 = "j0.msg",
|
||||
Jumper1 = "j1.msg",
|
||||
Jumper2 = "j2.msg",
|
||||
@ -108,105 +116,103 @@ enum MessageFilenames {
|
||||
CyberSecTest = "csec-test.msg",
|
||||
NiteSecTest = "nitesec-test.msg",
|
||||
BitRunnersTest = "19dfj3l1nd.msg",
|
||||
TruthGazer = "truthgazer.msg",
|
||||
RedPill = "icarus.msg",
|
||||
}
|
||||
|
||||
function initMessages(): void {
|
||||
//Reset
|
||||
Messages = {};
|
||||
|
||||
//Reset
|
||||
const Messages: Record<MessageFilenames, Message> = {
|
||||
//jump3R Messages
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.Jumper0,
|
||||
"I know you can sense it. I know you're searching for it. " +
|
||||
"It's why you spend night after " +
|
||||
"night at your computer. <br><br>It's real, I've seen it. And I can " +
|
||||
"help you find it. But not right now. You're not ready yet.<br><br>" +
|
||||
"Use this program to track your progress<br><br>" +
|
||||
"The fl1ght.exe program was added to your home computer<br><br>" +
|
||||
"-jump3R",
|
||||
),
|
||||
);
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.Jumper1,
|
||||
`Soon you will be contacted by a hacking group known as ${FactionNames.NiteSec}. ` +
|
||||
"They can help you with your search. <br><br>" +
|
||||
"You should join them, garner their favor, and " +
|
||||
"exploit them for their Augmentations. But do not trust them. " +
|
||||
"They are not what they seem. No one is.<br><br>" +
|
||||
"-jump3R",
|
||||
),
|
||||
);
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.Jumper2,
|
||||
"Do not try to save the world. There is no world to save. If " +
|
||||
"you want to find the truth, worry only about yourself. Ethics and " +
|
||||
`morals will get you killed. <br><br>Watch out for a hacking group known as ${FactionNames.NiteSec}.` +
|
||||
"<br><br>-jump3R",
|
||||
),
|
||||
);
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.Jumper3,
|
||||
"You must learn to walk before you can run. And you must " +
|
||||
`run before you can fly. Look for ${FactionNames.TheBlackHand}. <br><br>` +
|
||||
"I.I.I.I <br><br>-jump3R",
|
||||
),
|
||||
);
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.Jumper4,
|
||||
"To find what you are searching for, you must understand the bits. " +
|
||||
"The bits are all around us. The runners will help you.<br><br>" +
|
||||
"-jump3R",
|
||||
),
|
||||
);
|
||||
[MessageFilenames.Jumper0]: new Message(
|
||||
MessageFilenames.Jumper0,
|
||||
"I know you can sense it. I know you're searching for it. " +
|
||||
"It's why you spend night after " +
|
||||
"night at your computer. <br><br>It's real, I've seen it. And I can " +
|
||||
"help you find it. But not right now. You're not ready yet.<br><br>" +
|
||||
"Use this program to track your progress<br><br>" +
|
||||
"The fl1ght.exe program was added to your home computer<br><br>" +
|
||||
"-jump3R",
|
||||
),
|
||||
|
||||
[MessageFilenames.Jumper1]: new Message(
|
||||
MessageFilenames.Jumper1,
|
||||
`Soon you will be contacted by a hacking group known as ${FactionNames.NiteSec}. ` +
|
||||
"They can help you with your search. <br><br>" +
|
||||
"You should join them, garner their favor, and " +
|
||||
"exploit them for their Augmentations. But do not trust them. " +
|
||||
"They are not what they seem. No one is.<br><br>" +
|
||||
"-jump3R",
|
||||
),
|
||||
|
||||
[MessageFilenames.Jumper2]: new Message(
|
||||
MessageFilenames.Jumper2,
|
||||
"Do not try to save the world. There is no world to save. If " +
|
||||
"you want to find the truth, worry only about yourself. Ethics and " +
|
||||
`morals will get you killed. <br><br>Watch out for a hacking group known as ${FactionNames.NiteSec}.` +
|
||||
"<br><br>-jump3R",
|
||||
),
|
||||
|
||||
[MessageFilenames.Jumper3]: new Message(
|
||||
MessageFilenames.Jumper3,
|
||||
"You must learn to walk before you can run. And you must " +
|
||||
`run before you can fly. Look for ${FactionNames.TheBlackHand}. <br><br>` +
|
||||
"I.I.I.I <br><br>-jump3R",
|
||||
),
|
||||
|
||||
[MessageFilenames.Jumper4]: new Message(
|
||||
MessageFilenames.Jumper4,
|
||||
"To find what you are searching for, you must understand the bits. " +
|
||||
"The bits are all around us. The runners will help you.<br><br>" +
|
||||
"-jump3R",
|
||||
),
|
||||
|
||||
//Messages from hacking factions
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.CyberSecTest,
|
||||
"We've been watching you. Your skills are very impressive. But you're wasting " +
|
||||
"your talents. If you join us, you can put your skills to good use and change " +
|
||||
"the world for the better. If you join us, we can unlock your full potential. <br><br>" +
|
||||
"But first, you must pass our test. Find and install the backdoor on our server. <br><br>" +
|
||||
`-${FactionNames.CyberSec}`,
|
||||
),
|
||||
);
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.NiteSecTest,
|
||||
"People say that the corrupted governments and corporations rule the world. " +
|
||||
"Yes, maybe they do. But do you know who everyone really fears? People " +
|
||||
"like us. Because they can't hide from us. Because they can't fight shadows " +
|
||||
"and ideas with bullets. <br><br>" +
|
||||
"Join us, and people will fear you, too. <br><br>" +
|
||||
"Find and install the backdoor on our server. Then, we will contact you again." +
|
||||
`<br><br>-${FactionNames.NiteSec}`,
|
||||
),
|
||||
);
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.BitRunnersTest,
|
||||
"We know what you are doing. We know what drives you. We know " +
|
||||
"what you are looking for. <br><br> " +
|
||||
"We can help you find the answers.<br><br>" +
|
||||
"run4theh111z",
|
||||
),
|
||||
);
|
||||
[MessageFilenames.CyberSecTest]: new Message(
|
||||
MessageFilenames.CyberSecTest,
|
||||
"We've been watching you. Your skills are very impressive. But you're wasting " +
|
||||
"your talents. If you join us, you can put your skills to good use and change " +
|
||||
"the world for the better. If you join us, we can unlock your full potential. <br><br>" +
|
||||
"But first, you must pass our test. Find and install the backdoor on our server. <br><br>" +
|
||||
`-${FactionNames.CyberSec}`,
|
||||
),
|
||||
|
||||
AddToAllMessages(
|
||||
new Message(
|
||||
MessageFilenames.RedPill,
|
||||
"@)(#V%*N)@(#*)*C)@#%*)*V)@#(*%V@)(#VN%*)@#(*%<br>" +
|
||||
")@B(*#%)@)M#B*%V)____FIND___#$@)#%(B*)@#(*%B)<br>" +
|
||||
"@_#(%_@#M(BDSPOMB__THE-CAVE_#)$(*@#$)@#BNBEGB<br>" +
|
||||
"DFLSMFVMV)#@($*)@#*$MV)@#(*$V)M#(*$)M@(#*VM$)",
|
||||
),
|
||||
);
|
||||
}
|
||||
[MessageFilenames.NiteSecTest]: new Message(
|
||||
MessageFilenames.NiteSecTest,
|
||||
"People say that the corrupted governments and corporations rule the world. " +
|
||||
"Yes, maybe they do. But do you know who everyone really fears? People " +
|
||||
"like us. Because they can't hide from us. Because they can't fight shadows " +
|
||||
"and ideas with bullets. <br><br>" +
|
||||
"Join us, and people will fear you, too. <br><br>" +
|
||||
"Find and install the backdoor on our server. Then, we will contact you again." +
|
||||
`<br><br>-${FactionNames.NiteSec}`,
|
||||
),
|
||||
|
||||
export { Messages, checkForMessagesToSend, showMessage, loadMessages, initMessages };
|
||||
[MessageFilenames.BitRunnersTest]: new Message(
|
||||
MessageFilenames.BitRunnersTest,
|
||||
"We know what you are doing. We know what drives you. We know " +
|
||||
"what you are looking for. <br><br> " +
|
||||
"We can help you find the answers.<br><br>" +
|
||||
"run4theh111z",
|
||||
),
|
||||
|
||||
//Messages to guide players to the daemon
|
||||
[MessageFilenames.TruthGazer]: new Message(
|
||||
MessageFilenames.TruthGazer,
|
||||
//"THE TRUTH CAN NO LONGER ESCAPE YOUR GAZE"
|
||||
"@&*($#@&__TH3__#@A&#@*)__TRU1H__(*)&*)($#@&()E&R)W&<br>" +
|
||||
"%@*$^$()@&$)$*@__CAN__()(@^#)@&@)#__N0__(#@&#)@&@&(<br>" +
|
||||
"*(__LON6ER__^#)@)(()*#@)@__ESCAP3__)#(@(#@*@()@(#*$<br>" +
|
||||
"()@)#$*%)$#()$#__Y0UR__(*)$#()%(&(%)*!)($__GAZ3__#(",
|
||||
),
|
||||
|
||||
[MessageFilenames.RedPill]: new Message(
|
||||
MessageFilenames.RedPill,
|
||||
//"FIND THE-CAVE"
|
||||
"@)(#V%*N)@(#*)*C)@#%*)*V)@#(*%V@)(#VN%*)@#(*%<br>" +
|
||||
")@B(*#%)@)M#B*%V)____FIND___#$@)#%(B*)@#(*%B)<br>" +
|
||||
"@_#(%_@#M(BDSPOMB__THE-CAVE_#)$(*@#$)@#BNBEGB<br>" +
|
||||
"DFLSMFVMV)#@($*)@#*$MV)@#(*$V)M#(*$)M@(#*VM$)",
|
||||
),
|
||||
};
|
||||
|
||||
export { Messages, checkForMessagesToSend, showMessage };
|
||||
|
@ -182,6 +182,8 @@ const singularity: IMap<any> = {
|
||||
installAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
|
||||
isFocused: SF4Cost(0.1),
|
||||
setFocus: SF4Cost(0.1),
|
||||
b1tflum3: SF4Cost(16),
|
||||
destroyW0r1dD43m0n: SF4Cost(32),
|
||||
};
|
||||
|
||||
// Gang API
|
||||
@ -311,6 +313,7 @@ const ui: IMap<any> = {
|
||||
const grafting: IMap<any> = {
|
||||
getAugmentationGraftPrice: 3.75,
|
||||
getAugmentationGraftTime: 3.75,
|
||||
getGraftableAugmentations: 5,
|
||||
graftAugmentation: 7.5,
|
||||
};
|
||||
|
||||
|
@ -34,12 +34,12 @@ import { RunningScript } from "./Script/RunningScript";
|
||||
import {
|
||||
getServerOnNetwork,
|
||||
numCycleForGrowth,
|
||||
numCycleForGrowthCorrected,
|
||||
processSingleServerGrowth,
|
||||
safetlyCreateUniqueServer,
|
||||
} from "./Server/ServerHelpers";
|
||||
import { getPurchaseServerCost, getPurchaseServerLimit, getPurchaseServerMaxRam } from "./Server/ServerPurchases";
|
||||
import { Server } from "./Server/Server";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { influenceStockThroughServerHack, influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing";
|
||||
|
||||
import { isValidFilePath, removeLeadingSlash } from "./Terminal/DirectoryHelpers";
|
||||
@ -638,7 +638,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
if (percentHacked > 0) {
|
||||
// thread count is limited to the maximum number of threads needed
|
||||
threads = Math.ceil(1 / percentHacked);
|
||||
threads = Math.min(threads, Math.ceil(1 / percentHacked));
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,9 +757,26 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
return numCycleForGrowth(server, Number(growth), Player, cores);
|
||||
},
|
||||
growthAnalyzeSecurity: function (_threads: unknown): number {
|
||||
growthAnalyzeSecurity: function (_threads: unknown, _hostname?: unknown, _cores?: unknown): number {
|
||||
updateDynamicRam("growthAnalyzeSecurity", getRamCost(Player, "growthAnalyzeSecurity"));
|
||||
const threads = helper.number("growthAnalyzeSecurity", "threads", _threads);
|
||||
let threads = helper.number("growthAnalyzeSecurity", "threads", _threads);
|
||||
if (_hostname) {
|
||||
const cores = helper.number("growthAnalyzeSecurity", "cores", _cores) || 1;
|
||||
const hostname = helper.string("growthAnalyzeSecurity", "hostname", _hostname);
|
||||
const server = safeGetServer(hostname, "growthAnalyzeSecurity");
|
||||
|
||||
if (!(server instanceof Server)) {
|
||||
workerScript.log("growthAnalyzeSecurity", () => "Cannot be executed on this server.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const maxThreadsNeeded = Math.ceil(
|
||||
numCycleForGrowthCorrected(server, server.moneyMax, server.moneyAvailable, Player, cores),
|
||||
);
|
||||
|
||||
threads = Math.min(threads, maxThreadsNeeded);
|
||||
}
|
||||
|
||||
return 2 * CONSTANTS.ServerFortifyAmount * threads;
|
||||
},
|
||||
weaken: async function (_hostname: unknown, { threads: requestedThreads }: BasicHGWOptions = {}): Promise<number> {
|
||||
@ -1535,7 +1552,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
},
|
||||
getBitNodeMultipliers: function (): IBNMults {
|
||||
updateDynamicRam("getBitNodeMultipliers", getRamCost(Player, "getBitNodeMultipliers"));
|
||||
if (SourceFileFlags[5] <= 0 && Player.bitNodeN !== 5) {
|
||||
if (Player.sourceFileLvl(5) <= 0 && Player.bitNodeN !== 5) {
|
||||
throw makeRuntimeErrorMsg("getBitNodeMultipliers", "Requires Source-File 5 to run.");
|
||||
}
|
||||
const copy = Object.assign({}, BitNodeMultipliers);
|
||||
|
@ -53,6 +53,9 @@ import {
|
||||
SellShares,
|
||||
BuyBackShares,
|
||||
SetSmartSupplyUseLeftovers,
|
||||
LimitMaterialProduction,
|
||||
LimitProductProduction,
|
||||
UpgradeWarehouseCost,
|
||||
} from "../Corporation/Actions";
|
||||
import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades";
|
||||
import { CorporationUpgrades } from "../Corporation/data/CorporationUpgrades";
|
||||
@ -64,6 +67,7 @@ import { CorporationConstants } from "../Corporation/data/Constants";
|
||||
import { IndustryUpgrades } from "../Corporation/IndustryUpgrades";
|
||||
import { ResearchMap } from "../Corporation/ResearchMap";
|
||||
import { Factions } from "../Faction/Factions";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
|
||||
export function NetscriptCorporation(
|
||||
player: IPlayer,
|
||||
@ -74,6 +78,8 @@ export function NetscriptCorporation(
|
||||
if (!player.canAccessCorporation() || player.hasCorporation()) return false;
|
||||
if (!corporationName) return false;
|
||||
if (player.bitNodeN !== 3 && !selfFund) throw new Error("cannot use seed funds outside of BitNode 3");
|
||||
if (BitNodeMultipliers.CorporationSoftCap < 0.15)
|
||||
throw new Error(`You cannot create a corporation in Bitnode ${player.bitNodeN}`);
|
||||
|
||||
if (selfFund) {
|
||||
if (!player.canAfford(150e9)) return false;
|
||||
@ -88,35 +94,35 @@ export function NetscriptCorporation(
|
||||
|
||||
function hasUnlockUpgrade(upgradeName: string): boolean {
|
||||
const corporation = getCorporation();
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade[2] === upgradeName);
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade.name === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
const upgN = upgrade[0];
|
||||
const upgN = upgrade.index;
|
||||
return corporation.unlockUpgrades[upgN] === 1;
|
||||
}
|
||||
|
||||
function getUnlockUpgradeCost(upgradeName: string): number {
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade[2] === upgradeName);
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade.name === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
return upgrade[1];
|
||||
return upgrade.price;
|
||||
}
|
||||
|
||||
function getUpgradeLevel(_upgradeName: string): number {
|
||||
const upgradeName = helper.string("levelUpgrade", "upgradeName", _upgradeName);
|
||||
const corporation = getCorporation();
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade[4] === upgradeName);
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
const upgN = upgrade[0];
|
||||
const upgN = upgrade.index;
|
||||
return corporation.upgrades[upgN];
|
||||
}
|
||||
|
||||
function getUpgradeLevelCost(_upgradeName: string): number {
|
||||
const upgradeName = helper.string("levelUpgrade", "upgradeName", _upgradeName);
|
||||
const corporation = getCorporation();
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade[4] === upgradeName);
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
const upgN = upgrade[0];
|
||||
const baseCost = upgrade[1];
|
||||
const priceMult = upgrade[2];
|
||||
const upgN = upgrade.index;
|
||||
const baseCost = upgrade.basePrice;
|
||||
const priceMult = upgrade.priceMult;
|
||||
const level = corporation.upgrades[upgN];
|
||||
return baseCost * Math.pow(priceMult, level);
|
||||
}
|
||||
@ -311,12 +317,16 @@ export function NetscriptCorporation(
|
||||
checkAccess("getPurchaseWarehouseCost", 7);
|
||||
return CorporationConstants.WarehouseInitialCost;
|
||||
},
|
||||
getUpgradeWarehouseCost: function (_divisionName: unknown, _cityName: unknown): number {
|
||||
getUpgradeWarehouseCost: function (_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): number {
|
||||
checkAccess("upgradeWarehouse", 7);
|
||||
const divisionName = helper.string("getUpgradeWarehouseCost", "divisionName", _divisionName);
|
||||
const cityName = helper.city("getUpgradeWarehouseCost", "cityName", _cityName);
|
||||
const amt = helper.number("getUpgradeWarehouseCost", "amount", _amt);
|
||||
if (amt < 1) {
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.getUpgradeWarehouseCost`, "You must provide a positive number");
|
||||
}
|
||||
const warehouse = getWarehouse(divisionName, cityName);
|
||||
return CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
|
||||
return UpgradeWarehouseCost(warehouse, amt);
|
||||
},
|
||||
hasWarehouse: function (_divisionName: unknown, _cityName: unknown): boolean {
|
||||
checkAccess("hasWarehouse", 7);
|
||||
@ -348,6 +358,7 @@ export function NetscriptCorporation(
|
||||
const material = getMaterial(divisionName, cityName, materialName);
|
||||
const corporation = getCorporation();
|
||||
return {
|
||||
cost: material.bCost,
|
||||
name: material.name,
|
||||
qty: material.qty,
|
||||
qlt: material.qlt,
|
||||
@ -389,12 +400,16 @@ export function NetscriptCorporation(
|
||||
const corporation = getCorporation();
|
||||
PurchaseWarehouse(corporation, getDivision(divisionName), cityName);
|
||||
},
|
||||
upgradeWarehouse: function (_divisionName: unknown, _cityName: unknown): void {
|
||||
upgradeWarehouse: function (_divisionName: unknown, _cityName: unknown, _amt: unknown = 1): void {
|
||||
checkAccess("upgradeWarehouse", 7);
|
||||
const divisionName = helper.string("upgradeWarehouse", "divisionName", _divisionName);
|
||||
const cityName = helper.city("upgradeWarehouse", "cityName", _cityName);
|
||||
const amt = helper.number("upgradeWarehouse", "amount", _amt);
|
||||
const corporation = getCorporation();
|
||||
UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName));
|
||||
if (amt < 1) {
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.upgradeWarehouse`, "You must provide a positive number");
|
||||
}
|
||||
UpgradeWarehouse(corporation, getDivision(divisionName), getWarehouse(divisionName, cityName), amt);
|
||||
},
|
||||
sellMaterial: function (
|
||||
_divisionName: unknown,
|
||||
@ -508,6 +523,19 @@ export function NetscriptCorporation(
|
||||
const corporation = getCorporation();
|
||||
MakeProduct(corporation, getDivision(divisionName), cityName, productName, designInvest, marketingInvest);
|
||||
},
|
||||
limitProductProduction: function (
|
||||
_divisionName: unknown,
|
||||
_productName: unknown,
|
||||
_cityName: unknown,
|
||||
_qty: unknown,
|
||||
) {
|
||||
checkAccess("limitProductProduction", 7);
|
||||
const divisionName = helper.string("limitProductProduction", "divisionName", _divisionName);
|
||||
const cityName = helper.city("limitMaterialProduction", "cityName", _cityName);
|
||||
const productName = helper.string("limitProductProduction", "productName", _productName);
|
||||
const qty = helper.number("limitMaterialProduction", "qty", _qty);
|
||||
LimitProductProduction(getProduct(divisionName, productName), cityName, qty);
|
||||
},
|
||||
exportMaterial: function (
|
||||
_sourceDivision: unknown,
|
||||
_sourceCity: unknown,
|
||||
@ -548,6 +576,19 @@ export function NetscriptCorporation(
|
||||
const amt = helper.string("cancelExportMaterial", "amt", _amt);
|
||||
CancelExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "");
|
||||
},
|
||||
limitMaterialProduction: function (
|
||||
_divisionName: unknown,
|
||||
_cityName: unknown,
|
||||
_materialName: unknown,
|
||||
_qty: unknown,
|
||||
) {
|
||||
checkAccess("limitMaterialProduction", 7);
|
||||
const divisionName = helper.string("limitMaterialProduction", "divisionName", _divisionName);
|
||||
const cityName = helper.city("limitMaterialProduction", "cityName", _cityName);
|
||||
const materialName = helper.string("limitMaterialProduction", "materialName", _materialName);
|
||||
const qty = helper.number("limitMaterialProduction", "qty", _qty);
|
||||
LimitMaterialProduction(getMaterial(divisionName, cityName, materialName), qty);
|
||||
},
|
||||
setMaterialMarketTA1: function (
|
||||
_divisionName: unknown,
|
||||
_cityName: unknown,
|
||||
@ -820,7 +861,7 @@ export function NetscriptCorporation(
|
||||
checkAccess("unlockUpgrade");
|
||||
const upgradeName = helper.string("unlockUpgrade", "upgradeName", _upgradeName);
|
||||
const corporation = getCorporation();
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade[2] === upgradeName);
|
||||
const upgrade = Object.values(CorporationUnlockUpgrades).find((upgrade) => upgrade.name === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
UnlockUpgrade(corporation, upgrade);
|
||||
},
|
||||
@ -828,7 +869,7 @@ export function NetscriptCorporation(
|
||||
checkAccess("levelUpgrade");
|
||||
const upgradeName = helper.string("levelUpgrade", "upgradeName", _upgradeName);
|
||||
const corporation = getCorporation();
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade[4] === upgradeName);
|
||||
const upgrade = Object.values(CorporationUpgrades).find((upgrade) => upgrade.name === upgradeName);
|
||||
if (upgrade === undefined) throw new Error(`No upgrade named '${upgradeName}'`);
|
||||
LevelUpgrade(corporation, upgrade);
|
||||
},
|
||||
|
@ -3,11 +3,13 @@ import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Exploit } from "../Exploits/Exploit";
|
||||
import * as bcrypt from "bcryptjs";
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { Apr1Events as devMenu } from "../ui/Apr1";
|
||||
|
||||
export interface INetscriptExtra {
|
||||
heart: {
|
||||
break(): number;
|
||||
};
|
||||
openDevMenu(): void;
|
||||
exploit(): void;
|
||||
bypass(doc: Document): void;
|
||||
alterReality(): void;
|
||||
@ -22,6 +24,9 @@ export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, help
|
||||
return player.karma;
|
||||
},
|
||||
},
|
||||
openDevMenu: function (): void {
|
||||
devMenu.emit();
|
||||
},
|
||||
exploit: function (): void {
|
||||
player.giveExploit(Exploit.UndocumentedFunctionCall);
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import { CityName } from "../Locations/data/CityNames";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation";
|
||||
import { getAvailableAugs } from "../PersonObjects/Grafting/ui/GraftingRoot";
|
||||
import { getGraftingAvailableAugs } from "../PersonObjects/Grafting/GraftingHelpers";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
@ -28,7 +28,7 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
||||
updateRam("getAugmentationGraftPrice");
|
||||
const augName = helper.string("getAugmentationGraftPrice", "augName", _augName);
|
||||
checkGraftingAPIAccess("getAugmentationGraftPrice");
|
||||
if (!Augmentations.hasOwnProperty(augName)) {
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !Augmentations.hasOwnProperty(augName)) {
|
||||
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftPrice", `Invalid aug: ${augName}`);
|
||||
}
|
||||
const craftableAug = new GraftableAugmentation(Augmentations[augName]);
|
||||
@ -39,13 +39,20 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
||||
updateRam("getAugmentationGraftTime");
|
||||
const augName = helper.string("getAugmentationGraftTime", "augName", _augName);
|
||||
checkGraftingAPIAccess("getAugmentationGraftTime");
|
||||
if (!Augmentations.hasOwnProperty(augName)) {
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !Augmentations.hasOwnProperty(augName)) {
|
||||
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftTime", `Invalid aug: ${augName}`);
|
||||
}
|
||||
const craftableAug = new GraftableAugmentation(Augmentations[augName]);
|
||||
return craftableAug.time;
|
||||
},
|
||||
|
||||
getGraftableAugmentations: (): string[] => {
|
||||
updateRam("getGraftableAugmentations");
|
||||
checkGraftingAPIAccess("getGraftableAugmentations");
|
||||
const graftableAugs = getGraftingAvailableAugs(player);
|
||||
return graftableAugs;
|
||||
},
|
||||
|
||||
graftAugmentation: (_augName: string, _focus: unknown = true): boolean => {
|
||||
updateRam("graftAugmentation");
|
||||
const augName = helper.string("graftAugmentation", "augName", _augName);
|
||||
@ -57,7 +64,7 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
|
||||
"You must be in New Tokyo to begin grafting an Augmentation.",
|
||||
);
|
||||
}
|
||||
if (!getAvailableAugs(player).includes(augName)) {
|
||||
if (!getGraftingAvailableAugs(player).includes(augName) || !Augmentations.hasOwnProperty(augName)) {
|
||||
workerScript.log("grafting.graftAugmentation", () => `Invalid aug: ${augName}`);
|
||||
return false;
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ import { Server } from "../Server/Server";
|
||||
import { netscriptCanHack } from "../Hacking/netscriptCanHack";
|
||||
import { FactionInfos } from "../Faction/FactionInfo";
|
||||
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
|
||||
import { enterBitNode } from "../RedPill";
|
||||
|
||||
export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript): InternalAPI<ISingularity> {
|
||||
const getAugmentation = function (_ctx: NetscriptContext, name: string): Augmentation {
|
||||
@ -94,8 +96,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
return {
|
||||
getOwnedAugmentations: (_ctx: NetscriptContext) =>
|
||||
function (_purchased: unknown = false): string[] {
|
||||
const purchased = _ctx.helper.boolean(_purchased);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const purchased = _ctx.helper.boolean(_purchased);
|
||||
const res = [];
|
||||
for (let i = 0; i < player.augmentations.length; ++i) {
|
||||
res.push(player.augmentations[i].name);
|
||||
@ -109,52 +111,52 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
getAugmentationsFromFaction: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown): string[] {
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const faction = getFaction(_ctx, facName);
|
||||
|
||||
return getFactionAugmentationsFiltered(player, faction);
|
||||
},
|
||||
getAugmentationCost: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): [number, number] {
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return [aug.baseRepRequirement, aug.baseCost];
|
||||
},
|
||||
getAugmentationPrereq: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): string[] {
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return aug.prereqs.slice();
|
||||
},
|
||||
getAugmentationPrice: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): number {
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return aug.baseCost;
|
||||
},
|
||||
getAugmentationRepReq: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): number {
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return aug.baseRepRequirement;
|
||||
},
|
||||
getAugmentationStats: (_ctx: NetscriptContext) =>
|
||||
function (_augName: unknown): AugmentationStats {
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
return Object.assign({}, aug.mults);
|
||||
},
|
||||
purchaseAugmentation: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown, _augName: unknown): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const augName = _ctx.helper.string("augName", _augName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const fac = getFaction(_ctx, facName);
|
||||
const aug = getAugmentation(_ctx, augName);
|
||||
|
||||
@ -200,8 +202,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
softReset: (_ctx: NetscriptContext) =>
|
||||
function (_cbScript: unknown = ""): void {
|
||||
const cbScript = _ctx.helper.string("cbScript", _cbScript);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const cbScript = _ctx.helper.string("cbScript", _cbScript);
|
||||
|
||||
workerScript.log("softReset", () => "Soft resetting. This will cause this script to be killed");
|
||||
setTimeout(() => {
|
||||
@ -215,8 +217,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
installAugmentations: (_ctx: NetscriptContext) =>
|
||||
function (_cbScript: unknown = ""): boolean {
|
||||
const cbScript = _ctx.helper.string("cbScript", _cbScript);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const cbScript = _ctx.helper.string("cbScript", _cbScript);
|
||||
|
||||
if (player.queuedAugmentations.length === 0) {
|
||||
workerScript.log("installAugmentations", () => "You do not have any Augmentations to be installed.");
|
||||
@ -239,8 +241,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
goToLocation: (_ctx: NetscriptContext) =>
|
||||
function (_locationName: unknown): boolean {
|
||||
const locationName = _ctx.helper.string("locationName", _locationName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const locationName = _ctx.helper.string("locationName", _locationName);
|
||||
const location = Object.values(Locations).find((l) => l.name === locationName);
|
||||
if (!location) {
|
||||
workerScript.log("goToLocation", () => `No location named ${locationName}`);
|
||||
@ -256,10 +258,10 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
universityCourse: (_ctx: NetscriptContext) =>
|
||||
function (_universityName: unknown, _className: unknown, _focus: unknown = true): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const universityName = _ctx.helper.string("universityName", _universityName);
|
||||
const className = _ctx.helper.string("className", _className);
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const wasFocusing = player.focus;
|
||||
if (player.isWorking) {
|
||||
const txt = player.singularityStopWork();
|
||||
@ -347,10 +349,10 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
gymWorkout: (_ctx: NetscriptContext) =>
|
||||
function (_gymName: unknown, _stat: unknown, _focus: unknown = true): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const gymName = _ctx.helper.string("gymName", _gymName);
|
||||
const stat = _ctx.helper.string("stat", _stat);
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const wasFocusing = player.focus;
|
||||
if (player.isWorking) {
|
||||
const txt = player.singularityStopWork();
|
||||
@ -462,8 +464,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
travelToCity: (_ctx: NetscriptContext) =>
|
||||
function (_cityName: unknown): boolean {
|
||||
const cityName = _ctx.helper.city("cityName", _cityName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const cityName = _ctx.helper.city("cityName", _cityName);
|
||||
|
||||
switch (cityName) {
|
||||
case CityName.Aevum:
|
||||
@ -520,8 +522,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
purchaseProgram: (_ctx: NetscriptContext) =>
|
||||
function (_programName: unknown): boolean {
|
||||
const programName = _ctx.helper.string("programName", _programName).toLowerCase();
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const programName = _ctx.helper.string("programName", _programName).toLowerCase();
|
||||
|
||||
if (!player.hasTorRouter()) {
|
||||
workerScript.log("purchaseProgram", () => "You do not have the TOR router.");
|
||||
@ -569,8 +571,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
connect: (_ctx: NetscriptContext) =>
|
||||
function (_hostname: unknown): boolean {
|
||||
const hostname = _ctx.helper.string("hostname", _hostname);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const hostname = _ctx.helper.string("hostname", _hostname);
|
||||
if (!hostname) {
|
||||
throw _ctx.helper.makeRuntimeErrorMsg(`Invalid hostname: '${hostname}'`);
|
||||
}
|
||||
@ -580,6 +582,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
throw _ctx.helper.makeRuntimeErrorMsg(`Invalid hostname: '${hostname}'`);
|
||||
}
|
||||
|
||||
//Home case
|
||||
if (hostname === "home") {
|
||||
player.getCurrentServer().isConnectedTo = false;
|
||||
player.currentServer = player.getHomeComputer().hostname;
|
||||
@ -588,6 +591,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
return true;
|
||||
}
|
||||
|
||||
//Adjacent server case
|
||||
const server = player.getCurrentServer();
|
||||
for (let i = 0; i < server.serversOnNetwork.length; i++) {
|
||||
const other = getServerOnNetwork(server, i);
|
||||
@ -601,6 +605,17 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
}
|
||||
}
|
||||
|
||||
//Backdoor case
|
||||
const other = GetServer(hostname);
|
||||
if (other !== null && other instanceof Server && other.backdoorInstalled) {
|
||||
player.getCurrentServer().isConnectedTo = false;
|
||||
player.currentServer = target.hostname;
|
||||
player.getCurrentServer().isConnectedTo = true;
|
||||
Terminal.setcwd("/");
|
||||
return true;
|
||||
}
|
||||
|
||||
//Failure case
|
||||
return false;
|
||||
},
|
||||
manualHack: (_ctx: NetscriptContext) =>
|
||||
@ -649,8 +664,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
setFocus: (_ctx: NetscriptContext) =>
|
||||
function (_focus: unknown): boolean {
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
if (!player.isWorking) {
|
||||
throw _ctx.helper.makeRuntimeErrorMsg("Not currently working");
|
||||
}
|
||||
@ -849,9 +864,9 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
workForCompany: (_ctx: NetscriptContext) =>
|
||||
function (_companyName: unknown, _focus: unknown = true): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
let companyName = _ctx.helper.string("companyName", _companyName);
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
|
||||
// Sanitize input
|
||||
if (companyName == null) {
|
||||
@ -905,9 +920,9 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
applyToCompany: (_ctx: NetscriptContext) =>
|
||||
function (_companyName: unknown, _field: unknown): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
const field = _ctx.helper.string("field", _field);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
getCompany(_ctx, companyName);
|
||||
|
||||
player.location = companyName as LocationName;
|
||||
@ -977,22 +992,22 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
getCompanyRep: (_ctx: NetscriptContext) =>
|
||||
function (_companyName: unknown): number {
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
const company = getCompany(_ctx, companyName);
|
||||
return company.playerReputation;
|
||||
},
|
||||
getCompanyFavor: (_ctx: NetscriptContext) =>
|
||||
function (_companyName: unknown): number {
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
const company = getCompany(_ctx, companyName);
|
||||
return company.favor;
|
||||
},
|
||||
getCompanyFavorGain: (_ctx: NetscriptContext) =>
|
||||
function (_companyName: unknown): number {
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const companyName = _ctx.helper.string("companyName", _companyName);
|
||||
const company = getCompany(_ctx, companyName);
|
||||
return company.getFavorGain();
|
||||
},
|
||||
@ -1004,8 +1019,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
joinFaction: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown): boolean {
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
getFaction(_ctx, facName);
|
||||
|
||||
if (!player.factionInvitations.includes(facName)) {
|
||||
@ -1028,10 +1043,10 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
workForFaction: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown, _type: unknown, _focus: unknown = true): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const type = _ctx.helper.string("type", _type);
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
getFaction(_ctx, facName);
|
||||
|
||||
// if the player is in a gang and the target faction is any of the gang faction, fail
|
||||
@ -1117,30 +1132,30 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
getFactionRep: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown): number {
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const faction = getFaction(_ctx, facName);
|
||||
return faction.playerReputation;
|
||||
},
|
||||
getFactionFavor: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown): number {
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const faction = getFaction(_ctx, facName);
|
||||
return faction.favor;
|
||||
},
|
||||
getFactionFavorGain: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown): number {
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const faction = getFaction(_ctx, facName);
|
||||
return faction.getFavorGain();
|
||||
},
|
||||
donateToFaction: (_ctx: NetscriptContext) =>
|
||||
function (_facName: unknown, _amt: unknown): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const facName = _ctx.helper.string("facName", _facName);
|
||||
const amt = _ctx.helper.number("amt", _amt);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const faction = getFaction(_ctx, facName);
|
||||
if (!player.factions.includes(faction.name)) {
|
||||
workerScript.log("donateToFaction", () => `You can't donate to '${facName}' because you aren't a member`);
|
||||
@ -1187,9 +1202,9 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
createProgram: (_ctx: NetscriptContext) =>
|
||||
function (_programName: unknown, _focus: unknown = true): boolean {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const programName = _ctx.helper.string("programName", _programName).toLowerCase();
|
||||
const focus = _ctx.helper.boolean(_focus);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
|
||||
const wasFocusing = player.focus;
|
||||
if (player.isWorking) {
|
||||
@ -1236,8 +1251,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
commitCrime: (_ctx: NetscriptContext) =>
|
||||
function (_crimeRoughName: unknown): number {
|
||||
const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName);
|
||||
|
||||
if (player.isWorking) {
|
||||
const txt = player.singularityStopWork();
|
||||
@ -1257,8 +1272,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
getCrimeChance: (_ctx: NetscriptContext) =>
|
||||
function (_crimeRoughName: unknown): number {
|
||||
const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName);
|
||||
|
||||
const crime = findCrime(crimeRoughName.toLowerCase());
|
||||
if (crime == null) {
|
||||
@ -1269,8 +1284,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
getCrimeStats: (_ctx: NetscriptContext) =>
|
||||
function (_crimeRoughName: unknown): CrimeStats {
|
||||
const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const crimeRoughName = _ctx.helper.string("crimeRoughName", _crimeRoughName);
|
||||
|
||||
const crime = findCrime(crimeRoughName.toLowerCase());
|
||||
if (crime == null) {
|
||||
@ -1292,8 +1307,8 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
},
|
||||
getDarkwebProgramCost: (_ctx: NetscriptContext) =>
|
||||
function (_programName: unknown): number {
|
||||
const programName = _ctx.helper.string("programName", _programName).toLowerCase();
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const programName = _ctx.helper.string("programName", _programName).toLowerCase();
|
||||
|
||||
// If we don't have Tor, log it and return -1
|
||||
if (!player.hasTorRouter()) {
|
||||
@ -1322,5 +1337,51 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript
|
||||
}
|
||||
return item.price;
|
||||
},
|
||||
b1tflum3:
|
||||
(_ctx: NetscriptContext) =>
|
||||
(_nextBN: unknown, _callbackScript: unknown = ""): void => {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const nextBN = _ctx.helper.number("nextBN", _nextBN);
|
||||
const callbackScript = _ctx.helper.string("callbackScript", _callbackScript);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
enterBitNode(Router, true, player.bitNodeN, nextBN);
|
||||
if (callbackScript)
|
||||
setTimeout(() => {
|
||||
runAfterReset(callbackScript);
|
||||
}, 0);
|
||||
},
|
||||
destroyW0r1dD43m0n:
|
||||
(_ctx: NetscriptContext) =>
|
||||
(_nextBN: unknown, _callbackScript: unknown = ""): void => {
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
const nextBN = _ctx.helper.number("nextBN", _nextBN);
|
||||
const callbackScript = _ctx.helper.string("callbackScript", _callbackScript);
|
||||
_ctx.helper.checkSingularityAccess();
|
||||
|
||||
const hackingRequirements = (): boolean => {
|
||||
const wd = GetServer(SpecialServers.WorldDaemon);
|
||||
if (!(wd instanceof Server))
|
||||
throw new Error("WorldDaemon was not a normal server. This is a bug contact dev.");
|
||||
if (player.hacking < wd.requiredHackingSkill) return false;
|
||||
if (!wd.hasAdminRights) return false;
|
||||
return true;
|
||||
};
|
||||
const bladeburnerRequirements = (): boolean => {
|
||||
if (!player.inBladeburner()) return false;
|
||||
if (!player.bladeburner) return false;
|
||||
return player.bladeburner.blackops[BlackOperationNames.OperationDaedalus];
|
||||
};
|
||||
|
||||
if (!hackingRequirements() && !bladeburnerRequirements()) {
|
||||
_ctx.log(() => "Requirements not met to destroy the world daemon");
|
||||
return;
|
||||
}
|
||||
|
||||
enterBitNode(Router, false, player.bitNodeN, nextBN);
|
||||
if (callbackScript)
|
||||
setTimeout(() => {
|
||||
runAfterReset(callbackScript);
|
||||
}, 0);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { INetscriptHelper } from "./INetscriptHelper";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||
import { FactionWorkType } from "../Faction/FactionWorkTypeEnum";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
import { SleeveTaskType } from "../PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
|
||||
@ -20,7 +19,7 @@ import {
|
||||
|
||||
export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): ISleeve {
|
||||
const checkSleeveAPIAccess = function (func: string): void {
|
||||
if (player.bitNodeN !== 10 && !SourceFileFlags[10]) {
|
||||
if (player.bitNodeN !== 10 && !player.sourceFileLvl(10)) {
|
||||
throw helper.makeRuntimeErrorMsg(
|
||||
`sleeve.${func}`,
|
||||
"You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10",
|
||||
|
15
src/PersonObjects/Grafting/GraftingHelpers.ts
Normal file
15
src/PersonObjects/Grafting/GraftingHelpers.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
export const getGraftingAvailableAugs = (player: IPlayer): string[] => {
|
||||
const augs: string[] = [];
|
||||
|
||||
for (const [augName, aug] of Object.entries(Augmentations)) {
|
||||
if (augName === AugmentationNames.NeuroFluxGovernor || augName === AugmentationNames.TheRedPill || aug.isSpecial)
|
||||
continue;
|
||||
augs.push(augName);
|
||||
}
|
||||
|
||||
return augs.filter((augmentation: string) => !player.hasAugmentation(augmentation));
|
||||
};
|
@ -15,22 +15,11 @@ import { ConfirmationModal } from "../../../ui/React/ConfirmationModal";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { convertTimeMsToTimeElapsedString, formatNumber } from "../../../utils/StringHelperFunctions";
|
||||
import { IPlayer } from "../../IPlayer";
|
||||
import { getGraftingAvailableAugs } from "../GraftingHelpers";
|
||||
import { GraftableAugmentation } from "../GraftableAugmentation";
|
||||
|
||||
const GraftableAugmentations: IMap<GraftableAugmentation> = {};
|
||||
|
||||
export const getAvailableAugs = (player: IPlayer): string[] => {
|
||||
const augs: string[] = [];
|
||||
|
||||
for (const [augName, aug] of Object.entries(Augmentations)) {
|
||||
if (augName === AugmentationNames.NeuroFluxGovernor || augName === AugmentationNames.TheRedPill || aug.isSpecial)
|
||||
continue;
|
||||
augs.push(augName);
|
||||
}
|
||||
|
||||
return augs.filter((augmentation: string) => !player.hasAugmentation(augmentation));
|
||||
};
|
||||
|
||||
const canGraft = (player: IPlayer, aug: GraftableAugmentation): boolean => {
|
||||
if (player.money < aug.cost) {
|
||||
return false;
|
||||
@ -71,7 +60,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
GraftableAugmentations[name] = graftableAug;
|
||||
}
|
||||
|
||||
const [selectedAug, setSelectedAug] = useState(getAvailableAugs(player)[0]);
|
||||
const [selectedAug, setSelectedAug] = useState(getGraftingAvailableAugs(player)[0]);
|
||||
const [graftOpen, setGraftOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@ -92,10 +81,10 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
|
||||
<Box sx={{ my: 3 }}>
|
||||
<Typography variant="h5">Graft Augmentations</Typography>
|
||||
{getAvailableAugs(player).length > 0 ? (
|
||||
{getGraftingAvailableAugs(player).length > 0 ? (
|
||||
<Paper sx={{ my: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
|
||||
{getAvailableAugs(player).map((k, i) => (
|
||||
{getGraftingAvailableAugs(player).map((k, i) => (
|
||||
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
|
||||
<Typography>{k}</Typography>
|
||||
</ListItemButton>
|
||||
|
@ -7,7 +7,7 @@ import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
|
||||
import { calculateEntropy } from "../Grafting/EntropyAccumulation";
|
||||
|
||||
export function hasAugmentation(this: IPlayer, aug: string | Augmentation, installed = false): boolean {
|
||||
export function hasAugmentation(this: IPlayer, aug: string | Augmentation, includeQueued = false): boolean {
|
||||
const augName: string = aug instanceof Augmentation ? aug.name : aug;
|
||||
|
||||
for (const owned of this.augmentations) {
|
||||
@ -16,7 +16,7 @@ export function hasAugmentation(this: IPlayer, aug: string | Augmentation, insta
|
||||
}
|
||||
}
|
||||
|
||||
if (!installed) {
|
||||
if (!includeQueued) {
|
||||
for (const owned of this.queuedAugmentations) {
|
||||
if (owned.name === augName) {
|
||||
return true;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Bladeburner } from "../../Bladeburner/Bladeburner";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
export function canAccessBladeburner(this: IPlayer): boolean {
|
||||
@ -7,7 +6,7 @@ export function canAccessBladeburner(this: IPlayer): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.bitNodeN === 6 || this.bitNodeN === 7 || SourceFileFlags[6] > 0 || SourceFileFlags[7] > 0;
|
||||
return this.bitNodeN === 6 || this.bitNodeN === 7 || this.sourceFileLvl(6) > 0 || this.sourceFileLvl(7) > 0;
|
||||
}
|
||||
|
||||
export function inBladeburner(this: IPlayer): boolean {
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { Corporation } from "../../Corporation/Corporation";
|
||||
import { CorporationUnlockUpgrades } from "../../Corporation/data/CorporationUnlockUpgrades";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import {
|
||||
CorporationUnlockUpgradeIndex,
|
||||
CorporationUnlockUpgrades,
|
||||
} from "../../Corporation/data/CorporationUnlockUpgrades";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
export function canAccessCorporation(this: IPlayer): boolean {
|
||||
return this.bitNodeN === 3 || SourceFileFlags[3] > 0;
|
||||
return this.bitNodeN === 3 || this.sourceFileLvl(3) > 0;
|
||||
}
|
||||
|
||||
export function hasCorporation(this: IPlayer): boolean {
|
||||
@ -19,9 +21,9 @@ export function startCorporation(this: IPlayer, corpName: string, additionalShar
|
||||
name: corpName,
|
||||
});
|
||||
|
||||
if (SourceFileFlags[3] === 3) {
|
||||
const warehouseApi = CorporationUnlockUpgrades["7"][0];
|
||||
const OfficeApi = CorporationUnlockUpgrades["8"][0];
|
||||
if (this.sourceFileLvl(3) === 3) {
|
||||
const warehouseApi = CorporationUnlockUpgrades[CorporationUnlockUpgradeIndex.WarehouseAPI].index;
|
||||
const OfficeApi = CorporationUnlockUpgrades[CorporationUnlockUpgradeIndex.OfficeAPI].index;
|
||||
|
||||
this.corporation.unlockUpgrades[warehouseApi] = 1;
|
||||
this.corporation.unlockUpgrades[OfficeApi] = 1;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Gang } from "../../Gang/Gang";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
// Amount of negative karma needed to manage a gang in BitNodes other than 2
|
||||
@ -11,7 +10,7 @@ export function canAccessGang(this: IPlayer): boolean {
|
||||
if (this.bitNodeN === 2) {
|
||||
return true;
|
||||
}
|
||||
if (SourceFileFlags[2] <= 0) {
|
||||
if (this.sourceFileLvl(2) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,6 @@ import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
import { applySourceFile } from "../../SourceFile/applySourceFile";
|
||||
import { applyExploit } from "../../Exploits/applyExploits";
|
||||
import { SourceFiles } from "../../SourceFile/SourceFiles";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { influenceStockThroughCompanyWork } from "../../StockMarket/PlayerInfluencing";
|
||||
import { getHospitalizationCost } from "../../Hospital/Hospital";
|
||||
import { WorkerScript } from "../../Netscript/WorkerScript";
|
||||
@ -121,7 +120,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
|
||||
|
||||
this.queuedAugmentations = [];
|
||||
|
||||
const numSleeves = Math.min(3, SourceFileFlags[10] + (this.bitNodeN === 10 ? 1 : 0)) + this.sleevesFromCovenant;
|
||||
const numSleeves = Math.min(3, this.sourceFileLvl(10) + (this.bitNodeN === 10 ? 1 : 0)) + this.sleevesFromCovenant;
|
||||
if (this.sleeves.length > numSleeves) this.sleeves.length = numSleeves;
|
||||
for (let i = this.sleeves.length; i < numSleeves; i++) {
|
||||
this.sleeves.push(new Sleeve(this));
|
||||
@ -475,7 +474,7 @@ export function gainIntelligenceExp(this: IPlayer, exp: number): void {
|
||||
console.error("ERROR: NaN passed into Player.gainIntelligenceExp()");
|
||||
return;
|
||||
}
|
||||
if (SourceFileFlags[5] > 0 || this.intelligence > 0) {
|
||||
if (this.sourceFileLvl(5) > 0 || this.intelligence > 0) {
|
||||
this.intelligence_exp += exp;
|
||||
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
|
||||
}
|
||||
@ -1045,7 +1044,7 @@ export function getWorkMoneyGain(this: IPlayer): number {
|
||||
// If player has SF-11, calculate salary multiplier from favor
|
||||
let bn11Mult = 1;
|
||||
const company = Companies[this.companyName];
|
||||
if (SourceFileFlags[11] > 0) {
|
||||
if (this.sourceFileLvl(11) > 0) {
|
||||
bn11Mult = 1 + company.favor / 100;
|
||||
}
|
||||
|
||||
@ -1323,20 +1322,21 @@ export function createProgramWork(this: IPlayer, numCycles: number): boolean {
|
||||
|
||||
export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): string {
|
||||
const programName = this.createProgramName;
|
||||
if (cancelled === false) {
|
||||
if (!cancelled) {
|
||||
//Complete case
|
||||
this.gainIntelligenceExp((CONSTANTS.IntelligenceProgramBaseExpGain * this.timeWorked) / 1000);
|
||||
dialogBoxCreate(`You've finished creating ${programName}!<br>The new program can be found on your home computer.`);
|
||||
|
||||
this.getHomeComputer().programs.push(programName);
|
||||
} else {
|
||||
if (!this.getHomeComputer().programs.includes(programName)) {
|
||||
this.getHomeComputer().programs.push(programName);
|
||||
}
|
||||
} else if (!this.getHomeComputer().programs.includes(programName)) {
|
||||
//Incomplete case
|
||||
const perc = (Math.floor((this.timeWorkedCreateProgram / this.timeNeededToCompleteWork) * 10000) / 100).toString();
|
||||
const incompleteName = programName + "-" + perc + "%-INC";
|
||||
this.getHomeComputer().programs.push(incompleteName);
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
this.gainIntelligenceExp((CONSTANTS.IntelligenceProgramBaseExpGain * this.timeWorked) / 1000);
|
||||
}
|
||||
|
||||
this.isWorking = false;
|
||||
|
||||
this.resetWorkStatus();
|
||||
@ -2092,12 +2092,7 @@ export function reapplyAllAugmentations(this: IPlayer, resetMultipliers = true):
|
||||
|
||||
const playerAug = this.augmentations[i];
|
||||
const augName = playerAug.name;
|
||||
const aug = Augmentations[augName];
|
||||
if (aug == null) {
|
||||
console.warn(`Invalid augmentation name in Player.reapplyAllAugmentations(). Aug ${augName} will be skipped`);
|
||||
continue;
|
||||
}
|
||||
aug.owned = true;
|
||||
|
||||
if (augName == AugmentationNames.NeuroFluxGovernor) {
|
||||
for (let j = 0; j < playerAug.level; ++j) {
|
||||
applyAugmentation(this.augmentations[i], true);
|
||||
@ -2718,7 +2713,7 @@ export function gotoLocation(this: IPlayer, to: LocationName): boolean {
|
||||
}
|
||||
|
||||
export function canAccessGrafting(this: IPlayer): boolean {
|
||||
return this.bitNodeN === 10 || SourceFileFlags[10] > 0;
|
||||
return this.bitNodeN === 10 || this.sourceFileLvl(10) > 0;
|
||||
}
|
||||
|
||||
export function giveExploit(this: IPlayer, exploit: Exploit): void {
|
||||
@ -2756,7 +2751,7 @@ export function setMult(this: IPlayer, name: string, mult: number): void {
|
||||
}
|
||||
|
||||
export function canAccessCotMG(this: IPlayer): boolean {
|
||||
return this.bitNodeN === 13 || SourceFileFlags[13] > 0;
|
||||
return this.bitNodeN === 13 || this.sourceFileLvl(13) > 0;
|
||||
}
|
||||
|
||||
export function sourceFileLvl(this: IPlayer, n: number): number {
|
||||
|
@ -12,7 +12,6 @@ import { Faction } from "./Faction/Faction";
|
||||
import { Factions, initFactions } from "./Faction/Factions";
|
||||
import { joinFaction } from "./Faction/FactionHelpers";
|
||||
import { updateHashManagerCapacity } from "./Hacknet/HacknetHelpers";
|
||||
import { initMessages } from "./Message/MessageHelpers";
|
||||
import { prestigeWorkerScripts } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
@ -21,7 +20,6 @@ import { LiteratureNames } from "./Literature/data/LiteratureNames";
|
||||
|
||||
import { GetServer, AddToAllServers, initForeignServers, prestigeAllServers } from "./Server/AllServers";
|
||||
import { prestigeHomeComputer } from "./Server/ServerHelpers";
|
||||
import { SourceFileFlags, updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { SpecialServers } from "./Server/data/SpecialServers";
|
||||
import { deleteStockMarket, initStockMarket, initSymbolToStockMap } from "./StockMarket/StockMarket";
|
||||
import { Terminal } from "./Terminal";
|
||||
@ -56,15 +54,15 @@ export function prestigeAugmentation(): void {
|
||||
AddToAllServers(homeComp);
|
||||
prestigeHomeComputer(Player, homeComp);
|
||||
|
||||
if (augmentationExists(AugmentationNames.Neurolink) && Augmentations[AugmentationNames.Neurolink].owned) {
|
||||
if (augmentationExists(AugmentationNames.Neurolink) && Player.hasAugmentation(AugmentationNames.Neurolink)) {
|
||||
homeComp.programs.push(Programs.FTPCrackProgram.name);
|
||||
homeComp.programs.push(Programs.RelaySMTPProgram.name);
|
||||
}
|
||||
if (augmentationExists(AugmentationNames.CashRoot) && Augmentations[AugmentationNames.CashRoot].owned) {
|
||||
if (augmentationExists(AugmentationNames.CashRoot) && Player.hasAugmentation(AugmentationNames.CashRoot)) {
|
||||
Player.setMoney(1e6);
|
||||
homeComp.programs.push(Programs.BruteSSHProgram.name);
|
||||
}
|
||||
if (augmentationExists(AugmentationNames.PCMatrix) && Augmentations[AugmentationNames.PCMatrix].owned) {
|
||||
if (augmentationExists(AugmentationNames.PCMatrix) && Player.hasAugmentation(AugmentationNames.PCMatrix)) {
|
||||
homeComp.programs.push(Programs.DeepscanV1.name);
|
||||
homeComp.programs.push(Programs.AutoLink.name);
|
||||
}
|
||||
@ -105,9 +103,6 @@ export function prestigeAugmentation(): void {
|
||||
Player.reapplyAllSourceFiles();
|
||||
initCompanies();
|
||||
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
// Apply entropy from grafting
|
||||
Player.applyEntropy(Player.entropy);
|
||||
|
||||
@ -143,7 +138,7 @@ export function prestigeAugmentation(): void {
|
||||
if (Player.bitNodeN === 8) {
|
||||
Player.money = BitNode8StartingMoney;
|
||||
}
|
||||
if (Player.bitNodeN === 8 || SourceFileFlags[8] > 0) {
|
||||
if (Player.bitNodeN === 8 || Player.sourceFileLvl(8) > 0) {
|
||||
Player.hasWseAccount = true;
|
||||
Player.hasTixApiAccess = true;
|
||||
}
|
||||
@ -155,7 +150,7 @@ export function prestigeAugmentation(): void {
|
||||
}
|
||||
|
||||
// Red Pill
|
||||
if (augmentationExists(AugmentationNames.TheRedPill) && Augmentations[AugmentationNames.TheRedPill].owned) {
|
||||
if (augmentationExists(AugmentationNames.TheRedPill) && Player.hasAugmentation(AugmentationNames.TheRedPill)) {
|
||||
const WorldDaemon = GetServer(SpecialServers.WorldDaemon);
|
||||
const DaedalusServer = GetServer(SpecialServers.DaedalusServer);
|
||||
if (WorldDaemon && DaedalusServer) {
|
||||
@ -164,7 +159,7 @@ export function prestigeAugmentation(): void {
|
||||
}
|
||||
}
|
||||
|
||||
if (augmentationExists(AugmentationNames.StaneksGift1) && Augmentations[AugmentationNames.StaneksGift1].owned) {
|
||||
if (augmentationExists(AugmentationNames.StaneksGift1) && Player.hasAugmentation(AugmentationNames.StaneksGift1)) {
|
||||
joinFaction(Factions[FactionNames.ChurchOfTheMachineGod]);
|
||||
}
|
||||
|
||||
@ -178,7 +173,6 @@ export function prestigeAugmentation(): void {
|
||||
// Prestige by destroying Bit Node and gaining a Source File
|
||||
export function prestigeSourceFile(flume: boolean): void {
|
||||
initBitNodeMultipliers(Player);
|
||||
updateSourceFileFlags(Player);
|
||||
|
||||
Player.prestigeSourceFile();
|
||||
prestigeWorkerScripts(); // Delete all Worker Scripts objects
|
||||
@ -202,9 +196,9 @@ export function prestigeSourceFile(flume: boolean): void {
|
||||
// Re-create foreign servers
|
||||
initForeignServers(Player.getHomeComputer());
|
||||
|
||||
if (SourceFileFlags[9] >= 2) {
|
||||
if (Player.sourceFileLvl(9) >= 2) {
|
||||
homeComp.setMaxRam(128);
|
||||
} else if (SourceFileFlags[1] > 0) {
|
||||
} else if (Player.sourceFileLvl(1) > 0) {
|
||||
homeComp.setMaxRam(32);
|
||||
} else {
|
||||
homeComp.setMaxRam(8);
|
||||
@ -238,10 +232,10 @@ export function prestigeSourceFile(flume: boolean): void {
|
||||
}
|
||||
|
||||
// Give levels of NeuroFluxGoverner for Source-File 12. Must be done here before Augmentations are recalculated
|
||||
if (SourceFileFlags[12] > 0) {
|
||||
if (Player.sourceFileLvl(12) > 0) {
|
||||
Player.augmentations.push({
|
||||
name: AugmentationNames.NeuroFluxGovernor,
|
||||
level: SourceFileFlags[12],
|
||||
level: Player.sourceFileLvl(12),
|
||||
});
|
||||
}
|
||||
|
||||
@ -251,9 +245,6 @@ export function prestigeSourceFile(flume: boolean): void {
|
||||
Player.reapplyAllSourceFiles();
|
||||
initCompanies();
|
||||
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
if (Player.sourceFileLvl(5) > 0 || Player.bitNodeN === 5) {
|
||||
homeComp.programs.push(Programs.Formulas.name);
|
||||
}
|
||||
@ -271,7 +262,7 @@ export function prestigeSourceFile(flume: boolean): void {
|
||||
if (Player.bitNodeN === 8) {
|
||||
Player.money = BitNode8StartingMoney;
|
||||
}
|
||||
if (Player.bitNodeN === 8 || SourceFileFlags[8] > 0) {
|
||||
if (Player.bitNodeN === 8 || Player.sourceFileLvl(8) > 0) {
|
||||
Player.hasWseAccount = true;
|
||||
Player.hasTixApiAccess = true;
|
||||
}
|
||||
@ -299,7 +290,7 @@ export function prestigeSourceFile(flume: boolean): void {
|
||||
Player.bladeburner = null;
|
||||
|
||||
// Source-File 9 (level 3) effect
|
||||
if (SourceFileFlags[9] >= 3) {
|
||||
if (Player.sourceFileLvl(9) >= 3) {
|
||||
const hserver = Player.createHacknetServer();
|
||||
|
||||
hserver.level = 100;
|
||||
@ -316,7 +307,7 @@ export function prestigeSourceFile(flume: boolean): void {
|
||||
staneksGift.prestigeSourceFile();
|
||||
|
||||
// Gain int exp
|
||||
if (SourceFileFlags[5] !== 0 && !flume) Player.gainIntelligenceExp(300);
|
||||
if (Player.sourceFileLvl(5) !== 0 && !flume) Player.gainIntelligenceExp(300);
|
||||
|
||||
resetPidCounter();
|
||||
}
|
||||
|
@ -24,9 +24,4 @@ export class Program {
|
||||
this.create = create;
|
||||
this.run = run;
|
||||
}
|
||||
|
||||
htmlID(): string {
|
||||
const name = this.name.endsWith(".exe") ? this.name.slice(0, -".exe".length) : this.name;
|
||||
return "create-program-" + name;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import React from "react";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeSourceFile } from "./Prestige";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { SourceFiles } from "./SourceFile/SourceFiles";
|
||||
|
||||
import { dialogBoxCreate } from "./ui/React/DialogBox";
|
||||
@ -69,7 +68,7 @@ function giveSourceFile(bitNodeNumber: number): void {
|
||||
export function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number): void {
|
||||
if (!flume) {
|
||||
giveSourceFile(destroyedBitNode);
|
||||
} else if (SourceFileFlags[5] === 0 && newBitNode !== 5) {
|
||||
} else if (Player.sourceFileLvl(5) === 0 && newBitNode !== 5) {
|
||||
Player.intelligence = 0;
|
||||
Player.intelligence_exp = 0;
|
||||
}
|
||||
|
@ -3,11 +3,9 @@ import { Companies, loadCompanies } from "./Company/Companies";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Factions, loadFactions } from "./Faction/Factions";
|
||||
import { loadAllGangs, AllGangs } from "./Gang/AllGangs";
|
||||
import { loadMessages, initMessages, Messages } from "./Message/MessageHelpers";
|
||||
import { Player, loadPlayer } from "./Player";
|
||||
import { saveAllServers, loadAllServers, GetAllServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
|
||||
import { staneksGift, loadStaneksGift } from "./CotMG/Helper";
|
||||
|
||||
@ -67,7 +65,6 @@ class BitburnerSaveObject {
|
||||
FactionsSave = "";
|
||||
AliasesSave = "";
|
||||
GlobalAliasesSave = "";
|
||||
MessagesSave = "";
|
||||
StockMarketSave = "";
|
||||
SettingsSave = "";
|
||||
VersionSave = "";
|
||||
@ -83,7 +80,6 @@ class BitburnerSaveObject {
|
||||
this.FactionsSave = JSON.stringify(Factions);
|
||||
this.AliasesSave = JSON.stringify(Aliases);
|
||||
this.GlobalAliasesSave = JSON.stringify(GlobalAliases);
|
||||
this.MessagesSave = JSON.stringify(Messages);
|
||||
this.StockMarketSave = JSON.stringify(StockMarket);
|
||||
this.SettingsSave = JSON.stringify(Settings);
|
||||
this.VersionSave = JSON.stringify(CONSTANTS.VersionNumber);
|
||||
@ -129,7 +125,7 @@ class BitburnerSaveObject {
|
||||
// Save file name is based on current timestamp and BitNode
|
||||
const epochTime = Math.round(Date.now() / 1000);
|
||||
const bn = Player.bitNodeN;
|
||||
let filename = `bitburnerSave_${epochTime}_BN${bn}x${SourceFileFlags[bn]}.json`;
|
||||
let filename = `bitburnerSave_${epochTime}_BN${bn}x${Player.sourceFileLvl(bn) + 1}.json`;
|
||||
if (isRecovery) filename = "RECOVERY" + filename;
|
||||
return filename;
|
||||
}
|
||||
@ -398,6 +394,9 @@ function evaluateVersionCompatibility(ver: string | number): void {
|
||||
delete anyPlayer.resleeves;
|
||||
}
|
||||
}
|
||||
if (ver < 14) {
|
||||
delete (Settings as any).EditorTheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,17 +440,6 @@ function loadGame(saveString: string): boolean {
|
||||
console.warn(`Save file did not contain a GlobalAliases property`);
|
||||
loadGlobalAliases("");
|
||||
}
|
||||
if (saveObj.hasOwnProperty("MessagesSave")) {
|
||||
try {
|
||||
loadMessages(saveObj.MessagesSave);
|
||||
} catch (e) {
|
||||
console.warn(`Could not load Messages from save`);
|
||||
initMessages();
|
||||
}
|
||||
} else {
|
||||
console.warn(`Save file did not contain a Messages property`);
|
||||
initMessages();
|
||||
}
|
||||
if (saveObj.hasOwnProperty("StockMarketSave")) {
|
||||
try {
|
||||
loadStockMarket(saveObj.StockMarketSave);
|
||||
|
79
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
79
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -2386,6 +2386,30 @@ export interface Singularity {
|
||||
* purchased. Throws an error if the specified program/exploit does not exist
|
||||
*/
|
||||
getDarkwebProgramCost(programName: string): number;
|
||||
|
||||
/**
|
||||
* b1t_flum3 into a different BN.
|
||||
* @remarks
|
||||
* RAM cost: 16 GB * 16/4/1
|
||||
*
|
||||
* @param nextBN - BN number to jump to
|
||||
* @param callbackScript - Name of the script to launch in the next BN.
|
||||
*/
|
||||
b1tflum3(nextBN: number, callbackScript?: string): void;
|
||||
|
||||
/**
|
||||
* Destroy the w0r1d_d43m0n and move on to the next BN.
|
||||
* @remarks
|
||||
* RAM cost: 32 GB * 16/4/1
|
||||
*
|
||||
* You must have the special augment installed and the required hacking level
|
||||
* OR
|
||||
* Completed the final black op.
|
||||
*
|
||||
* @param nextBN - BN number to jump to
|
||||
* @param callbackScript - Name of the script to launch in the next BN.
|
||||
*/
|
||||
destroyW0r1dD43m0n(nextBN: number, callbackScript?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3234,7 +3258,7 @@ export interface CodingContract {
|
||||
* Attempts to solve the Coding Contract with the provided solution.
|
||||
*
|
||||
* @param answer - Solution for the contract.
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @param opts - Optional parameters for configuring function behavior.
|
||||
* @returns True if the solution was correct, false otherwise. If the returnReward option is configured, then the function will instead return a string. If the contract is successfully solved, the string will contain a description of the contract’s reward. Otherwise, it will be an empty string.
|
||||
@ -3249,7 +3273,7 @@ export interface CodingContract {
|
||||
* Returns a name describing the type of problem posed by the Coding Contract.
|
||||
* (e.g. Find Largest Prime Factor, Total Ways to Sum, etc.)
|
||||
*
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @returns Name describing the type of problem posed by the Coding Contract.
|
||||
*/
|
||||
@ -3262,7 +3286,7 @@ export interface CodingContract {
|
||||
*
|
||||
* Get the full text description for the problem posed by the Coding Contract.
|
||||
*
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @returns Contract’s text description.
|
||||
*/
|
||||
@ -3290,7 +3314,7 @@ export interface CodingContract {
|
||||
*
|
||||
* Get the number of tries remaining on the contract before it self-destructs.
|
||||
*
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @returns How many attempts are remaining for the contract;
|
||||
*/
|
||||
@ -3784,6 +3808,18 @@ export interface Grafting {
|
||||
*/
|
||||
getAugmentationGraftTime(augName: string): number;
|
||||
|
||||
/**
|
||||
* Retrieves a list of Augmentations that can be grafted.
|
||||
* @remarks
|
||||
* RAM cost: 5 GB
|
||||
*
|
||||
* Note that this function returns a list of currently graftable Augmentations,
|
||||
* based off of the Augmentations that you already own.
|
||||
*
|
||||
* @returns An array of graftable Augmentations.
|
||||
*/
|
||||
getGraftableAugmentations(): string[];
|
||||
|
||||
/**
|
||||
* Begins grafting the named aug. You must be in New Tokyo to use this.
|
||||
* @remarks
|
||||
@ -4693,9 +4729,11 @@ export interface NS {
|
||||
* Returns the security increase that would occur if a grow with this many threads happened.
|
||||
*
|
||||
* @param threads - Amount of threads that will be used.
|
||||
* @param hostname - Optional. Hostname of the target server. The number of threads is limited to the number needed to hack the servers maximum amount of money.
|
||||
* @param cores - Optional. The number of cores of the server that would run grow.
|
||||
* @returns The security increase.
|
||||
*/
|
||||
growthAnalyzeSecurity(threads: number): number;
|
||||
growthAnalyzeSecurity(threads: number, hostname?: string, cores?: number): number;
|
||||
|
||||
/**
|
||||
* Suspends the script for n milliseconds.
|
||||
@ -5129,8 +5167,7 @@ export interface NS {
|
||||
* PID stands for Process ID. The PID is a unique identifier for each script.
|
||||
* The PID will always be a positive integer.
|
||||
*
|
||||
* Running this function with a numThreads argument of 0 will return 0 without running the script.
|
||||
* However, running this function with a negative numThreads argument will cause a runtime error.
|
||||
* Running this function with 0 or a negative numThreads argument will cause a runtime error.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
@ -6781,8 +6818,9 @@ export interface WarehouseAPI {
|
||||
* Upgrade warehouse
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param amt - amount of upgrades defaults to 1
|
||||
*/
|
||||
upgradeWarehouse(divisionName: string, cityName: string): void;
|
||||
upgradeWarehouse(divisionName: string, cityName: string, amt?: number): void;
|
||||
/**
|
||||
* Create a new product
|
||||
* @param divisionName - Name of the division
|
||||
@ -6798,6 +6836,22 @@ export interface WarehouseAPI {
|
||||
designInvest: number,
|
||||
marketingInvest: number,
|
||||
): void;
|
||||
/**
|
||||
* Limit Material Production.
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param materialName - Name of the material
|
||||
* @param qty - Amount to limit to
|
||||
*/
|
||||
limitMaterialProduction(divisionName: string, cityName: string, materialName: string, qty: number): void;
|
||||
/**
|
||||
* Limit Product Production.
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param productName - Name of the product
|
||||
* @param qty - Amount to limit to
|
||||
*/
|
||||
limitProductProduction(divisionName: string, cityName: string, productName: string, qty: number): void;
|
||||
/**
|
||||
* Gets the cost to purchase a warehouse
|
||||
* @returns cost
|
||||
@ -6805,9 +6859,12 @@ export interface WarehouseAPI {
|
||||
getPurchaseWarehouseCost(): number;
|
||||
/**
|
||||
* Gets the cost to upgrade a warehouse to the next level
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param amt - amount of upgrades defaults to 1
|
||||
* @returns cost to upgrade
|
||||
*/
|
||||
getUpgradeWarehouseCost(adivisionName: any, acityName: any): number;
|
||||
getUpgradeWarehouseCost(adivisionName: any, acityName: any, amt?: number): number;
|
||||
/**
|
||||
* Check if you have a warehouse in city
|
||||
* @returns true if warehouse is present, false if not
|
||||
@ -7051,8 +7108,10 @@ interface Material {
|
||||
cmp: number | undefined;
|
||||
/** Amount of material produced */
|
||||
prod: number;
|
||||
/** Amount of material sold */
|
||||
/** Amount of material sold */
|
||||
sell: number;
|
||||
/** cost to buy material */
|
||||
cost: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,10 @@ import Select from "@mui/material/Select";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import SaveIcon from "@mui/icons-material/Save";
|
||||
|
||||
import { ThemeEditorModal } from "./ThemeEditorModal";
|
||||
|
||||
interface IProps {
|
||||
options: Options;
|
||||
@ -23,6 +27,7 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
const [fontSize, setFontSize] = useState(props.options.fontSize);
|
||||
const [wordWrap, setWordWrap] = useState(props.options.wordWrap);
|
||||
const [vim, setVim] = useState(props.options.vim);
|
||||
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
||||
|
||||
function save(): void {
|
||||
props.save({
|
||||
@ -43,6 +48,7 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<ThemeEditorModal open={themeEditorOpen} onClose={() => setThemeEditorOpen(false)} />
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
<Typography>Theme: </Typography>
|
||||
<Select onChange={(event) => setTheme(event.target.value)} value={theme}>
|
||||
@ -53,7 +59,11 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
<MenuItem value="light">light</MenuItem>
|
||||
<MenuItem value="dracula">dracula</MenuItem>
|
||||
<MenuItem value="one-dark">one-dark</MenuItem>
|
||||
<MenuItem value="customTheme">Custom theme</MenuItem>
|
||||
</Select>
|
||||
<Button onClick={() => setThemeEditorOpen(true)} sx={{ mx: 1 }} startIcon={<EditIcon />}>
|
||||
Edit custom theme
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
@ -80,7 +90,9 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
<TextField type="number" label="Font size" value={fontSize} onChange={onFontChange} />
|
||||
</Box>
|
||||
<br />
|
||||
<Button onClick={save}>Save</Button>
|
||||
<Button onClick={save} startIcon={<SaveIcon />}>
|
||||
Save
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import { Settings } from "../../Settings/Settings";
|
||||
import { iTutorialNextStep, ITutorial, iTutorialSteps } from "../../InteractiveTutorial";
|
||||
import { debounce } from "lodash";
|
||||
import { saveObject } from "../../SaveObject";
|
||||
import { loadThemes } from "./themes";
|
||||
import { loadThemes, makeTheme, sanitizeTheme } from "./themes";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
@ -362,6 +362,8 @@ export function Root(props: IProps): React.ReactElement {
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(source, "netscript.d.ts");
|
||||
monaco.languages.typescript.typescriptDefaults.addExtraLib(source, "netscript.d.ts");
|
||||
loadThemes(monaco);
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monaco.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
}
|
||||
|
||||
// When the editor is mounted
|
||||
@ -993,7 +995,11 @@ export function Root(props: IProps): React.ReactElement {
|
||||
</Box>
|
||||
<OptionsModal
|
||||
open={optionsOpen}
|
||||
onClose={() => setOptionsOpen(false)}
|
||||
onClose={() => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monacoRef.current?.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
setOptionsOpen(false);
|
||||
}}
|
||||
options={{
|
||||
theme: Settings.MonacoTheme,
|
||||
insertSpaces: Settings.MonacoInsertSpaces,
|
||||
@ -1002,6 +1008,8 @@ export function Root(props: IProps): React.ReactElement {
|
||||
vim: Settings.MonacoVim,
|
||||
}}
|
||||
save={(options: Options) => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monacoRef.current?.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
setOptions(options);
|
||||
Settings.MonacoTheme = options.theme;
|
||||
Settings.MonacoInsertSpaces = options.insertSpaces;
|
||||
|
276
src/ScriptEditor/ui/ThemeEditorModal.tsx
Normal file
276
src/ScriptEditor/ui/ThemeEditorModal.tsx
Normal file
@ -0,0 +1,276 @@
|
||||
import { History, Reply, Save } from "@mui/icons-material";
|
||||
import { Box, Button, Paper, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import _ from "lodash";
|
||||
import { Color, ColorPicker } from "material-ui-color";
|
||||
import React, { useState } from "react";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { OptionSwitch } from "../../ui/React/OptionSwitch";
|
||||
import { defaultMonacoTheme, IScriptEditorTheme } from "./themes";
|
||||
|
||||
interface IProps {
|
||||
onClose: () => void;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
interface IColorEditorProps {
|
||||
label: string;
|
||||
themePath: string;
|
||||
color: string | undefined;
|
||||
onColorChange: (name: string, value: string) => void;
|
||||
defaultColor: string;
|
||||
}
|
||||
|
||||
// Slightly tweaked version of the same function found in game options
|
||||
function ColorEditor({ label, themePath, onColorChange, color, defaultColor }: IColorEditorProps): React.ReactElement {
|
||||
if (color === undefined) {
|
||||
console.error(`color ${themePath} was undefined, reverting to default`);
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={label}>
|
||||
<span>
|
||||
<TextField
|
||||
label={themePath}
|
||||
value={"#" + color}
|
||||
sx={{ display: "block", my: 1 }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<>
|
||||
<ColorPicker
|
||||
hideTextfield
|
||||
deferred
|
||||
value={"#" + color}
|
||||
onChange={(newColor: Color) => onColorChange(themePath, newColor.hex)}
|
||||
disableAlpha
|
||||
/>
|
||||
</>
|
||||
),
|
||||
endAdornment: (
|
||||
<>
|
||||
<IconButton onClick={() => onColorChange(themePath, defaultColor)}>
|
||||
<Reply color="primary" />
|
||||
</IconButton>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((o) => !o);
|
||||
}
|
||||
|
||||
// Need to deep copy the object since it has nested attributes
|
||||
const [themeCopy, setThemeCopy] = useState<IScriptEditorTheme>(JSON.parse(JSON.stringify(Settings.EditorTheme)));
|
||||
|
||||
function onColorChange(name: string, value: string): void {
|
||||
setThemeCopy(_.set(themeCopy, name, value));
|
||||
rerender();
|
||||
}
|
||||
|
||||
function onThemeChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
try {
|
||||
const importedTheme = JSON.parse(event.target.value);
|
||||
if (typeof importedTheme !== "object") return;
|
||||
setThemeCopy(importedTheme);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={props.open}
|
||||
onClose={() => {
|
||||
setThemeCopy(Settings.EditorTheme);
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
<Typography variant="h4">Customize Editor theme</Typography>
|
||||
<Typography>Hover over input boxes for more information</Typography>
|
||||
<Paper sx={{ p: 1, my: 1 }}>
|
||||
<OptionSwitch
|
||||
checked={themeCopy.base === "vs"}
|
||||
onChange={(val) => {
|
||||
setThemeCopy(_.set(themeCopy, "base", val ? "vs" : "vs-dark"));
|
||||
rerender();
|
||||
}}
|
||||
text="Use light theme as base"
|
||||
tooltip={
|
||||
<>
|
||||
If enabled, the <code>vs</code> light theme will be used as the theme base, otherwise,{" "}
|
||||
<code>vs-dark</code> will be used.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "fit-content", gap: 1 }}>
|
||||
<Box>
|
||||
<Typography variant="h6">UI</Typography>
|
||||
<ColorEditor
|
||||
label="Background color"
|
||||
themePath="common.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.bg}
|
||||
defaultColor={defaultMonacoTheme.common.bg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Current line and minimap background color"
|
||||
themePath="ui.line"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.line}
|
||||
defaultColor={defaultMonacoTheme.ui.line}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Base text color"
|
||||
themePath="common.fg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.fg}
|
||||
defaultColor={defaultMonacoTheme.common.fg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Popup background color"
|
||||
themePath="ui.panel.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.bg}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.bg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Background color for selected item in popup"
|
||||
themePath="ui.panel.selected"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.selected}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.selected}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Popup border color"
|
||||
themePath="ui.panel.border"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.border}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.border}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Background color of highlighted text"
|
||||
themePath="ui.selection.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.selection.bg}
|
||||
defaultColor={defaultMonacoTheme.ui.selection.bg}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography variant="h6">Syntax</Typography>
|
||||
<ColorEditor
|
||||
label="Numbers, function names, and other key vars"
|
||||
themePath="common.accent"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.accent}
|
||||
defaultColor={defaultMonacoTheme.common.accent}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Keywords"
|
||||
themePath="syntax.keyword"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.keyword}
|
||||
defaultColor={defaultMonacoTheme.syntax.keyword}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Strings"
|
||||
themePath="syntax.string"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.string}
|
||||
defaultColor={defaultMonacoTheme.syntax.string}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Regexp literals as well as escapes within strings"
|
||||
themePath="syntax.regexp"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.regexp}
|
||||
defaultColor={defaultMonacoTheme.syntax.regexp}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Constants"
|
||||
themePath="syntax.constant"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.constant}
|
||||
defaultColor={defaultMonacoTheme.syntax.constant}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Entities"
|
||||
themePath="syntax.entity"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.entity}
|
||||
defaultColor={defaultMonacoTheme.syntax.entity}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="'this', 'ns', types, and tags"
|
||||
themePath="syntax.tag"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.tag}
|
||||
defaultColor={defaultMonacoTheme.syntax.tag}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Netscript functions and constructors"
|
||||
themePath="syntax.markup"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.markup}
|
||||
defaultColor={defaultMonacoTheme.syntax.markup}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Errors"
|
||||
themePath="syntax.error"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.error}
|
||||
defaultColor={defaultMonacoTheme.syntax.error}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Comments"
|
||||
themePath="syntax.comment"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.comment}
|
||||
defaultColor={defaultMonacoTheme.syntax.comment}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<TextField
|
||||
multiline
|
||||
fullWidth
|
||||
maxRows={10}
|
||||
label={"import / export theme"}
|
||||
value={JSON.stringify(themeCopy, undefined, 2)}
|
||||
onChange={onThemeChange}
|
||||
/>
|
||||
<Box sx={{ mt: 1 }}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
Settings.EditorTheme = { ...themeCopy };
|
||||
props.onClose();
|
||||
}}
|
||||
startIcon={<Save />}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setThemeCopy(defaultMonacoTheme);
|
||||
rerender();
|
||||
}}
|
||||
startIcon={<History />}
|
||||
>
|
||||
Reset to default
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,3 +1,216 @@
|
||||
export interface IScriptEditorTheme {
|
||||
[key: string]: any;
|
||||
base: string;
|
||||
inherit: boolean;
|
||||
common: {
|
||||
[key: string]: string;
|
||||
accent: string;
|
||||
bg: string;
|
||||
fg: string;
|
||||
};
|
||||
syntax: {
|
||||
[key: string]: string;
|
||||
tag: string;
|
||||
entity: string;
|
||||
string: string;
|
||||
regexp: string;
|
||||
markup: string;
|
||||
keyword: string;
|
||||
comment: string;
|
||||
constant: string;
|
||||
error: string;
|
||||
};
|
||||
ui: {
|
||||
[key: string]: any;
|
||||
line: string;
|
||||
panel: {
|
||||
[key: string]: string;
|
||||
bg: string;
|
||||
selected: string;
|
||||
border: string;
|
||||
};
|
||||
selection: {
|
||||
[key: string]: string;
|
||||
bg: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const defaultMonacoTheme: IScriptEditorTheme = {
|
||||
base: "vs-dark",
|
||||
inherit: true,
|
||||
common: {
|
||||
accent: "B5CEA8",
|
||||
bg: "1E1E1E",
|
||||
fg: "D4D4D4",
|
||||
},
|
||||
syntax: {
|
||||
tag: "569CD6",
|
||||
entity: "569CD6",
|
||||
string: "CE9178",
|
||||
regexp: "646695",
|
||||
markup: "569CD6",
|
||||
keyword: "569CD6",
|
||||
comment: "6A9955",
|
||||
constant: "569CD6",
|
||||
error: "F44747",
|
||||
},
|
||||
ui: {
|
||||
line: "1E1E1E",
|
||||
panel: {
|
||||
bg: "252526",
|
||||
selected: "252526",
|
||||
border: "1E1E1E",
|
||||
},
|
||||
selection: {
|
||||
bg: "ADD6FF26",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Regex used for token color validation
|
||||
// https://github.com/microsoft/vscode/blob/973684056e67153952f495fce93bf50d0ec0b892/src/vs/editor/common/languages/supports/tokenization.ts#L153
|
||||
const colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;
|
||||
|
||||
// Recursively sanitize the theme data to prevent errors
|
||||
// Invalid data will be replaced with FF0000 (bright red)
|
||||
export const sanitizeTheme = (theme: IScriptEditorTheme): void => {
|
||||
for (const [k, v] of Object.entries(theme)) {
|
||||
switch (k) {
|
||||
case "base":
|
||||
if (!["vs-dark", "vs"].includes(theme.base)) theme.base = "vs-dark";
|
||||
continue;
|
||||
case "inherit":
|
||||
if (typeof theme.inherit !== "boolean") theme.inherit = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const repairBlock = (block: { [key: string]: any }): void => {
|
||||
for (const [k, v] of Object.entries(block)) {
|
||||
if (typeof v === "object") {
|
||||
repairBlock(v as { [key: string]: string });
|
||||
} else if (!v.match(colorRegExp)) block[k] = "FF0000";
|
||||
}
|
||||
};
|
||||
repairBlock(v);
|
||||
}
|
||||
};
|
||||
|
||||
export function makeTheme(theme: IScriptEditorTheme): any {
|
||||
const themeRules = [
|
||||
{
|
||||
token: "",
|
||||
background: theme.ui.line,
|
||||
foreground: theme.common.fg,
|
||||
},
|
||||
{
|
||||
token: "identifier",
|
||||
foreground: theme.common.accent,
|
||||
},
|
||||
{
|
||||
token: "keyword",
|
||||
foreground: theme.syntax.keyword,
|
||||
},
|
||||
{
|
||||
token: "string",
|
||||
foreground: theme.syntax.string,
|
||||
},
|
||||
{
|
||||
token: "string.escape",
|
||||
foreground: theme.syntax.regexp,
|
||||
},
|
||||
{
|
||||
token: "comment",
|
||||
foreground: theme.syntax.comment,
|
||||
},
|
||||
{
|
||||
token: "constant",
|
||||
foreground: theme.syntax.constant,
|
||||
},
|
||||
{
|
||||
token: "entity",
|
||||
foreground: theme.syntax.entity,
|
||||
},
|
||||
{
|
||||
token: "type",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "tag",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "regexp",
|
||||
foreground: theme.syntax.regexp,
|
||||
},
|
||||
{
|
||||
token: "attribute",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "constructor",
|
||||
foreground: theme.syntax.markup,
|
||||
},
|
||||
{
|
||||
token: "invalid",
|
||||
foreground: theme.syntax.error,
|
||||
},
|
||||
{
|
||||
token: "number",
|
||||
foreground: theme.common.accent,
|
||||
},
|
||||
{
|
||||
token: "delimiter",
|
||||
foreground: theme.common.fg,
|
||||
},
|
||||
// Custom tokens
|
||||
{
|
||||
token: "ns",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "netscriptfunction",
|
||||
foreground: theme.syntax.markup,
|
||||
},
|
||||
{
|
||||
token: "otherkeywords",
|
||||
foreground: theme.syntax.keyword,
|
||||
},
|
||||
{
|
||||
token: "otherkeyvars",
|
||||
foreground: theme.common.accent,
|
||||
},
|
||||
{
|
||||
token: "this",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
];
|
||||
|
||||
const themeColors = Object.fromEntries(
|
||||
[
|
||||
["editor.background", theme.common.bg],
|
||||
["editor.foreground", theme.common.fg],
|
||||
["editor.lineHighlightBackground", theme.ui.line],
|
||||
["editor.selectionBackground", theme.ui.selection.bg],
|
||||
|
||||
["editorSuggestWidget.background", theme.ui.panel.bg],
|
||||
["editorSuggestWidget.border", theme.ui.panel.border],
|
||||
["editorSuggestWidget.selectedBackground", theme.ui.panel.selected],
|
||||
|
||||
["editorHoverWidget.background", theme.ui.panel.bg],
|
||||
["editorHoverWidget.border", theme.ui.panel.border],
|
||||
|
||||
["editorWidget.background", theme.ui.panel.bg],
|
||||
["editorWidget.border", theme.ui.panel.border],
|
||||
|
||||
["input.background", theme.ui.panel.bg],
|
||||
["input.border", theme.ui.panel.border],
|
||||
].map(([k, v]) => [k, "#" + v]),
|
||||
);
|
||||
|
||||
return { base: theme.base, inherit: theme.inherit, rules: themeRules, colors: themeColors };
|
||||
}
|
||||
|
||||
export async function loadThemes(monaco: { editor: any }): Promise<void> {
|
||||
monaco.editor.defineTheme("monokai", {
|
||||
base: "vs-dark",
|
||||
@ -261,6 +474,7 @@ export async function loadThemes(monaco: { editor: any }): Promise<void> {
|
||||
foreground: "FFB86C",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
|
||||
{
|
||||
token: "netscriptfunction",
|
||||
foreground: "FF79C6",
|
||||
|
@ -5,6 +5,7 @@ import { defaultStyles } from "../Themes/Styles";
|
||||
import { WordWrapOptions } from "../ScriptEditor/ui/Options";
|
||||
import { OverviewSettings } from "../ui/React/Overview";
|
||||
import { IStyleSettings } from "../ScriptEditor/NetscriptDefinitions";
|
||||
import { defaultMonacoTheme, IScriptEditorTheme } from "../ScriptEditor/ui/themes";
|
||||
|
||||
/**
|
||||
* Represents the default settings the player could customize.
|
||||
@ -157,6 +158,11 @@ interface IDefaultSettings {
|
||||
* If the game's sidebar is opened
|
||||
*/
|
||||
IsSidebarOpened: boolean;
|
||||
|
||||
/**
|
||||
* Script editor theme data
|
||||
*/
|
||||
EditorTheme: IScriptEditorTheme;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,6 +222,8 @@ export const defaultSettings: IDefaultSettings = {
|
||||
theme: defaultTheme,
|
||||
styles: defaultStyles,
|
||||
overview: { x: 0, y: 0, opened: true },
|
||||
|
||||
EditorTheme: defaultMonacoTheme,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -262,6 +270,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
theme: { ...defaultTheme },
|
||||
styles: { ...defaultStyles },
|
||||
overview: defaultSettings.overview,
|
||||
EditorTheme: { ...defaultMonacoTheme },
|
||||
init() {
|
||||
Object.assign(Settings, defaultSettings);
|
||||
},
|
||||
@ -273,6 +282,8 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
delete save.styles;
|
||||
Object.assign(Settings.overview, save.overview);
|
||||
delete save.overview;
|
||||
Object.assign(Settings.EditorTheme, save.EditorTheme);
|
||||
delete save.EditorTheme;
|
||||
Object.assign(Settings, save);
|
||||
},
|
||||
};
|
||||
|
@ -1,18 +0,0 @@
|
||||
// Contains an array containing information about the player's source files
|
||||
// Array[n] returns what level the player has of Source-File N.
|
||||
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
|
||||
export const SourceFileFlags: number[] = Array(CONSTANTS.TotalNumBitNodes + 1); // Skip index 0
|
||||
|
||||
export function updateSourceFileFlags(p: IPlayer): void {
|
||||
for (let i = 0; i < SourceFileFlags.length; ++i) {
|
||||
SourceFileFlags[i] = 0;
|
||||
}
|
||||
|
||||
for (let i = 0; i < p.sourceFiles.length; ++i) {
|
||||
const sf = p.sourceFiles[i];
|
||||
SourceFileFlags[sf.n] = sf.lvl;
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@ import { OrderTypes } from "../data/OrderTypes";
|
||||
import { PositionTypes } from "../data/PositionTypes";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
|
||||
@ -288,12 +287,12 @@ export function StockTicker(props: IProps): React.ReactElement {
|
||||
|
||||
// Whether the player has access to orders besides market orders (limit/stop)
|
||||
function hasOrderAccess(): boolean {
|
||||
return props.p.bitNodeN === 8 || SourceFileFlags[8] >= 3;
|
||||
return props.p.bitNodeN === 8 || props.p.sourceFileLvl(8) >= 3;
|
||||
}
|
||||
|
||||
// Whether the player has access to shorting stocks
|
||||
function hasShortAccess(): boolean {
|
||||
return props.p.bitNodeN === 8 || SourceFileFlags[8] >= 2;
|
||||
return props.p.bitNodeN === 8 || props.p.sourceFileLvl(8) >= 2;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -9,7 +9,6 @@ import { Stock } from "../Stock";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Box from "@mui/material/Box";
|
||||
@ -67,7 +66,7 @@ function ShortPosition(props: IProps): React.ReactElement {
|
||||
percentageGains = 0;
|
||||
}
|
||||
|
||||
if (props.p.bitNodeN === 8 || SourceFileFlags[8] >= 2) {
|
||||
if (props.p.bitNodeN === 8 || props.p.sourceFileLvl(8) >= 2) {
|
||||
return (
|
||||
<>
|
||||
<Box display="flex">
|
||||
|
@ -51,3 +51,14 @@ export function getSubdirectories(serv: BaseServer, dir: string): string[] {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if the server's directory itself or one of its subdirectory contains files.
|
||||
*/
|
||||
export function containsFiles(server: BaseServer, dir: string): boolean {
|
||||
const dirWithTrailingSlash = dir + (dir.slice(-1) === "/" ? "" : "/");
|
||||
|
||||
return [...server.scripts.map((s) => s.filename), ...server.textFiles.map((t) => t.fn)].some((filename) =>
|
||||
filename.startsWith(dirWithTrailingSlash),
|
||||
);
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ import { ITerminal } from "../ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { showMessage } from "../../Message/MessageHelpers";
|
||||
import { MessageFilenames, showMessage } from "../../Message/MessageHelpers";
|
||||
import { showLiterature } from "../../Literature/LiteratureHelpers";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { checkEnum } from "../../utils/helpers/checkEnum";
|
||||
|
||||
export function cat(
|
||||
terminal: ITerminal,
|
||||
@ -43,6 +44,7 @@ export function cat(
|
||||
} else if (filename.endsWith(".msg")) {
|
||||
const file = server.messages[i];
|
||||
if (file !== filename) continue;
|
||||
if (!checkEnum(MessageFilenames, file)) return;
|
||||
showMessage(file);
|
||||
return;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
|
||||
import { evaluateDirectoryPath, removeTrailingSlash } from "../DirectoryHelpers";
|
||||
import { containsFiles } from "../DirectoryServerHelpers";
|
||||
|
||||
export function cd(
|
||||
terminal: ITerminal,
|
||||
@ -31,10 +32,7 @@ export function cd(
|
||||
}
|
||||
|
||||
const server = player.getCurrentServer();
|
||||
if (
|
||||
!server.scripts.some((script) => script.filename.startsWith(evaledDir + "")) &&
|
||||
!server.textFiles.some((file) => file.fn.startsWith(evaledDir + ""))
|
||||
) {
|
||||
if (!containsFiles(server, evaledDir)) {
|
||||
terminal.error("Invalid path. Failed to change directories");
|
||||
return;
|
||||
}
|
||||
|
@ -366,9 +366,9 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
sx={{ mb: 1 }}
|
||||
multiline
|
||||
fullWidth
|
||||
maxRows={3}
|
||||
maxRows={10}
|
||||
label={"import / export theme"}
|
||||
value={JSON.stringify(customTheme)}
|
||||
value={JSON.stringify(customTheme, undefined, 2)}
|
||||
onChange={onThemeChange}
|
||||
/>
|
||||
<>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user