prettify, sorry for the big ass commit

This commit is contained in:
Olivier Gagnon 2021-09-04 19:09:30 -04:00
parent 3d7cdb4ef9
commit a18bdd6afc
554 changed files with 91615 additions and 66138 deletions

File diff suppressed because it is too large Load Diff

@ -1,24 +1,27 @@
# Contributing to Bitburner
## In General
The game is made better because the community as a whole speaks up about
ways to improve the game. Here's some of the ways you can make your voice
heard:
- [Discord](https://discordapp.com)
There is a dedicated Discord instance set up for more free-form chats
between all members of the community. Regular players, heavy scripters,
Bitburner contributors, and everyone in between can be found on the
server.
- [Github Issues](https://github.com/danielyxie/bitburner/issues)
Although the term "issues" can have a negative connotation, they are a
means of communicating with the community. A new Issue can be a
interesting new feature that you feel would improve the game. It could be
an unexpected behavior within the game. Or because the game is about
scripting perhaps there is something that is conflicting with the
browser's Javascript interaction. So please do not be afraid to open a
[new issue](https://github.com/danielyxie/bitburner/issues/new).
- [Discord](https://discordapp.com)
There is a dedicated Discord instance set up for more free-form chats
between all members of the community. Regular players, heavy scripters,
Bitburner contributors, and everyone in between can be found on the
server.
- [Github Issues](https://github.com/danielyxie/bitburner/issues)
Although the term "issues" can have a negative connotation, they are a
means of communicating with the community. A new Issue can be a
interesting new feature that you feel would improve the game. It could be
an unexpected behavior within the game. Or because the game is about
scripting perhaps there is something that is conflicting with the
browser's Javascript interaction. So please do not be afraid to open a
[new issue](https://github.com/danielyxie/bitburner/issues/new).
## Reporting Bugs
The recommended method for reporting a bug is by opening a
[Github Issue](https://github.com/danielyxie/bitburner/issues).
@ -30,18 +33,19 @@ already been reported as an [Issue](https://github.com/danielyxie/bitburner/issu
#### How to Submit a Good Bug Report
* **Use a clear and descriptive title** for the issue
* **State your browser, your browser's version, and your computer's OS**
* **Attach your save file**, if you think it would help solve the issue
* **Provide instructions on how to reproduce the bug** in as much detail
as possible. If you cannot reliably reproduce the bug, then just try
your best to explain what was happening when the bug occurred
* **Provide any scripts** that triggered the bug if the issue is Netscript-related
* **Open your browser's Dev Console and report any error-related output**
that may be printed there. The Dev Console can be opened on most modern
browsers by pressing F12
- **Use a clear and descriptive title** for the issue
- **State your browser, your browser's version, and your computer's OS**
- **Attach your save file**, if you think it would help solve the issue
- **Provide instructions on how to reproduce the bug** in as much detail
as possible. If you cannot reliably reproduce the bug, then just try
your best to explain what was happening when the bug occurred
- **Provide any scripts** that triggered the bug if the issue is Netscript-related
- **Open your browser's Dev Console and report any error-related output**
that may be printed there. The Dev Console can be opened on most modern
browsers by pressing F12
## As a Developer
Anyone is welcome to contribute to Bitburner code. However, please read
the [license](https://github.com/danielyxie/bitburner/blob/dev/license.txt)
and the [readme](https://github.com/danielyxie/bitburner/blob/dev/README.md)
@ -52,64 +56,70 @@ To contribute to Bitburner code, you will need to have
called `npm` is installed as well.
#### What are you Allowed to Contribute?
Not all code contributions will be accepted. The safest way to ensure
that you don't waste time working on something that gets rejected is to
run your idea(s)/plan(s) past [danielyxie](https://github.com/danielyxie) first.
You can contact him through:
* Github
* Discord
* [Reddit](https://www.reddit.com/user/chapt3r/)
- Github
- Discord
- [Reddit](https://www.reddit.com/user/chapt3r/)
Otherwise, here are some general guidelines for determining what types of
changes are okay to contribute:
##### Contributions that Will Most Likely Be Accepted
* Bug Fixes
* Quality-of-Life Changes
* Adding a new, commonly-requested Netscript function
* Fixing or improving UI elements
* Adding game settings/options
* Adding a new Terminal command
* Code Refactors that conform to good/standard practices
- Bug Fixes
- Quality-of-Life Changes
- Adding a new, commonly-requested Netscript function
- Fixing or improving UI elements
- Adding game settings/options
- Adding a new Terminal command
- Code Refactors that conform to good/standard practices
##### Contributions that will not be Accepted without prior approval
* Changes that directly affect the game's balance
* New gameplay mechanics
- Changes that directly affect the game's balance
- New gameplay mechanics
#### Submitting a Pull Request
When submitting a pull request with your code contributions, please abide by
the following rules:
- Work in a branch forked from `dev` to isolate the new code
- Ensure you have latest from the [game's main
repository](danielyxie/bitburner@dev)
- Rebase your branch if necessary
- Run the game locally to test out your changes
- When submitting the pull request, make sure that the base fork is
_danielyxie/bitburner_ and the base is _dev_.
- If your changes affect the game's UI, attach some screenshots or GIFs showing
the changes to the UI
- If your changes affect Netscript, provide some
scripts that can be used to test the Netscript changes.
- Ensure you have run `npm run lint` to make sure your changes conform to the
rules enforced across the code base. The command will fail if any of the
linters find a violation.
- Do not check in any bundled files (`dist\*.bundle.js`) or the `index.html`
in the root of the repository. These will be updated as part of official
releases.
- Work in a branch forked from `dev` to isolate the new code
- Ensure you have latest from the [game's main
repository](danielyxie/bitburner@dev)
- Rebase your branch if necessary
- Run the game locally to test out your changes
- When submitting the pull request, make sure that the base fork is
_danielyxie/bitburner_ and the base is _dev_.
- If your changes affect the game's UI, attach some screenshots or GIFs showing
the changes to the UI
- If your changes affect Netscript, provide some
scripts that can be used to test the Netscript changes.
- Ensure you have run `npm run lint` to make sure your changes conform to the
rules enforced across the code base. The command will fail if any of the
linters find a violation.
- Do not check in any bundled files (`dist\*.bundle.js`) or the `index.html`
in the root of the repository. These will be updated as part of official
releases.
## As a Documentor
To contribute to and view your changes to the BitBurner documentation, you will
need to have Python installed, along with [Sphinx](http://www.sphinx-doc.org).
Before submitting your code for a pull request, please try to follow these
rules:
- Work in a branch forked from `dev` to isolate the new code
- Ensure you have latest from the [game's main
repository](danielyxie/bitburner@dev)
- Rebase your branch if necessary
- When submitting the pull request, make sure that the base fork is
_danielyxie/bitburner_ and the base is _dev_.
- Do not check in any generated files under `doc\`. The documentation is built
automatically by ReadTheDocs.
- Work in a branch forked from `dev` to isolate the new code
- Ensure you have latest from the [game's main
repository](danielyxie/bitburner@dev)
- Rebase your branch if necessary
- When submitting the pull request, make sure that the base fork is
_danielyxie/bitburner_ and the base is _dev_.
- Do not check in any generated files under `doc\`. The documentation is built
automatically by ReadTheDocs.

@ -1,9 +1,11 @@
# Bitburner
Bitburner is a programming-based [incremental game](https://en.wikipedia.org/wiki/Incremental_game)
that revolves around hacking and cyberpunk themes.
The game can be played at https://danielyxie.github.io/bitburner.
# Documentation
The game's official documentation can be found on [Read The
Docs](http://bitburner.readthedocs.io/). Please note that this is still a
work-in-progress.
@ -16,6 +18,7 @@ For further guidance, please refer to the "As A Documentor" section of
[CONTRIBUTING](CONTRIBUTING.md).
# Contribution
There are many ways to contribute to the game. It can be as simple as fixing
a typo, correcting a bug, or improving the UI. For guidance on doing so,
please refer to the [CONTRIBUTING](CONTRIBUTING.md) document.

@ -1,7 +1,7 @@
Deploying a new version
-----------------------
## Deploying a new version
Update the following
- `src/Constants.ts` `Version` and `LatestUpdate`
- `package.json` `version`
- `doc/source/conf.py` `version` and `release`
@ -9,15 +9,13 @@ Update the following
- post to discord
- post to reddit.com/r/Bitburner
Deploying `dev` to the Beta Branch
----------------------------------
## Deploying `dev` to the Beta Branch
TODO
Development Workflow Best Practices
-----------------------------------
## Development Workflow Best Practices
- Work in a new branch forked from the `dev` branch to isolate your new code
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`

@ -1,9 +1,9 @@
const TEST = process.env.NODE_ENV === "test";
module.exports = {
"presets": [
"@babel/preset-react",
TEST && "@babel/preset-env",
TEST && "@babel/preset-typescript",
].filter(Boolean),
}
presets: [
"@babel/preset-react",
TEST && "@babel/preset-env",
TEST && "@babel/preset-typescript",
].filter(Boolean),
};

@ -1,61 +1,61 @@
@mixin animation($property) {
-webkit-animation: $property;
-moz-animation: $property;
-ms-animation: $property;
-o-animation: $property;
animation: $property;
-webkit-animation: $property;
-moz-animation: $property;
-ms-animation: $property;
-o-animation: $property;
animation: $property;
}
@mixin borderRadius($property) {
-webkit-border-radius: $property;
-moz-border-radius: $property;
border-radius: $property;
-webkit-border-radius: $property;
-moz-border-radius: $property;
border-radius: $property;
}
@mixin boxShadow($value) {
-webkit-box-shadow: $value;
-moz-box-shadow: $value;
box-shadow: $value;
-webkit-box-shadow: $value;
-moz-box-shadow: $value;
box-shadow: $value;
}
@mixin keyframes($animationName) {
@-webkit-keyframes #{$animationName} {
$browser: '-webkit-' !global;
@content;
}
@-webkit-keyframes #{$animationName} {
$browser: "-webkit-" !global;
@content;
}
@-moz-keyframes #{$animationName} {
$browser: '-moz-' !global;
@content;
}
@-moz-keyframes #{$animationName} {
$browser: "-moz-" !global;
@content;
}
@-ms-keyframes #{$animationName} {
$browser: '-ms-' !global;
@content;
}
@-ms-keyframes #{$animationName} {
$browser: "-ms-" !global;
@content;
}
@-o-keyframes #{$animationName} {
$browser: '-o-' !global;
@content;
}
@-o-keyframes #{$animationName} {
$browser: "-o-" !global;
@content;
}
@keyframes #{$animationName} {
$browser: '' !global;
@content;
}
@keyframes #{$animationName} {
$browser: "" !global;
@content;
}
}
@mixin transform($property) {
-webkit-transform: $property;
-moz-transform: $property;
-ms-transform: $property;
-o-transform: $property;
transform: $property;
-webkit-transform: $property;
-moz-transform: $property;
-ms-transform: $property;
-o-transform: $property;
transform: $property;
}
@mixin userSelect($value) {
-webkit-user-select: $value;
-moz-user-select: $value;
-ms-user-select: $value;
user-select: $value;
-webkit-user-select: $value;
-moz-user-select: $value;
-ms-user-select: $value;
user-select: $value;
}

@ -1,15 +1,15 @@
@import "theme";
* {
font-size: $defaultFontSize;
font-family: $fontFamily;
font-size: $defaultFontSize;
font-family: $fontFamily;
}
*,
*:before,
*:after {
margin: 0;
padding: 0;
box-sizing: border-box;
vertical-align: top;
margin: 0;
padding: 0;
box-sizing: border-box;
vertical-align: top;
}

@ -1,4 +1,5 @@
$fontFamily: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman';
$fontFamily: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas",
"Courier New", Courier, monospace, "Times New Roman";
$defaultFontSize: 16px;
/* COLORS */

@ -1,126 +1,132 @@
@import "theme";
.active-scripts-list {
list-style-type: none;
list-style-type: none;
}
#active-scripts-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
> p {
width: 70%;
margin: 6px;
padding: 4px;
}
> p {
width: 70%;
margin: 6px;
padding: 4px;
}
.accordion-header {
> pre {
color: white;
}
.accordion-header {
> pre {
color: white;
}
}
}
.active-scripts-server-header {
background-color: #444;
font-size: $defaultFontSize * 1.25;
background-color: #444;
font-size: $defaultFontSize * 1.25;
color: #fff;
margin: 6px 6px 0 6px;
padding: 6px;
cursor: pointer;
width: 60%;
text-align: left;
border: none;
outline: none;
&:after {
content: "\02795"; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125;
color: #fff;
margin: 6px 6px 0 6px;
padding: 6px;
cursor: pointer;
width: 60%;
text-align: left;
border: none;
outline: none;
float: right;
margin-left: 5px;
}
&:after {
content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125;
color: #fff;
float: right;
margin-left: 5px;
}
&.active, &:hover {
background-color: #555;
}
&.active,
&:hover {
background-color: #555;
}
}
.active-scripts-server-header.active {
&:after {
content: "\2796"; /* "minus" sign (-) */
font-size: $defaultFontSize * 0.8125;
color: #fff;
float: right;
margin-left: 5px;
}
&:after {
content: "\2796"; /* "minus" sign (-) */
font-size: $defaultFontSize * 0.8125;
color: #fff;
float: right;
margin-left: 5px;
}
&:hover {
background-color: #666;
}
&:hover {
background-color: #666;
}
}
.active-scripts-server-panel {
margin: 0 6px 6px 6px;
padding: 0 6px 6px 6px;
width: 55%;
margin-left: 5%;
display: none;
margin: 0 6px 6px 6px;
padding: 0 6px 6px 6px;
width: 55%;
margin-left: 5%;
display: none;
div, ul, ul > li {
background-color: #555;
}
div,
ul,
ul > li {
background-color: #555;
}
}
.active-scripts-script-header {
background-color: #555;
border: none;
color: var(--my-font-color);
cursor: pointer;
display: block;
outline: none;
padding: 4px 25px 4px 10px;
position: relative;
text-align: left;
width: auto;
&:after {
content: "\02795"; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125;
float: right;
margin-left: 5px;
color: transparent;
text-shadow: 0 0 0 var(--my-font-color);
position: absolute;
bottom: 4px;
}
&.active:after {
content: "\2796"; /* "minus" sign (-) */
}
&:hover,
&.active:hover {
background-color: #666;
}
&.active {
background-color: #555;
border: none;
color: var(--my-font-color);
cursor: pointer;
display: block;
outline: none;
padding: 4px 25px 4px 10px;
position: relative;
text-align: left;
width: auto;
&:after {
content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.8125;
float: right;
margin-left: 5px;
color: transparent;
text-shadow: 0 0 0 var(--my-font-color);
position: absolute;
bottom: 4px;
}
&.active:after {
content: "\2796"; /* "minus" sign (-) */
}
&:hover,
&.active:hover {
background-color: #666;
}
&.active {
background-color: #555;
}
}
}
.active-scripts-script-panel {
background-color: #555;
display: none;
font-size: 14px;
margin-bottom: 6px;
padding: 0 18px;
width: auto;
background-color: #555;
display: none;
font-size: 14px;
margin-bottom: 6px;
padding: 0 18px;
width: auto;
pre, h2, ul, li {
background-color: #555;
width: auto;
color: #fff;
margin-left: 5%;
}
pre,
h2,
ul,
li {
background-color: #555;
width: auto;
color: #fff;
margin-left: 5%;
}
}

@ -6,25 +6,25 @@
@import "theme";
#augmentations-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#augmentations-content {
> p {
font-size: $defaultFontSize * 0.875;
width: 70%;
}
> p {
font-size: $defaultFontSize * 0.875;
width: 70%;
}
}
.augmentations-list {
button,
div {
color: var(--my-font-color);
text-decoration: none;
}
button,
div {
color: var(--my-font-color);
text-decoration: none;
}
button {
padding: 4px;
}
button {
padding: 4px;
}
}

@ -1,135 +1,135 @@
@import "theme";
#bladeburner-container {
a,
div,
p,
pre,
td {
font-size: $defaultFontSize * 0.8125;
}
a,
div,
p,
pre,
td {
font-size: $defaultFontSize * 0.8125;
}
}
.bladeburner-action {
border: 1px solid #fff;
margin: 7px;
padding: 7px;
white-space: pre-wrap;
border: 1px solid #fff;
margin: 7px;
padding: 7px;
white-space: pre-wrap;
pre {
white-space: pre-wrap;
}
pre {
white-space: pre-wrap;
}
}
/* Whatever action is currently active */
.bladeburner-active-action {
border: 4px solid #fff;
border: 4px solid #fff;
}
/* Action & Skills panel navigation button */
%bladeburner-nav-button {
border: 1px solid #fff;
margin: 2px;
padding: 2px;
color: #fff;
border: 1px solid #fff;
margin: 2px;
padding: 2px;
color: #fff;
}
.bladeburner-nav-button {
@extend %bladeburner-nav-button;
@extend %bladeburner-nav-button;
&:hover {
background-color: #3d4044;
}
&:hover {
background-color: #3d4044;
}
}
.bladeburner-nav-button-inactive {
@extend %bladeburner-nav-button;
@extend %bladeburner-nav-button;
text-decoration: none;
background-color: #555;
cursor: default;
pointer-events: none;
text-decoration: none;
background-color: #555;
cursor: default;
pointer-events: none;
}
/* Checkbox for (de)selecting autoleveling */
.bbcheckbox {
position: relative;
display: inline;
label {
width: 20px;
height: 20px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
background: black;
border-width: 1px;
border-color: white;
border-style: solid;
&:after {
content: '';
width: 9px;
height: 5px;
position: absolute;
top: 5px;
left: 5px;
border: 3px solid white;
border-top: none;
border-right: none;
opacity: 0;
transform: rotate(-45deg);
}
position: relative;
display: inline;
label {
width: 20px;
height: 20px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
background: black;
border-width: 1px;
border-color: white;
border-style: solid;
&:after {
content: "";
width: 9px;
height: 5px;
position: absolute;
top: 5px;
left: 5px;
border: 3px solid white;
border-top: none;
border-right: none;
opacity: 0;
transform: rotate(-45deg);
}
input[type="checkbox"] {
margin: 3px;
visibility: hidden;
&:checked + label:after {
opacity: 1;
}
}
input[type="checkbox"] {
margin: 3px;
visibility: hidden;
&:checked + label:after {
opacity: 1;
}
}
}
/* Bladeburner Console */
.bladeburner-console-div {
display: inline-block;
width: 40%;
border: 1px solid #fff;
overflow: auto;
height: 100%;
position: absolute;
display: inline-block;
width: 40%;
border: 1px solid #fff;
overflow: auto;
height: 100%;
position: absolute;
}
.bladeburner-console-table {
height: auto;
overflow: auto;
table-layout: fixed;
width: 100%;
height: auto;
overflow: auto;
table-layout: fixed;
width: 100%;
}
.bladeburner-console-input-row {
transition: height 1s;
width: 100%;
transition: height 1s;
width: 100%;
}
.bladeburner-console-input-cell {
display: flex;
display: flex;
}
.bladeburner-console-input {
display: inline-block;
padding: 0 !important;
margin: 0 !important;
border: 0;
background-color: var(--my-background-color);
font-size: $defaultFontSize * 0.8125;
outline: none;
color: var(--my-font-color);
flex: 1 1 auto;
display: inline-block;
padding: 0 !important;
margin: 0 !important;
border: 0;
background-color: var(--my-background-color);
font-size: $defaultFontSize * 0.8125;
outline: none;
color: var(--my-font-color);
flex: 1 1 auto;
}
.bladeburner-console-line {
word-wrap: break-word;
hyphens: auto;
-webkit-hyphens: auto;
-moz-hyphens: auto;
word-wrap: break-word;
hyphens: auto;
-webkit-hyphens: auto;
-moz-hyphens: auto;
}

@ -11,80 +11,80 @@
/* Remove default <button> styling */
button {
border: none;
background-color: transparent;
border: none;
background-color: transparent;
}
.a-link-button,
.std-button {
@extend .noselect;
text-decoration: none;
background-color: #555;
color: #fff;
padding: 3px 5px;
margin: 5px;
border: 1px solid #333;
@extend .noselect;
text-decoration: none;
background-color: #555;
color: #fff;
padding: 3px 5px;
margin: 5px;
border: 1px solid #333;
&:hover {
background-color: #666;
}
&:hover {
background-color: #666;
}
&:active {
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
}
&:active {
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
}
}
.a-link-button-inactive,
.std-button-disabled,
.std-button:disabled {
text-decoration: none;
background-color: #333;
color: #fff;
padding: 3px 5px;
margin: 5px;
border: 1px solid #333;
cursor: default;
text-decoration: none;
background-color: #333;
color: #fff;
padding: 3px 5px;
margin: 5px;
border: 1px solid #333;
cursor: default;
-moz-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
&:hover {
.tooltiptext,
.tooltiptexthigh,
.tooltiptextleft {
visibility: visible;
}
&:hover {
.tooltiptext,
.tooltiptexthigh,
.tooltiptextleft {
visibility: visible;
}
}
&:active {
pointer-events: none;
}
&:active {
pointer-events: none;
}
}
.a-link-button-bought,
.std-button-bought {
@extend .noselect;
text-decoration: none;
background-color: #0a0;
color: #fff;
padding: 3px 5px;
margin: 5px;
border: 1px solid #0a0;
cursor: default;
@extend .noselect;
text-decoration: none;
background-color: #0a0;
color: #fff;
padding: 3px 5px;
margin: 5px;
border: 1px solid #0a0;
cursor: default;
&:hover {
.tooltiptext,
.tooltiptexthigh,
.tooltiptextleft {
visibility: visible;
}
&:hover {
.tooltiptext,
.tooltiptexthigh,
.tooltiptextleft {
visibility: visible;
}
}
&:active {
pointer-events: none;
}
&:active {
pointer-events: none;
}
}
/**
@ -92,21 +92,21 @@ button {
* It has a black background so it does not clash with the default accordion coloring
*/
.accordion-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
margin: 4px;
padding: 4px;
background-color: #000;
&:hover,
&:active {
color: #fff;
text-decoration: none;
cursor: pointer;
}
/* TODO focus selector? */
&:hover,
&:active {
color: #fff;
text-decoration: none;
cursor: pointer;
}
/* TODO focus selector? */
}

@ -1,24 +1,24 @@
.casino-card {
padding: 10px;
border: solid 1px #808080;
background-color: white;
display: inline-block;
border-radius: 10px;
font-size: 18.5px;
text-align: center;
margin: 3px;
font-weight: bold;
padding: 10px;
border: solid 1px #808080;
background-color: white;
display: inline-block;
border-radius: 10px;
font-size: 18.5px;
text-align: center;
margin: 3px;
font-weight: bold;
}
.casino-card .value {
font-size: 20px;
font-family: sans-serif;
font-size: 20px;
font-family: sans-serif;
}
.casino-card.red {
color: red;
color: red;
}
.casino-card.black {
color: black;
color: black;
}

@ -6,91 +6,117 @@
*/
#character-overview-wrapper {
position: relative;
position: relative;
}
#character-overview-container {
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: auto; /* Full height */
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: auto;
max-width: 280px;
overflow: auto; /* Enable scroll if needed */
background-color: rgba(57, 54, 54, 0.9); /* Fallback color */
z-index: 1;
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: auto; /* Full height */
padding: 10px 2px;
border: 2px solid var(--my-highlight-color);
width: auto;
max-width: 280px;
overflow: auto; /* Enable scroll if needed */
background-color: rgba(57, 54, 54, 0.9); /* Fallback color */
z-index: 1;
}
#character-overview-text {
color: $my-stat-physical;
color: $my-stat-physical;
table {
border-collapse: collapse;
margin: auto;
}
table {
border-collapse: collapse;
margin: auto;
}
td {
padding: 2px;
vertical-align: middle;
}
td {
padding: 2px;
vertical-align: middle;
}
}
.character-stat-text {
color: #fff;
background-color: #444;
color: #fff;
background-color: #444;
}
.character-stat-cell {
text-align: right;
text-align: right;
}
#character-str-wrapper td,
#character-cha-wrapper td {
padding-top: 10px;
padding-top: 10px;
}
.character-divider td {
border-top: 1px #aaa solid;
padding-top: 10px;
border-top: 1px #aaa solid;
padding-top: 10px;
}
#character-hp-wrapper { color: $my-stat-hp-color; }
.character-hp-cell { color: $my-stat-hp-color; }
#character-money-wrapper { color: $my-stat-money-color; }
.character-money-cell { color: $my-stat-money-color; }
#character-hack-wrapper { color: $my-stat-hack-color; }
.character-hack-cell { color: $my-stat-hack-color; }
#character-cha-wrapper { color: $my-stat-cha-color; }
.character-cha-cell { color: $my-stat-cha-color; }
#character-int-wrapper { color: $my-stat-int-color; }
.character-int-cell { color: $my-stat-int-color; }
.character-combat-cell { color: $my-stat-physical; }
#character-work-wrapper { color: $my-stat-hack-color; }
.character-work-cell { color: $my-stat-hack-color; }
#character-hp-wrapper {
color: $my-stat-hp-color;
}
.character-hp-cell {
color: $my-stat-hp-color;
}
#character-money-wrapper {
color: $my-stat-money-color;
}
.character-money-cell {
color: $my-stat-money-color;
}
#character-hack-wrapper {
color: $my-stat-hack-color;
}
.character-hack-cell {
color: $my-stat-hack-color;
}
#character-cha-wrapper {
color: $my-stat-cha-color;
}
.character-cha-cell {
color: $my-stat-cha-color;
}
#character-int-wrapper {
color: $my-stat-int-color;
}
.character-int-cell {
color: $my-stat-int-color;
}
.character-combat-cell {
color: $my-stat-physical;
}
#character-work-wrapper {
color: $my-stat-hack-color;
}
.character-work-cell {
color: $my-stat-hack-color;
}
.character-overview-btn {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #cecece;
display: inline-block;
font-size: $defaultFontSize * 0.875;
font-weight: bold;
height: 25px;
background-color: #000;
padding: 5px 8px;
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #cecece;
display: inline-block;
font-size: $defaultFontSize * 0.875;
font-weight: bold;
height: 25px;
background-color: #000;
padding: 5px 8px;
}
.character-quick-options {
margin-top: 10px;
text-align: center;
margin-top: 10px;
text-align: center;
}
.character-overview-btn:hover,
.character-overview-btn:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
color: #fff;
text-decoration: none;
cursor: pointer;
}

@ -5,45 +5,45 @@
*/
#codemirror-form-wrapper {
height: 80%;
margin: 10px 0 0 6px;
height: 80%;
margin: 10px 0 0 6px;
}
.CodeMirror {
height: 100%;
width: 100%;
border: 2px solid var(--my-highlight-color);
z-index: 1;
font-family: $fontFamily;
font-size: $defaultFontSize;
height: 100%;
width: 100%;
border: 2px solid var(--my-highlight-color);
z-index: 1;
font-family: $fontFamily;
font-size: $defaultFontSize;
}
/**
* Highlight matches
*/
.cm-matchhighlight {
background-color: #8f908a;
background-color: #8f908a;
}
.CodeMirror-selection-highlight-scrollbar {
background-color: #8f908a;
background-color: #8f908a;
}
/**
* Show Invisibles
*/
.cm-whitespace::before {
position: absolute;
pointer-events: none;
color: #404f7d;
position: absolute;
pointer-events: none;
color: #404f7d;
}
/**
* Vim command display
*/
#codemirror-vim-command-display-wrapper {
background-color: white;
font-size: 13px;
height: 30px;
margin-left: 6px;
background-color: white;
font-size: 13px;
height: 30px;
margin-left: 6px;
}

@ -12,154 +12,154 @@
#cmpy-mgmt-container a,
#cmpy-mgmt-container div,
#cmpy-mgmt-container br {
font-size: $defaultFontSize * 0.8125;
font-size: $defaultFontSize * 0.8125;
}
/* Header tabs */
.cmpy-mgmt-header-tab {
display: inline-block;
color: #fff;
background-color: #555;
border: 1px solid #fff;
padding: 4px;
display: inline-block;
color: #fff;
background-color: #555;
border: 1px solid #fff;
padding: 4px;
}
.cmpy-mgmt-header-tab:hover {
background-color: #666;
background-color: #666;
}
.cmpy-mgmt-header-tab.current {
background-color: #777;
background-color: #777;
}
/* Switch between Cities */
.cmpy-mgmt-city-tab {
display: inline-block;
color: #fff;
background-color: #555;
border: 1px solid #fff;
padding: 4px;
display: inline-block;
color: #fff;
background-color: #555;
border: 1px solid #fff;
padding: 4px;
}
.cmpy-mgmt-city-tab:hover {
background-color: #666;
background-color: #666;
}
.cmpy-mgmt-city-tab.current {
background-color: #777;
background-color: #777;
}
/* Panels */
#cmpy-mgmt-panel {
height: 90%;
height: 90%;
}
.cmpy-mgmt-industry-left-panel,
.cmpy-mgmt-industry-right-panel {
display: inline-block;
height: 100%;
overflow-y: auto;
overflow-x: auto;
overflow: visible;
top: 10px;
width: 45%;
display: inline-block;
height: 100%;
overflow-y: auto;
overflow-x: auto;
overflow: visible;
top: 10px;
width: 45%;
}
.cmpy-mgmt-industry-overview-panel {
border: 1px solid #fff;
color: var(--my-font-color);
display: inline-block;
padding: 3px;
width: 100%;
border: 1px solid #fff;
color: var(--my-font-color);
display: inline-block;
padding: 3px;
width: 100%;
}
.cmpy-mgmt-employee-panel {
border: 1px solid #fff;
display: block;
padding: 3px;
width: 100%;
border: 1px solid #fff;
display: block;
padding: 3px;
width: 100%;
}
.cmpy-mgmt-warehouse-panel {
border: 1px solid #fff;
display: inline-block;
padding: 3px;
width: 100%;
border: 1px solid #fff;
display: inline-block;
padding: 3px;
width: 100%;
}
/* Hiring new employees */
.cmpy-mgmt-find-employee-option {
border: 1px solid #fff;
margin: 6px;
border: 1px solid #fff;
margin: 6px;
}
.cmpy-mgmt-find-employee-option:hover {
background-color: #3d4044;
background-color: #3d4044;
}
/* Warehouse */
.cmpy-mgmt-warehouse-material-div {
padding: 2px;
border: 1px solid #fff;
padding: 2px;
border: 1px solid #fff;
}
.cmpy-mgmt-warehouse-product-div {
padding: 2px;
border: 1px solid #fff;
padding: 2px;
border: 1px solid #fff;
}
/* Exporting materials/products */
.cmpy-mgmt-existing-export {
border: 1px solid #fff;
border-radius: 25px;
margin: 4px;
padding: 4px;
border: 1px solid #fff;
border-radius: 25px;
margin: 4px;
padding: 4px;
}
.cmpy-mgmt-existing-export:hover {
background-color: #333;
background-color: #333;
}
/* Corporation Upgrades */
.cmpy-mgmt-upgrade-container {
border: 1px solid #fff;
width: 60%;
margin: 4px;
border: 1px solid #fff;
width: 60%;
margin: 4px;
}
.cmpy-mgmt-upgrade-header {
margin: 6px;
padding: 6px;
margin: 6px;
padding: 6px;
}
.cmpy-mgmt-upgrade-div {
display: inline-block;
border: 1px solid #fff;
margin: 2px;
padding: 6px;
border-radius: 25px;
font-size: $defaultFontSize * 0.75;
color: var(--my-font-color);
display: inline-block;
border: 1px solid #fff;
margin: 2px;
padding: 6px;
border-radius: 25px;
font-size: $defaultFontSize * 0.75;
color: var(--my-font-color);
}
.cmpy-mgmt-upgrade-div:hover {
background-color: #333;
background-color: #333;
}
/* Industry Upgrades */
.industry-purchases-and-upgrades-header {
font-size: 14px;
margin: 2px;
padding: 2px;
font-size: 14px;
margin: 2px;
padding: 2px;
}
/* Advertising */
.cmpy-mgmt-advertising-info {
font-size: $defaultFontSize * 0.75;
font-size: $defaultFontSize * 0.75;
}
/* Research */
#corporation-research-popup-box-content {
overflow-x: auto !important;
overflow-y: auto !important;
overflow-x: auto !important;
overflow-y: auto !important;
}

@ -1,32 +1,32 @@
.add-exp-button {
margin-right: 0;
margin-right: 0;
}
.remove-exp-button {
margin-left: 0;
margin-left: 0;
}
.exp-input {
margin: 5px 0 5px 0;
margin: 5px 0 5px 0;
padding: 2px 5px;
padding: 2px 5px;
}
.text-center {
margin: auto;
text-align: center;
vertical-align: middle;
margin: auto;
text-align: center;
vertical-align: middle;
}
.touch-right {
margin-right: 0;
margin-right: 0;
}
.touch-left {
margin-left: 0;
margin-left: 0;
}
.touch-sides {
margin-left: 0;
margin-right: 0;
margin-left: 0;
margin-right: 0;
}

@ -7,13 +7,13 @@
@import "theme";
#game-options-right-panel {
a {
display: block;
width: 46%;
}
a {
display: block;
width: 46%;
}
button {
display: inline-block;
width: 46%;
}
button {
display: inline-block;
width: 46%;
}
}

@ -6,28 +6,29 @@
*/
#gang-container {
position: fixed;
padding: 6px;
position: fixed;
padding: 6px;
p, pre {
font-size: $defaultFontSize * 0.9375;
}
p,
pre {
font-size: $defaultFontSize * 0.9375;
}
select {
background-color: black;
color: white;
}
select {
background-color: black;
color: white;
}
}
#gang-management-subpage > p {
padding: 4px;
padding: 4px;
}
.gang-member-info-div {
background-color: #555;
display: inline;
float: left;
width: 30%;
background-color: #555;
display: inline;
float: left;
width: 30%;
}
/**
@ -35,14 +36,14 @@
*/
.gang-owned-upgrades-div {
display: inline-block;
margin-left: 6px;
width: 75%;
display: inline-block;
margin-left: 6px;
width: 75%;
}
.gang-owned-upgrade {
border: 1px solid white;
font-size: 12px;
margin: 1px;
padding: 1px;
border: 1px solid white;
font-size: 12px;
margin: 1px;
padding: 1px;
}

3408
css/grid.min.css vendored

File diff suppressed because one or more lines are too long

@ -6,70 +6,71 @@
*/
#hacknet-nodes-container {
position: fixed;
padding: 10px;
position: fixed;
padding: 10px;
}
.hacknet-general-info {
margin: 10px;
width: 70vw;
margin: 10px;
width: 70vw;
}
#hacknet-nodes-container li {
float: left;
overflow: hidden;
white-space: nowrap;
float: left;
overflow: hidden;
white-space: nowrap;
&.hacknet-node {
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
&.hacknet-node {
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1),
0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
margin: 6px;
padding: 7px;
width: 35vw;
border: 2px solid var(--my-highlight-color);
}
margin: 6px;
padding: 7px;
width: 35vw;
border: 2px solid var(--my-highlight-color);
}
}
#hacknet-nodes-list {
list-style: none;
width: 82vw;
list-style: none;
width: 82vw;
}
#hacknet-nodes-money {
margin: 10px;
float: left;
margin: 10px;
float: left;
}
#hacknet-nodes-money-multipliers-div {
display: inline-block;
width: 70vw;
display: inline-block;
width: 70vw;
}
#hacknet-nodes-multipliers {
float: right;
float: right;
}
#hacknet-nodes-purchase-button {
display: inline-block;
display: inline-block;
}
.hacknet-node-container {
display: inline-table;
display: inline-table;
.row {
display: table-row;
height: 30px;
.row {
display: table-row;
height: 30px;
p {
display: table-cell;
}
p {
display: table-cell;
}
}
.upgradable-info {
display: inline-block;
margin: 0 4px; /* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: $defaultFontSize * 4;
}
.upgradable-info {
display: inline-block;
margin: 0 4px; /* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: $defaultFontSize * 4;
}
}

@ -1,56 +1,61 @@
@import "theme";
.blinking-cursor {
font-weight: 100;
color: #2e3d48;
-webkit-animation: 1s cursorblink step-end infinite;
-moz-animation: 1s cursorblink step-end infinite;
-ms-animation: 1s cursorblink step-end infinite;
-o-animation: 1s cursorblink step-end infinite;
animation: 1s cursorblink step-end infinite;
font-weight: 100;
color: #2e3d48;
-webkit-animation: 1s cursorblink step-end infinite;
-moz-animation: 1s cursorblink step-end infinite;
-ms-animation: 1s cursorblink step-end infinite;
-o-animation: 1s cursorblink step-end infinite;
animation: 1s cursorblink step-end infinite;
}
@keyframes cursorblink {
from, to {
color: transparent;
}
50% {
color: $hacker-green;
}
from,
to {
color: transparent;
}
50% {
color: $hacker-green;
}
}
@-moz-keyframes cursorblink {
from, to {
color: transparent;
}
50% {
color: $hacker-green;
}
from,
to {
color: transparent;
}
50% {
color: $hacker-green;
}
}
@-webkit-keyframes cursorblink {
from, to {
color: transparent;
}
50% {
color: $hacker-green;
}
from,
to {
color: transparent;
}
50% {
color: $hacker-green;
}
}
@-ms-keyframes cursorblink {
from, to {
color: transparent;
}
50% {
color: $hacker-green;
}
from,
to {
color: transparent;
}
50% {
color: $hacker-green;
}
}
@-o-keyframes cursorblink {
from, to {
color: transparent;
}
50% {
color: $hacker-green;
}
from,
to {
color: transparent;
}
50% {
color: $hacker-green;
}
}

@ -3,88 +3,88 @@
/* interactivetutorial.css */
#interactive-tutorial-wrapper {
position: relative;
position: relative;
}
#interactive-tutorial-container {
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: 450px;
padding: 10px;
border: 5px solid #fff;
width: 23%;
overflow: hidden;
background-color: #444; /* Fallback color */
color: #fff;
display: none;
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: 450px;
padding: 10px;
border: 5px solid #fff;
width: 23%;
overflow: hidden;
background-color: #444; /* Fallback color */
color: #fff;
> strong {
background-color: #444;
}
> strong {
background-color: #444;
}
}
#interactive-tutorial-text {
padding: 4px;
margin: 4px;
color: #fff;
background-color: #444;
font-size: $defaultFontSize * 0.875;
max-height: 350px;
overflow-y: auto;
padding: 4px;
margin: 4px;
color: #fff;
background-color: #444;
font-size: $defaultFontSize * 0.875;
max-height: 350px;
overflow-y: auto;
}
#interactive-tutorial-exit,
#interactive-tutorial-next,
#interactive-tutorial-back {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
font-size: $defaultFontSize * 1.125;
font-weight: bold;
background-color: #000;
color: #aaa;
font-size: $defaultFontSize * 1.125;
font-weight: bold;
background-color: #000;
&:hover,
&:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
&:hover,
&:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
}
}
#interactive-tutorial-exit {
position: absolute;
bottom: 0;
left: 0;
padding: 4px;
position: absolute;
bottom: 0;
left: 0;
padding: 4px;
}
#interactive-tutorial-back {
float: left;
padding: 4px;
float: left;
padding: 4px;
}
#interactive-tutorial-next {
float: right;
padding: 4px;
float: right;
padding: 4px;
}
.interactive-tutorial-command {
background-color: #000;
color: $hacker-green;
white-space: nowrap;
background-color: #000;
color: $hacker-green;
white-space: nowrap;
}
.interactive-tutorial-code {
background-color: #272822;
color: white;
padding: 3px;
background-color: #272822;
color: white;
padding: 3px;
}
.interactive-tutorial-tab {
background-color: #555;
color: #e6e6e6;
padding: 3px;
box-shadow: 0 0 3px #000;
background-color: #555;
color: #e6e6e6;
padding: 3px;
box-shadow: 0 0 3px #000;
}

@ -3,109 +3,109 @@
@import "theme";
@include keyframes(LOADERSPINNER) {
0% {
#{$browser}transform: translate(-50%, -50%) rotate(0deg);
}
100% {
#{$browser}transform: translate(-50%, -50%) rotate(360deg);
}
0% {
#{$browser}transform: translate(-50%, -50%) rotate(0deg);
}
100% {
#{$browser}transform: translate(-50%, -50%) rotate(360deg);
}
}
@include keyframes(LOADERLABEL) {
0% {
opacity: 1.0;
#{$browser}transform: translate(-50%, -50%) scale(1.0);
}
5% {
opacity: 0.5;
#{$browser}transform: translate(-50%, -50%) scale(0.5);
}
95% {
opacity: 0.5;
#{$browser}transform: translate(-50%, -50%) scale(0.5);
}
100% {
opacity: 1.0;
#{$browser}transform: translate(-50%, -50%) scale(1.0);
}
0% {
opacity: 1;
#{$browser}transform: translate(-50%, -50%) scale(1);
}
5% {
opacity: 0.5;
#{$browser}transform: translate(-50%, -50%) scale(0.5);
}
95% {
opacity: 0.5;
#{$browser}transform: translate(-50%, -50%) scale(0.5);
}
100% {
opacity: 1;
#{$browser}transform: translate(-50%, -50%) scale(1);
}
}
.loaderoverlay {
$spinnerBoxSize: 200px;
$themeColor: #6f3;
$spinnerBoxSize: 200px;
$themeColor: #6f3;
position: absolute;
width: 100%;
height: 100%;
background: #000;
color: $themeColor;
%spinnerBox {
border: 20px solid rgba(0, 0, 0, 0);
border-top-color: $themeColor;
border-bottom-color: $themeColor;
border-radius: 1000px;
position: absolute;
width: 100%;
height: 100%;
background: #000;
color: $themeColor;
top: 50%;
left: 50%;
}
%spinnerBox {
border: 20px solid rgba(0, 0, 0, 0);
border-top-color: $themeColor;
border-bottom-color: $themeColor;
border-radius: 1000px;
position: absolute;
top: 50%;
left: 50%;
}
.loaderspinner:before,
.loaderspinner:after {
content: "";
}
.loaderspinner:before,
.loaderspinner:after {
content: "";
}
.loaderspinner {
@extend %spinnerBox;
@include animation(LOADERSPINNER 5s linear infinite);
.loaderspinner {
@extend %spinnerBox;
@include animation(LOADERSPINNER 5s linear infinite);
width: $spinnerBoxSize;
height: $spinnerBoxSize;
}
width: $spinnerBoxSize;
height: $spinnerBoxSize;
}
.loaderspinner:before {
@extend %spinnerBox;
@include animation(LOADERSPINNER 10s linear infinite);
.loaderspinner:before {
@extend %spinnerBox;
@include animation(LOADERSPINNER 10s linear infinite);
width: $spinnerBoxSize * 0.8;
height: $spinnerBoxSize * 0.8;
}
width: $spinnerBoxSize * 0.8;
height: $spinnerBoxSize * 0.8;
}
.loaderspinner:after {
@extend %spinnerBox;
@include animation(LOADERSPINNER 5s linear infinite);
.loaderspinner:after {
@extend %spinnerBox;
@include animation(LOADERSPINNER 5s linear infinite);
width: $spinnerBoxSize * 0.6;
height: $spinnerBoxSize * 0.6;
}
width: $spinnerBoxSize * 0.6;
height: $spinnerBoxSize * 0.6;
}
.loaderlabel {
@include animation(LOADERLABEL 5s linear infinite);
.loaderlabel {
@include animation(LOADERLABEL 5s linear infinite);
text-transform: uppercase;
font-family: sans-serif;
font-size: $defaultFontSize * 1.375;
font-weight: 700;
letter-spacing: 2px;
position: absolute;
top: 50%;
left: 50%;
}
text-transform: uppercase;
font-family: sans-serif;
font-size: $defaultFontSize * 1.375;
font-weight: 700;
letter-spacing: 2px;
position: absolute;
top: 50%;
left: 50%;
}
}
.killAllMessage {
position: absolute;
top: 95%;
left: 50%;
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
transform: translateX(-50%);
position: absolute;
top: 95%;
left: 50%;
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
transform: translateX(-50%);
}
.killAllMessageWrapperHidden {
display: none;
display: none;
}
.killAllMessageWrapperShow {
display: block;
display: block;
}

@ -6,130 +6,130 @@
*/
.mainmenu {
list-style-type: none;
margin: 0;
padding: 0;
width: 10%;
position: fixed;
height: 100%;
overflow: auto;
list-style-type: none;
margin: 0;
padding: 0;
width: 10%;
position: fixed;
height: 100%;
overflow: auto;
border: 0;
border-bottom: 1px solid #000;
border-radius: 0;
background-color: #333;
border: 0;
border-bottom: 1px solid #000;
border-radius: 0;
background-color: #333;
}
/* Default buttons */
.mainmenu > li a,
.mainmenu > li button {
display: block;
color: #e6e6e6;
background-color: #555;
padding: 12px 8px;
display: block;
color: #e6e6e6;
background-color: #555;
padding: 12px 8px;
text-decoration: none;
cursor: pointer;
width: 100%;
text-align: left;
text-decoration: none;
cursor: pointer;
width: 100%;
text-align: left;
}
.mainmenu.classic > li a,
.mainmenu.classic > li button {
padding: 16px;
padding: 16px;
}
.mainmenu.compact > li a,
.mainmenu.compact > li button {
display: block;
color: #e6e6e6;
background-color: #555;
display: block;
color: #e6e6e6;
background-color: #555;
text-decoration: none;
cursor: pointer;
width: 100%;
text-align: left;
padding: 4px;
text-decoration: none;
cursor: pointer;
width: 100%;
text-align: left;
padding: 4px;
}
/* Hovering makes them lighter */
.mainmenu > li a:hover,
.mainmenu > li a:hover:not(.active),
.mainmenu > li a:focus {
background-color: #777;
color: #fff;
background-color: #777;
color: #fff;
}
.mainmenu > li button:hover,
.mainmenu > li button:hover:not(.active) {
background-color: #777;
color: #fff;
background-color: #777;
color: #fff;
}
/* Panel headers can become active, and they are "lighter" than the rest */
.mainmenu > li a.active,
.mainmenu > li button.active {
background-color: #777;
color: #fff;
background-color: #777;
color: #fff;
}
.mainmenu > li a.active:hover,
.mainmenu > li button.active:hover {
background-color: #aaa;
background-color: #aaa;
}
#hacking-menu-header-li,
#character-menu-header-li,
#world-menu-header-li,
#help-menu-header-li {
position: relative;
position: relative;
}
/* Accordion Outline */
.mainmenu-accordion-header,
.mainmenu-accordion-header-compact {
outline: 2px solid #fff !important;
outline: 2px solid #fff !important;
}
.mainmenu-accordion-header-classic {
border: 2px solid #fff;
padding: 16px !important;
border: 2px solid #fff;
padding: 16px !important;
}
/* Plus and minus signs */
.mainmenu-accordion-header:after,
.mainmenu-accordion-header-compact:after {
content: '\02795';
float: right;
font-size: $defaultFontSize * 0.8125;
position: absolute;
bottom: 25%;
right: 3px;
color: transparent;
text-shadow: 0 0 0 #fff;
content: "\02795";
float: right;
font-size: $defaultFontSize * 0.8125;
position: absolute;
bottom: 25%;
right: 3px;
color: transparent;
text-shadow: 0 0 0 #fff;
}
.mainmenu-accordion-header-classic:after {
content: '\02795';
float: right;
font-size: $defaultFontSize * 0.8125;
color: #fff;
margin-left: 5px;
content: "\02795";
float: right;
font-size: $defaultFontSize * 0.8125;
color: #fff;
margin-left: 5px;
}
.mainmenu-accordion-header.opened,
.mainmenu-accordion-header-classic.opened,
.mainmenu-accordion-header-compact.opened {
background-color: #222 !important;
background-color: #222 !important;
&:after {
content: "\2796";
}
&:after {
content: "\2796";
}
}
/* Slide down transition */
.mainmenu-accordion-panel {
max-height: 0;
opacity: 1;
transition: max-height 0.2s ease-out;
max-height: 0;
opacity: 1;
transition: max-height 0.2s ease-out;
}

@ -5,151 +5,151 @@
terminal which has its own page) */
.generic-menupage-container {
height: 100%;
padding-left: 10px;
margin-left: 10%;
width: 99%;
overflow-y: scroll;
height: 100%;
padding-left: 10px;
margin-left: 10%;
width: 99%;
overflow-y: scroll;
}
/* Character Info */
#character-container {
padding-top: 10px;
position: fixed;
padding-top: 10px;
position: fixed;
}
/* World */
#world-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#world-city-name,
#world-city-desc {
padding: 4px;
margin: 4px;
padding: 4px;
margin: 4px;
}
/* Create program */
#create-program-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#create-program-page-text,
#create-program-list {
width: 70%;
width: 70%;
}
/* Factions and Faction (Single Faction page) */
#factions-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#faction-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
.faction-work-div {
width: 70%;
height: 100%;
width: 70%;
height: 100%;
}
.faction-work-div-wrapper {
overflow: hidden;
border: 2px solid #333;
padding: 6px;
margin: 6px;
width: 70%;
overflow: hidden;
border: 2px solid #333;
padding: 6px;
margin: 6px;
width: 70%;
}
#faction-container p,
#faction-container pre {
padding: 4px 6px;
margin: 4px 6px;
padding: 4px 6px;
margin: 4px 6px;
}
#faction-container pre {
width: 70%;
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
width: 70%;
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
/* World */
#world-container li {
margin: 0 0 15px 0;
list-style-type: none;
margin: 0 0 15px 0;
list-style-type: none;
}
/* Tutorial */
#tutorial-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#tutorial-text {
width: 70%;
margin: 10px;
width: 70%;
margin: 10px;
}
#tutorial-container a {
width: 50%;
width: 50%;
}
/* Dev menu */
#dev-menu-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#dev-menu-text {
width: 70%;
margin: 10px;
width: 70%;
margin: 10px;
}
#dev-menu-container a {
width: 50%;
width: 50%;
}
/* Location */
#location-container {
position: fixed;
padding: 6px;
overflow-x: hidden;
position: fixed;
padding: 6px;
overflow-x: hidden;
}
#location-container a {
display: inline-block;
width: 30%;
display: inline-block;
width: 30%;
}
#location-slums-description {
width: 70%;
margin: 10px;
width: 70%;
margin: 10px;
}
#location-return-to-world-button {
margin: 10px;
padding: 6px;
margin: 10px;
padding: 6px;
}
#location-container > * {
margin: 10px 5px 10px 5px;
margin: 10px 5px 10px 5px;
}
#location-job-reputation,
#location-company-favor {
display: inline;
display: inline;
}
/* Infiltration */
#infiltration-container {
position: fixed;
margin: 5px;
width: 70%;
position: fixed;
margin: 5px;
width: 70%;
}

@ -1,5 +1,5 @@
#milestones-container {
position: fixed;
padding: 6px;
width: 60%;
position: fixed;
padding: 6px;
width: 60%;
}

@ -5,115 +5,115 @@
/* Hacking missions */
#mission-container {
overflow: hidden;
overflow: hidden;
}
.hack-mission-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-gap: 2.5%;
height: 90%;
position: absolute;
width: 100%;
overflow-y: auto;
padding-right: 10px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-gap: 2.5%;
height: 90%;
position: absolute;
width: 100%;
overflow-y: auto;
padding-right: 10px;
&::-webkit-scrollbar {
display: none;
}
&::-webkit-scrollbar {
display: none;
}
}
.hack-mission-node {
z-index: 5;
background-color: #808080;
align-self: center;
justify-self: center;
display: inline-block;
z-index: 5;
background-color: #808080;
align-self: center;
justify-self: center;
display: inline-block;
p {
@include userSelect(none);
p {
@include userSelect(none);
margin-top: 8px;
color: #fff;
font-size: $defaultFontSize * 0.75;
text-align: center;
}
margin-top: 8px;
color: #fff;
font-size: $defaultFontSize * 0.75;
text-align: center;
}
}
.hack-mission-player-node {
color: #fff;
background-color: #00f;
color: #fff;
background-color: #00f;
}
.hack-mission-player-node-active {
border: 2px solid #fff;
background-color: #66f;
border: 2px solid #fff;
background-color: #66f;
}
.hack-mission-enemy-node {
color: #fff;
background-color: #f00;
color: #fff;
background-color: #f00;
}
.hack-mission-cpu-node {
@include borderRadius(50%);
width: 100%;
height: 100%;
@include borderRadius(50%);
width: 100%;
height: 100%;
}
.hack-mission-firewall-node {
width: 90%;
height: 100%;
width: 90%;
height: 100%;
}
.hack-mission-database-node {
@include transform(skew(20deg));
@include transform(skew(20deg));
width: 100%;
height: 90%;
width: 100%;
height: 90%;
p {
@include transform(skew(-20deg));
@include userSelect(none);
p {
@include transform(skew(-20deg));
@include userSelect(none);
color: #fff;
font-size: $defaultFontSize * 0.75;
margin-top: 8px;
text-align: center;
}
color: #fff;
font-size: $defaultFontSize * 0.75;
margin-top: 8px;
text-align: center;
}
}
.hack-mission-transfer-node {
@include transform(skew(-20deg));
@include transform(skew(-20deg));
width: 100%;
height: 90%;
width: 100%;
height: 90%;
p {
@include transform(skew(20deg));
@include userSelect(none);
p {
@include transform(skew(20deg));
@include userSelect(none);
color: #fff;
font-size: $defaultFontSize * 0.75;
margin-top: 8px;
text-align: center;
}
color: #fff;
font-size: $defaultFontSize * 0.75;
margin-top: 8px;
text-align: center;
}
}
.hack-mission-spam-node,
.hack-mission-shield-node {
height: 100%;
width: 100%;
height: 100%;
width: 100%;
}
/* Non-map related DOM elements */
/* Element at the top of the Hacking Mission page (intro page, start button, guide buttons, etc.) */
.hack-mission-header-element {
margin: 6px;
margin: 6px;
}
.hack-mission-action-buttons-container {
border: 2px solid #fff;
border: 2px solid #fff;
}

@ -4,240 +4,241 @@
/* Pop-up boxes */
.popup-box-container {
display: none; /* Initially hidden */
position: fixed; /* Stay in place */
z-index: 10; /* Sit on top */
left: 0;
top: 0;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: rbga(var(--my-background-color), 0.4);
display: none; /* Initially hidden */
position: fixed; /* Stay in place */
z-index: 10; /* Sit on top */
left: 0;
top: 0;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: rbga(var(--my-background-color), 0.4);
}
.popup-box-content {
background-color: var(--my-background-color);
padding: 12px;
border: 5px solid var(--my-highlight-color);
width: 70%;
max-height: 80%;
overflow-y: auto;
z-index: 11; /* Sit on top of the container */
color: var(--my-font-color);
background-color: var(--my-background-color);
padding: 12px;
border: 5px solid var(--my-highlight-color);
width: 70%;
max-height: 80%;
overflow-y: auto;
z-index: 11; /* Sit on top of the container */
color: var(--my-font-color);
}
.popup-box-button,
.popup-box-button-inactive {
color: #aaa;
float: right;
font-size: $defaultFontSize;
font-weight: bold;
padding: 2px;
margin: 6px;
border: 1px solid #fff;
background-color: #000;
color: #aaa;
float: right;
font-size: $defaultFontSize;
font-weight: bold;
padding: 2px;
margin: 6px;
border: 1px solid #fff;
background-color: #000;
}
.popup-box-button:hover,
.popup-box-button:focus {
color: var(--my-font-color);
text-decoration: none;
cursor: pointer;
color: var(--my-font-color);
text-decoration: none;
cursor: pointer;
}
.popupbox-button-inactive {
pointer-events: none;
cursor: default;
pointer-events: none;
cursor: default;
}
#yes-no-text-input-box-input {
color: var(--my-font-color);
border: 1px solid #fff;
background-color: #000;
color: var(--my-font-color);
border: 1px solid #fff;
background-color: #000;
}
.dialog-box-container {
display: block;
position: absolute;
z-index: 10;
width: 50%;
height: auto;
max-height: 50%;
top: 40%;
left: 50%;
margin: -10% 0 0 -25%;
overflow: auto;
background-color: var(--my-background-color);
border: 5px solid var(--my-highlight-color);
display: block;
position: absolute;
z-index: 10;
width: 50%;
height: auto;
max-height: 50%;
top: 40%;
left: 50%;
margin: -10% 0 0 -25%;
overflow: auto;
background-color: var(--my-background-color);
border: 5px solid var(--my-highlight-color);
}
.log-box-container {
display: flex;
flex-flow: column;
background-color: gray;
width: 50%;
position: absolute;
left: 50%;
top: 40%;
margin: -10% 0 0 -25%;
height: auto;
max-height: 50%;
z-index: 10;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
display: flex;
flex-flow: column;
background-color: gray;
width: 50%;
position: absolute;
left: 50%;
top: 40%;
margin: -10% 0 0 -25%;
height: auto;
max-height: 50%;
z-index: 10;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
}
.log-box-header {
background-color: #333;
border: 1px solid var(--my-highlight-color);
display: flex;
flex: row nowrap;
align-items: center;
justify-content: space-between;
background-color: #333;
border: 1px solid var(--my-highlight-color);
display: flex;
flex: row nowrap;
align-items: center;
justify-content: space-between;
}
.log-box-log-container {
overflow-y: auto;
overflow-y: auto;
}
.log-box-button {
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
padding: 2px;
margin: 6px;
border: 1px solid #fff;
background-color: #000;
color: #aaa;
font-size: $defaultFontSize;
font-weight: bold;
padding: 2px;
margin: 6px;
border: 1px solid #fff;
background-color: #000;
}
.log-box-button:hover,
.log-box-button:focus {
color: var(--my-font-color);
text-decoration: none;
cursor: pointer;
color: var(--my-font-color);
text-decoration: none;
cursor: pointer;
}
.dialog-box-content {
z-index: 2;
background-color: var(--my-background-color);
padding: 10px;
z-index: 2;
background-color: var(--my-background-color);
padding: 10px;
p span {
padding: 0;
margin: 0;
}
p span {
padding: 0;
margin: 0;
}
}
.dialog-box-close-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
@extend .noselect;
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
@extend .noselect;
float: right;
color: #aaa;
font-size: $defaultFontSize * 1.25;
font-weight: bold;
float: right;
color: #aaa;
font-size: $defaultFontSize * 1.25;
font-weight: bold;
}
#log-box-close {
position: fixed;
right: 27%;
position: fixed;
right: 27%;
}
#log-box-kill-script {
right: 11%;
position: relative;
right: 11%;
position: relative;
}
#log-box-close, #log-box-kill-script {
float: right;
display: inline-block;
#log-box-close,
#log-box-kill-script {
float: right;
display: inline-block;
}
.dialog-box-close-button:hover,
.dialog-box-close-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
color: #fff;
text-decoration: none;
cursor: pointer;
}
/* Faction invitation box */
#faction-invitation-box-container {
transition: opacity 400ms ease-in;
transition: opacity 400ms ease-in;
}
#faction-invitation-box-warning {
margin: 4px;
padding: 4px;
margin: 4px;
padding: 4px;
}
/* Infiltration-box */
#infiltration-box-sell,
#infiltration-box-faction {
display: block;
padding: 8px;
margin: 8px;
display: block;
padding: 8px;
margin: 8px;
}
#infiltration-box-content span {
padding: 0;
margin: 0;
padding: 0;
margin: 0;
}
#infiltration-faction-select {
background-color: #000;
background-color: #000;
}
/* Generic Yes No Box */
#yes-no-text-input-box-input {
color: #fff;
color: #fff;
}
/* Game Options */
#game-options-container {
transition: opacity 400ms ease-in;
transition: opacity 400ms ease-in;
}
#game-options-content {
background-color: var(--my-background-color);
padding: 10px;
border: 5px solid var(--my-highlight-color);
color: var(--my-font-color);
width: 80%;
max-height: 80%;
overflow-y: auto;
background-color: var(--my-background-color);
padding: 10px;
border: 5px solid var(--my-highlight-color);
color: var(--my-font-color);
width: 80%;
max-height: 80%;
overflow-y: auto;
}
#game-options-left-panel,
#game-options-right-panel {
display: inline-block;
width: 49%;
display: inline-block;
width: 49%;
}
#game-options-close-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
float: right;
margin: 4px;
padding: 4px;
font-size: $defaultFontSize * 1.25;
font-weight: bold;
color: #aaa;
float: right;
margin: 4px;
padding: 4px;
font-size: $defaultFontSize * 1.25;
font-weight: bold;
}
#game-options-close-button:hover,
#game-options-close-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
color: #fff;
text-decoration: none;
cursor: pointer;
}
#game-options-left-panel fieldset {
padding: 2px;
margin: 2px;
padding: 2px;
margin: 2px;
}
#import-game-file-selector {
display: none;
display: none;
}

@ -4,31 +4,31 @@
* Styling for the Red Pill screen (the BitNode selection UI)
*/
#red-pill-container {
position: fixed;
position: fixed;
}
.bitnode {
&.level-0 {
color: red;
}
&.level-0 {
color: red;
}
&.level-1 {
color: yellow;
}
&.level-1 {
color: yellow;
}
&.level-2 {
color: #48d1cc;
}
&.level-2 {
color: #48d1cc;
}
&.level-3 {
color: blue;
}
&.level-3 {
color: blue;
}
&.unimplemented {
color: gray;
}
&.unimplemented {
color: gray;
}
&:hover {
color: #fff;
}
&:hover {
color: #fff;
}
}

@ -4,25 +4,25 @@
@import "theme";
.resleeve-container {
border: 1px solid white;
margin: 4px;
width: 75%;
border: 1px solid white;
margin: 4px;
width: 75%;
p {
font-size: $defaultFontSize * 0.8125;
}
p {
font-size: $defaultFontSize * 0.8125;
}
}
.resleeve-panel {
display: inline-block;
margin: 0;
padding: 2px;
display: inline-block;
margin: 0;
padding: 2px;
}
.resleeve-aug-selector {
font-size: $defaultFontSize * 0.8125;
font-size: $defaultFontSize * 0.8125;
option {
font-size: $defaultFontSize * 0.8125;
}
option {
font-size: $defaultFontSize * 0.8125;
}
}

@ -6,102 +6,102 @@
*/
#script-editor-container {
background-color: transparent;
background-color: transparent;
}
/* This temp element is used for auto adjusting filename field */
.tmp-element {
visibility: hidden;
white-space: pre;
visibility: hidden;
white-space: pre;
}
#script-editor-container {
position: fixed;
padding-top: 10px;
position: fixed;
padding-top: 10px;
}
#script-editor-buttons-wrapper {
width: 100%;
padding-right: 0;
margin-right: 0;
width: 100%;
padding-right: 0;
margin-right: 0;
}
#script-editor-wrapper {
height: 100%;
width: 70%;
background: transparent;
height: 100%;
width: 70%;
background: transparent;
}
#script-editor-filename-wrapper {
background-color: #555;
margin-right: 0;
padding-left: 6px;
width: 100%;
border: 2px solid var(--my-highlight-color);
background-color: #555;
margin-right: 0;
padding-left: 6px;
width: 100%;
border: 2px solid var(--my-highlight-color);
}
#script-editor-filename-tag {
display: inline-block;
padding-top: 10px;
padding-bottom: 0;
float: center;
background-color: #555;
color: #fff;
display: inline-block;
padding-top: 10px;
padding-bottom: 0;
float: center;
background-color: #555;
color: #fff;
}
#script-editor-filename {
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
$boxShadowArgs: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
@include boxShadow($boxShadowArgs);
background-color: #555;
border: 2px solid var(--my-highlight-color);
color: #fff;
display: inline-block;
float: center;
margin: 4px;
padding: 2px;
resize: none;
width: 60%;
background-color: #555;
border: 2px solid var(--my-highlight-color);
color: #fff;
display: inline-block;
float: center;
margin: 4px;
padding: 2px;
resize: none;
width: 60%;
}
#script-editor-status {
float: left;
color: #fff;
float: left;
color: #fff;
}
#script-editor-options-panel {
position: absolute;
right: 9%;
bottom: 15%;
border: 2px solid #fff;
width: 19%;
background-color: #444;
padding: 2px;
overflow: auto;
z-index: 1;
color: #fff;
max-height: 50%;
position: absolute;
right: 9%;
bottom: 15%;
border: 2px solid #fff;
width: 19%;
background-color: #444;
padding: 2px;
overflow: auto;
z-index: 1;
color: #fff;
max-height: 50%;
}
#script-editor-options-panel fieldset {
margin-top: 8px;
margin-bottom: 8px;
padding: 2px;
font-size: $defaultFontSize * 0.75;
margin-top: 8px;
margin-bottom: 8px;
padding: 2px;
font-size: $defaultFontSize * 0.75;
input {
margin: 2px;
}
input {
margin: 2px;
}
}
.editor-options-container {
display: flex;
flex-flow: column;
display: flex;
flex-flow: column;
}
.editor-options-line {
display: flex;
flex: row nowrap;
align-items: center;
justify-content: start;
display: flex;
flex: row nowrap;
align-items: center;
justify-content: start;
}

@ -4,26 +4,26 @@
@import "theme";
.sleeve-container {
border: 1px solid white;
margin: 4px;
width: 75%;
border: 1px solid white;
margin: 4px;
width: 75%;
p {
font-size: $defaultFontSize * 0.875;
}
p {
font-size: $defaultFontSize * 0.875;
}
}
.sleeves-page-info {
display: "block";
width: 75%;
display: "block";
width: 75%;
}
.sleeve-panel {
display: inline-block;
margin: 0;
padding: 2px;
display: inline-block;
margin: 0;
padding: 2px;
select {
display: block;
}
select {
display: block;
}
}

@ -1,98 +1,99 @@
@import "theme";
#stock-market-container {
position: fixed;
padding: 6px;
position: fixed;
padding: 6px;
p {
font-size: $defaultFontSize * 0.8125;
}
p {
font-size: $defaultFontSize * 0.8125;
}
a {
font-size: $defaultFontSize * 0.875;
}
a {
font-size: $defaultFontSize * 0.875;
}
}
.stock-market-info-and-purchases {
> h2 {
display: block;
margin-top: 10px;
margin-left: 10px;
}
> h2 {
display: block;
margin-top: 10px;
margin-left: 10px;
}
> p {
display: block;
margin-left: 10px;
width: 70%;
}
> p {
display: block;
margin-left: 10px;
width: 70%;
}
> a, > button {
margin: 10px;
}
> a,
> button {
margin: 10px;
}
}
#stock-market-list {
list-style: none;
list-style: none;
li {
button {
font-size: $defaultFontSize;
}
li {
button {
font-size: $defaultFontSize;
}
}
}
#stock-market-watchlist-filter {
display: block;
margin: 5px 5px 5px 10px;
padding: 4px;
width: 50%;
display: block;
margin: 5px 5px 5px 10px;
padding: 4px;
width: 50%;
}
.stock-market-input {
display: inline-block;
padding: 4px;
margin: 2px;
background-color: #000;
border: 1px solid #fff;
color: var(--my-font-color);
display: inline-block;
padding: 4px;
margin: 2px;
background-color: #000;
border: 1px solid #fff;
color: var(--my-font-color);
}
.stock-market-price-movement-warning {
border: 1px solid white;
color: red;
margin: 2px;
padding: 2px;
border: 1px solid white;
color: red;
margin: 2px;
padding: 2px;
}
.stock-market-position-text {
color: #fff;
display: block;
p {
color: #fff;
display: block;
display: inline-block;
margin: 4px;
}
p {
color: #fff;
display: inline-block;
margin: 4px;
}
h3 {
margin: 4px;
}
h3 {
margin: 4px;
}
}
.stock-market-order-list {
overflow-y: auto;
max-height: 100px;
overflow-y: auto;
max-height: 100px;
li {
color: #fff;
padding: 4px;
}
li {
color: #fff;
padding: 4px;
}
}
.stock-market-order-cancel-btn {
background-color: #000;
border: 1px solid #fff;
color: var(--my-font-color);
margin: 2px;
padding: 0;
background-color: #000;
border: 1px solid #fff;
color: var(--my-font-color);
margin: 2px;
padding: 0;
}

@ -4,14 +4,14 @@
@import "reset";
:root {
--my-font-color: #6f3;
--my-background-color: #000;
--my-highlight-color: #fff;
--my-prompt-color: #f92672;
--my-font-color: #6f3;
--my-background-color: #000;
--my-highlight-color: #fff;
--my-prompt-color: #f92672;
}
body {
background-color: var(--my-background-color);
background-color: var(--my-background-color);
}
p,
@ -21,29 +21,29 @@ h3,
h4,
.text,
td {
color: var(--my-font-color);
color: var(--my-font-color);
}
h1 {
font-size: $defaultFontSize * 1.375;
color: var(--my-font-color);
font-size: $defaultFontSize * 1.375;
color: var(--my-font-color);
}
ul {
padding: 2px;
list-style-type: none;
padding: 2px;
list-style-type: none;
}
li {
list-style-type: none;
list-style-type: none;
}
br {
@extend .noselect;
@extend .noselect;
}
#entire-game-container {
background-color: transparent;
background-color: transparent;
}
/* Disable border highlight on elements */
@ -52,383 +52,452 @@ textarea:focus,
button:focus,
td:focus,
tr:focus {
outline: none;
outline: none;
}
/* Make html links ("a" elements) nice looking buttons with this class */
a:link,
a:visited {
color: #fff;
color: #fff;
}
.dropdown {
color: #fff;
background-color: #000;
color: #fff;
background-color: #000;
}
.text-input {
color: #fff;
background-color: #000;
border-style: solid;
border-width: 1px;
border-color: white;
color: #fff;
background-color: #000;
border-style: solid;
border-width: 1px;
border-color: white;
}
/* Notification icon (for create program right now only) */
#create-program-tab {
position: relative;
position: relative;
}
#create-program-notification {
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
}
#factions-tab {
position: relative;
position: relative;
}
#factions-notification {
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
}
#augmentations-tab {
position: relative;
position: relative;
}
#augmentations-notification {
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
font-size: $defaultFontSize * 0.625;
position: absolute; /* Position the badge within the relatively positioned button */
top: 0;
right: 0;
}
.notification-on {
background-color: #fa3e3e;
color: #fff;
border-radius: 2px;
padding: 1px 3px;
background-color: #fa3e3e;
color: #fff;
border-radius: 2px;
padding: 1px 3px;
}
.notification-off {
background-color: #333;
color: #333;
border-radius: 0;
padding: 0;
background-color: #333;
color: #333;
border-radius: 0;
padding: 0;
}
/* help tip. Question mark that opens popup with info/details */
.help-tip {
background-color: black;
border: 1px solid #fff;
border-radius: 5px;
color: #fff;
content: '?';
display: inline-block;
margin-left: 3px;
padding: 1px;
background-color: black;
border: 1px solid #fff;
border-radius: 5px;
color: #fff;
content: "?";
display: inline-block;
margin-left: 3px;
padding: 1px;
}
.help-tip-big {
content: '?';
padding: 3px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff;
border-radius: 8px;
display: inline-block;
content: "?";
padding: 3px;
margin-left: 3px;
color: #fff;
border: 1px solid #fff;
border-radius: 8px;
display: inline-block;
}
.help-tip:hover,
.help-tip-big:hover {
background-color: #888;
background-color: #888;
}
.help-tip:active,
.help-tip-big:active {
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
@include boxShadow(inset 0 1px 4px rgba(0, 0, 0, 0.6));
}
/* Flashing button (Red) */
@-webkit-keyframes glowing {
0% { background-color: #b20000; -webkit-box-shadow: 0 0 3px #b20000; }
50% { background-color: #f00; -webkit-box-shadow: 0 0 40px #f00; }
100% { background-color: #b20000; -webkit-box-shadow: 0 0 3px #b20000; }
0% {
background-color: #b20000;
-webkit-box-shadow: 0 0 3px #b20000;
}
50% {
background-color: #f00;
-webkit-box-shadow: 0 0 40px #f00;
}
100% {
background-color: #b20000;
-webkit-box-shadow: 0 0 3px #b20000;
}
}
@-moz-keyframes glowing {
0% { background-color: #b20000; -moz-box-shadow: 0 0 3px #b20000; }
50% { background-color: #f00; -moz-box-shadow: 0 0 40px #f00; }
100% { background-color: #b20000; -moz-box-shadow: 0 0 3px #b20000; }
0% {
background-color: #b20000;
-moz-box-shadow: 0 0 3px #b20000;
}
50% {
background-color: #f00;
-moz-box-shadow: 0 0 40px #f00;
}
100% {
background-color: #b20000;
-moz-box-shadow: 0 0 3px #b20000;
}
}
@-o-keyframes glowing {
0% { background-color: #b20000; box-shadow: 0 0 3px #b20000; }
50% { background-color: #f00; box-shadow: 0 0 40px #f00; }
100% { background-color: #b20000; box-shadow: 0 0 3px #b20000; }
0% {
background-color: #b20000;
box-shadow: 0 0 3px #b20000;
}
50% {
background-color: #f00;
box-shadow: 0 0 40px #f00;
}
100% {
background-color: #b20000;
box-shadow: 0 0 3px #b20000;
}
}
@keyframes glowing {
0% { background-color: #b20000; box-shadow: 0 0 3px #b20000; }
50% { background-color: #f00; box-shadow: 0 0 40px #f00; }
100% { background-color: #b20000; box-shadow: 0 0 3px #b20000; }
0% {
background-color: #b20000;
box-shadow: 0 0 3px #b20000;
}
50% {
background-color: #f00;
box-shadow: 0 0 40px #f00;
}
100% {
background-color: #b20000;
box-shadow: 0 0 3px #b20000;
}
}
.flashing-button {
-webkit-animation: glowing 1500ms infinite;
-moz-animation: glowing 1500ms infinite;
-o-animation: glowing 1500ms infinite;
animation: glowing 1500ms infinite;
-webkit-animation: glowing 1500ms infinite;
-moz-animation: glowing 1500ms infinite;
-o-animation: glowing 1500ms infinite;
animation: glowing 1500ms infinite;
}
/* Blinking Cursor */
/* ----- blinking cursor animation ----- */
.typed-cursor {
opacity: 1;
-webkit-animation: blink 0.95s infinite;
-moz-animation: blink 0.95s infinite;
-ms-animation: blink 0.95s infinite;
-o-animation: blink 0.95s infinite;
animation: blink 0.95s infinite;
opacity: 1;
-webkit-animation: blink 0.95s infinite;
-moz-animation: blink 0.95s infinite;
-ms-animation: blink 0.95s infinite;
-o-animation: blink 0.95s infinite;
animation: blink 0.95s infinite;
}
@-keyframes blink{
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
@-keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@-webkit-keyframes blink{
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
@-webkit-keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@-moz-keyframes blink{
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
@-moz-keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@-ms-keyframes blink{
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
@-ms-keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@-o-keyframes blink{
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
@-o-keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* Status text */
@-webkit-keyframes status-text {
from {
opacity: 1;
}
to {
opacity: 0;
}
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.status-text {
z-index: 2;
-webkit-animation: status-text 3s 1;
z-index: 2;
-webkit-animation: status-text 3s 1;
}
#status-text-container {
background-color: transparent;
position: absolute;
top: 0;
left: 50%;
background-color: transparent;
position: absolute;
top: 0;
left: 50%;
}
#status-text {
background-color: transparent;
bottom: 0;
color: #fff;
display: none;
font-size: $defaultFontSize * 1.25;
margin-right: 14px;
opacity: 0;
padding: 4px;
right: 0;
top: 0;
width: auto;
background-color: transparent;
bottom: 0;
color: #fff;
display: none;
font-size: $defaultFontSize * 1.25;
margin-right: 14px;
opacity: 0;
padding: 4px;
right: 0;
top: 0;
width: auto;
}
/* Scan analyze links from AutoLink */
.scan-analyze-link {
cursor: pointer;
color: #fff;
text-decoration: underline;
cursor: pointer;
color: #fff;
text-decoration: underline;
&:hover {
text-decoration: none;
}
&:hover {
text-decoration: none;
}
}
/* Accordion menus (Header with collapsible panel) */
.accordion-header {
background-color: #444;
color: #fff;
font-size: $defaultFontSize * 1.25;
margin: 6px 6px 0 6px;
padding: 4px 6px;
cursor: pointer;
width: 80%;
text-align: left;
border: none;
outline: none;
position: relative;
background-color: #444;
color: #fff;
font-size: $defaultFontSize * 1.25;
margin: 6px 6px 0 6px;
padding: 4px 6px;
cursor: pointer;
width: 80%;
text-align: left;
border: none;
outline: none;
position: relative;
&.active,
&:hover {
background-color: #555;
}
&.active,
&:hover {
background-color: #555;
}
&.active:hover {
background-color: #666;
}
&.active:hover {
background-color: #666;
}
&:after {
content: '\02795'; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.875;
float: right;
color: transparent;
text-shadow: 0 0 0 #fff;
position: absolute;
bottom: 5px;
right: 6px;
}
&:after {
content: "\02795"; /* "plus" sign (+) */
font-size: $defaultFontSize * 0.875;
float: right;
color: transparent;
text-shadow: 0 0 0 #fff;
position: absolute;
bottom: 5px;
right: 6px;
}
&.active:after {
content: "\2796"; /* "minus" sign (-) */
}
&.active:after {
content: "\2796"; /* "minus" sign (-) */
}
}
.accordion-panel {
margin: 0 6px 6px 6px;
padding: 0 6px 6px 6px;
width: 75%;
margin-left: 5%;
display: none;
background-color: #555;
overflow-y: auto;
overflow-x: none;
margin: 0 6px 6px 6px;
padding: 0 6px 6px 6px;
width: 75%;
margin-left: 5%;
display: none;
background-color: #555;
overflow-y: auto;
overflow-x: none;
div, ul, p, ul > li {
background-color: #555;
}
div,
ul,
p,
ul > li {
background-color: #555;
}
}
/* override the global <span> styling */
#active-scripts-total-production-active,
#active-scripts-total-prod-aug-total,
#active-scripts-total-prod-aug-avg {
margin: 0;
padding: 0;
margin: 0;
padding: 0;
}
/* Helper Classes */
.hacker-green {
color: $hacker-green;
color: $hacker-green;
}
.money-gold {
color: $money-gold;
color: $money-gold;
}
.light-yellow {
color: $light-yellow;
color: $light-yellow;
}
.unbuyable {
color: #66cfbc;
color: #66cfbc;
}
.failure {
color: $alert-red;
text-shadow: 0 0 0 $alert-red;
color: $alert-red;
text-shadow: 0 0 0 $alert-red;
}
.success {
color: $success-green;
text-shadow: 0 0 0 $success-green;
color: $success-green;
text-shadow: 0 0 0 $success-green;
}
.physical-yellow {
color: $my-stat-physical;
color: $my-stat-physical;
}
.charisma-purple {
color: $my-stat-cha-color;
color: $my-stat-cha-color;
}
.reputation {
color: $light-yellow;
color: $light-yellow;
}
.smallfont {
font-size: $defaultFontSize * 0.8125;
font-size: $defaultFontSize * 0.8125;
}
.samefont {
font-size: inherit;
font-size: inherit;
}
.noscrollbar {
-ms-overflow-style: none; /* IE and Edge */
/* stylelint-disable-next-line property-no-unknown */
scrollbar-width: none; /* Firefox https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width */
-ms-overflow-style: none; /* IE and Edge */
/* stylelint-disable-next-line property-no-unknown */
scrollbar-width: none; /* Firefox https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width */
}
.noscrollbar::-webkit-scrollbar {
display: none;
display: none;
}
input[type="checkbox"] {
filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10);
filter: invert(1) sepia(1) hue-rotate(41deg) brightness(100%) saturate(10);
}
.optionCheckbox {
margin: 5px;
float: right;
margin: 5px;
float: right;
}
.optionRange {
-webkit-appearance: none;
background: #777;
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: 0.2s;
transition: opacity 0.2s;
margin: 3px;
-webkit-appearance: none;
background: #777;
outline: none;
opacity: 0.7;
height: 10px;
-webkit-transition: 0.2s;
transition: opacity 0.2s;
margin: 3px;
}
.optionRange::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
}
.optionRange::-moz-range-thumb {
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
width: 10px;
height: 10px;
background: var(--my-font-color);
cursor: pointer;
}
.noselect {
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}

@ -1,72 +1,72 @@
@import "theme";
#terminal-container {
position: fixed;
margin-left: 10%;
height: 100%;
width: 99%;
overflow: auto;
overflow-y: scroll;
position: fixed;
margin-left: 10%;
height: 100%;
width: 99%;
overflow: auto;
overflow-y: scroll;
}
#terminal {
padding-top: 10px;
padding-left: 10px;
height: auto;
width: 70%;
font-size: $defaultFontSize;
overflow: auto;
overflow-y: scroll;
background-color: var(--my-background-color);
table-layout: fixed;
padding-top: 10px;
padding-left: 10px;
height: auto;
width: 70%;
font-size: $defaultFontSize;
overflow: auto;
overflow-y: scroll;
background-color: var(--my-background-color);
table-layout: fixed;
.prompt {
color: var(--my-prompt-color);
margin: 0;
padding: 0;
}
.prompt {
color: var(--my-prompt-color);
margin: 0;
padding: 0;
}
}
#terminal-input {
background-color: var(--my-background-color);
color: var(--my-font-color);
transition: height 1s;
background-color: var(--my-background-color);
color: var(--my-font-color);
transition: height 1s;
}
.terminal-input {
display: inline-block;
padding: 0 !important;
margin: 0 !important;
border: 0;
background-color: var(--my-background-color);
font-size: $defaultFontSize;
outline: none;
color: var(--my-font-color);
display: inline-block;
padding: 0 !important;
margin: 0 !important;
border: 0;
background-color: var(--my-background-color);
font-size: $defaultFontSize;
outline: none;
color: var(--my-font-color);
}
.terminal-line {
width: 70%;
word-wrap: break-word;
hyphens: auto;
-webkit-hyphens: auto;
-moz-hyphens: auto;
width: 70%;
word-wrap: break-word;
hyphens: auto;
-webkit-hyphens: auto;
-moz-hyphens: auto;
}
#terminal-input-td {
display: flex;
display: flex;
}
#terminal-input-td textarea {
overflow: hidden;
resize: none;
height: auto;
overflow: hidden;
resize: none;
height: auto;
}
#terminal-input-header {
white-space: pre;
white-space: pre;
}
#terminal-input-text-box {
margin-left: 2px;
flex: 1 1 auto;
margin-left: 2px;
flex: 1 1 auto;
}

@ -4,67 +4,10 @@
/* Tool tips (when hovering over an element */
.tooltip {
display: inline-block;
position: relative;
display: inline-block;
position: relative;
.tooltiptext {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
}
/* Positioned to left of element rather than right */
.tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99;
}
/* Tooltip goes below cursor instead of above */
.tooltiptextlow {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
bottom: 25%;
}
}
/* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh {
.tooltiptext {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
@ -73,57 +16,114 @@
text-align: center;
padding: 4px;
left: 101%;
bottom: -25%;
pointer-events: none;
position: absolute;
z-index: 99;
}
/* Positioned to left of element rather than right */
.tooltiptextleft {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
top: 50%;
left: 50%;
transform: translate(-100%, -100%);
/* Backwards compatibility */
-webkit-transform: translate(-100%, -100%);
-moz-transform: translate(-100%, -100%);
-o-transform: translate(-100%, -100%);
-ms-transform: translate(-100%, -100%);
position: absolute;
z-index: 99;
}
/* Tooltip goes below cursor instead of above */
.tooltiptextlow {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
pointer-events: none;
position: absolute;
z-index: 99;
bottom: 25%;
}
}
/* Same thing as a normal tooltip except its a bit higher */
.tooltip .tooltiptexthigh {
visibility: hidden;
width: 300px;
background-color: var(--my-background-color);
border: 2px solid var(--my-highlight-color);
color: #fff;
text-align: center;
padding: 4px;
left: 101%;
bottom: -25%;
position: absolute;
z-index: 99;
}
.tooltip:hover .tooltiptext,
.tooltip:hover .tooltiptexthigh,
.tooltip:hover .tooltiptextleft,
.tooltip:hover .tooltiptextlow {
visibility: visible;
visibility: visible;
}
.copy_tooltip {
position: relative;
display: inline-block;
position: relative;
display: inline-block;
}
.copy_tooltip_copied {
color: #fff;
transition: color 0.3s;
color: #fff;
transition: color 0.3s;
}
.copy_tooltip .copy_tooltip_text {
visibility: hidden;
font-size: 15px;
padding: 5px;
background-color: var(--my-background-color);
color: #fff;
text-align: center;
position: absolute;
z-index: 1;
top: 120%;
left: 5%;
opacity: 0;
border: 2px solid var(--my-highlight-color);
visibility: hidden;
font-size: 15px;
padding: 5px;
background-color: var(--my-background-color);
color: #fff;
text-align: center;
position: absolute;
z-index: 1;
top: 120%;
left: 5%;
opacity: 0;
border: 2px solid var(--my-highlight-color);
}
.copy_tooltip .copy_tooltip_text::after {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -6px;
border-width: 8px;
border-style: solid;
border-color: transparent transparent white transparent;
content: "";
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -6px;
border-width: 8px;
border-style: solid;
border-color: transparent transparent white transparent;
}
.copy_tooltip .copy_tooltip_text_visible {
visibility: visible;
opacity: 1;
transition: opacity 0.3s;
visibility: visible;
opacity: 1;
transition: opacity 0.3s;
}

@ -1,39 +1,68 @@
/* required LIB STYLES */
/* .Treant se automatski dodaje na svaki chart conatiner */
.Treant { position: relative; overflow: hidden; padding: 0 !important; }
.Treant {
position: relative;
overflow: hidden;
padding: 0 !important;
}
.Treant > .node,
.Treant > .pseudo { position: absolute; display: block; visibility: hidden; }
.Treant > .pseudo {
position: absolute;
display: block;
visibility: hidden;
}
.Treant.Treant-loaded .node,
.Treant.Treant-loaded .pseudo { visibility: visible; }
.Treant > .pseudo { width: 0; height: 0; border: none; padding: 0; }
.Treant .collapse-switch { width: 3px; height: 3px; display: block; border: 1px solid black; position: absolute; top: 1px; right: 1px; cursor: pointer; }
.Treant .collapsed .collapse-switch { background-color: #868dee; }
.Treant > .node img { border: none; float: left; }
.Treant.Treant-loaded .pseudo {
visibility: visible;
}
.Treant > .pseudo {
width: 0;
height: 0;
border: none;
padding: 0;
}
.Treant .collapse-switch {
width: 3px;
height: 3px;
display: block;
border: 1px solid black;
position: absolute;
top: 1px;
right: 1px;
cursor: pointer;
}
.Treant .collapsed .collapse-switch {
background-color: #868dee;
}
.Treant > .node img {
border: none;
float: left;
}
.Treant > .node {
cursor: pointer;
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #e8e8e3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
font-size: 12px;
cursor: pointer;
padding: 4px;
min-width: 60px;
text-align: center;
border: 2px solid #e8e8e3;
border-radius: 2px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
font-size: 12px;
}
.Treant > .researched {
background-color: #666;
font-size: 16px;
background-color: #666;
font-size: 16px;
}
.Treant > .locked > div {
color: red;
pointer-events: none;
color: red;
pointer-events: none;
}
.Treant > .node > div {
font-size: 12px;
font-size: 12px;
}
.Treant > .unlocked:hover {
background-color: #666;
background-color: #666;
}

@ -3,49 +3,49 @@
/* Both Work in progress and BitNode stuff */
.generic-fullscreen-container {
color: var(--my-font-color);
width: 99%;
height: 100%;
overflow-y: hidden;
color: var(--my-font-color);
width: 99%;
height: 100%;
overflow-y: hidden;
}
.generic-fullscreen-container-scroll {
height: 100%;
width: 100%;
overflow: auto;
padding-right: 20px;
height: 100%;
width: 100%;
overflow: auto;
padding-right: 20px;
}
#work-in-progress-container {
position: fixed;
position: fixed;
}
#work-in-progress-text {
color: var(--my-font-color);
width: 70%;
margin: 10px;
color: var(--my-font-color);
width: 70%;
margin: 10px;
}
.work-button {
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
@include borderRadius(12px);
@include boxShadow(1px 1px 3px #000);
color: #aaa;
float: left;
font-size: $defaultFontSize * 1.25;
font-weight: bold;
margin: 10px;
padding: 5px;
border: 3px solid #fff;
color: #aaa;
float: left;
font-size: $defaultFontSize * 1.25;
font-weight: bold;
margin: 10px;
padding: 5px;
border: 3px solid #fff;
}
.work-button:hover,
.work-button:focus {
color: #fff;
text-decoration: none;
cursor: pointer;
color: #fff;
text-decoration: none;
cursor: pointer;
}
#cinematic-text-container {
position: fixed;
position: fixed;
}

@ -21,10 +21,11 @@ body {
background-color: #eeeeec;
}
/* Page layout */
div.header, div.content, div.footer {
div.header,
div.content,
div.footer {
width: 70em;
margin-left: auto;
margin-right: auto;
@ -35,13 +36,13 @@ div.header-wrapper {
border-bottom: 3px solid #2e3436;
}
/* Default body styles */
a {
color: #ce5c00;
}
div.bodywrapper a, div.footer a {
div.bodywrapper a,
div.footer a {
text-decoration: underline;
}
@ -58,22 +59,25 @@ div.bodywrapper a, div.footer a {
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
h1, h2, h3, h4 {
h1,
h2,
h3,
h4 {
font-family: "Georgia", "Times New Roman", serif;
font-weight: normal;
color: #3465a4;
margin-bottom: .8em;
margin-bottom: 0.8em;
}
h1 {
@ -81,14 +85,14 @@ h1 {
}
h2 {
padding-bottom: .5em;
padding-bottom: 0.5em;
border-bottom: 1px solid #3465a4;
}
a.headerlink {
visibility: hidden;
color: #dddddd;
padding-left: .3em;
padding-left: 0.3em;
}
h1:hover > a.headerlink,
@ -120,7 +124,8 @@ p.admonition-title {
font-weight: bold;
}
dt:target, .highlighted {
dt:target,
.highlighted {
background-color: #fbe54e;
}
@ -135,8 +140,8 @@ div.header .headertitle {
font-family: "Georgia", "Times New Roman", serif;
font-weight: normal;
font-size: 180%;
letter-spacing: .08em;
margin-bottom: .8em;
letter-spacing: 0.08em;
margin-bottom: 0.8em;
}
div.header .headertitle a {
@ -149,19 +154,18 @@ div.header div.rel {
div.header div.rel a {
color: #fcaf3e;
letter-spacing: .1em;
letter-spacing: 0.1em;
text-transform: uppercase;
}
p.logo {
float: right;
float: right;
}
img.logo {
border: 0;
border: 0;
}
/* Content */
div.content-wrapper {
background-color: white;
@ -190,7 +194,7 @@ div.document ul {
div.document dd {
margin-left: 1.2em;
margin-top: .4em;
margin-top: 0.4em;
margin-bottom: 1em;
}
@ -206,13 +210,13 @@ div.document div.highlight {
background-color: #eeeeec;
border-top: 2px solid #dddddd;
border-bottom: 2px solid #dddddd;
margin-top: .8em;
margin-bottom: .8em;
margin-top: 0.8em;
margin-bottom: 0.8em;
}
div.document div.literal-block-wrapper {
margin-top: .8em;
margin-bottom: .8em;
margin-top: 0.8em;
margin-bottom: 0.8em;
}
div.document div.literal-block-wrapper div.highlight {
@ -220,19 +224,19 @@ div.document div.literal-block-wrapper div.highlight {
}
div.document div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
padding: 0.1em 0.3em;
font-style: italic;
}
div.document div.code-block-caption span.caption-text {
}
div.document h2 {
margin-top: .7em;
margin-top: 0.7em;
}
div.document p {
margin-bottom: .5em;
margin-bottom: 0.5em;
}
div.document li.toctree-l1 {
@ -244,7 +248,7 @@ div.document .descname {
}
div.document .sig-paren {
font-size: larger;
font-size: larger;
}
div.document .docutils.literal {
@ -265,16 +269,15 @@ div.document ol {
margin: 1.5em;
}
/* Sidebar */
div.sidebar {
width: 20em;
position:fixed;
position: fixed;
right: 10%;
height:75%;
font-size: .9em;
overflow-y:auto;
height: 75%;
font-size: 0.9em;
overflow-y: auto;
}
/*
div.sidebar {
@ -284,11 +287,13 @@ div.sidebar {
}
*/
div.sidebar a, div.header a {
div.sidebar a,
div.header a {
text-decoration: none;
}
div.sidebar a:hover, div.header a:hover {
div.sidebar a:hover,
div.header a:hover {
text-decoration: underline;
}
@ -296,7 +301,7 @@ div.sidebar h3 {
color: #2e3436;
text-transform: uppercase;
font-size: 130%;
letter-spacing: .1em;
letter-spacing: 0.1em;
}
div.sidebar ul {
@ -308,7 +313,7 @@ div.sidebar li.toctree-l1 a {
padding: 1px;
border: 1px solid #dddddd;
background-color: #eeeeec;
margin-bottom: .4em;
margin-bottom: 0.4em;
padding-left: 3px;
color: #2e3436;
}
@ -347,7 +352,6 @@ div.sidebar input[type="submit"] {
width: 30px;
}
/* Footer */
div.footer-wrapper {
@ -358,7 +362,8 @@ div.footer-wrapper {
min-height: 80px;
}
div.footer, div.footer a {
div.footer,
div.footer a {
color: #888a85;
}
@ -370,48 +375,53 @@ div.footer .left {
text-transform: uppercase;
}
/* Styles copied from basic theme */
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
img.align-left,
.figure.align-left,
object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
img.align-right,
.figure.align-right,
object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
img.align-center,
.figure.align-center,
object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
text-align: left;
}
.align-center {
text-align: center;
text-align: center;
}
.align-right {
text-align: right;
text-align: right;
}
table caption span.caption-number {
font-style: italic;
font-style: italic;
}
table caption span.caption-text {
}
div.figure p.caption span.caption-number {
font-style: italic;
font-style: italic;
}
div.figure p.caption span.caption-text {
@ -420,122 +430,122 @@ div.figure p.caption span.caption-text {
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable td {
text-align: left;
vertical-align: top;
text-align: left;
vertical-align: top;
}
table.indextable ul {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
padding-left: 0em;
}
table.indextable tr.pcap {
height: 10px;
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
padding: 2px;
border-collapse: collapse;
}
/* -- viewcode extension ---------------------------------------------------- */
.viewcode-link {
float: right;
float: right;
}
.viewcode-back {
float: right;
font-family: "Verdana", Arial, sans-serif;
float: right;
font-family: "Verdana", Arial, sans-serif;
}
div.viewcode-block:target {
margin: -1px -3px;
padding: 0 3px;
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
margin: -1px -3px;
padding: 0 3px;
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
div.code-block-caption {
background-color: #ddd;
color: #333;
padding: 2px 5px;
font-size: small;
background-color: #ddd;
color: #333;
padding: 2px 5px;
font-size: small;
}
/* -- math display ---------------------------------------------------------- */
div.body div.math p {
text-align: center;
text-align: center;
}
span.eqno {
float: right;
float: right;
}

@ -1,3 +1,3 @@
.wy-nav-content {
max-width: none;
max-width: none;
}

@ -1,15 +1,15 @@
version: "3.4"
services:
web:
image: bitburner:dev
build:
context: .
dockerfile: Dockerfile
target: dev
ports:
- "8000:8000"
volumes:
- ./src:/app/src
- ./css:/app/css
- ./utils:/app/utils
- ./test:/app/test
web:
image: bitburner:dev
build:
context: .
dockerfile: Dockerfile
target: dev
ports:
- "8000:8000"
volumes:
- ./src:/app/src
- ./css:/app/css
- ./utils:/app/utils
- ./test:/app/test

1454
index.html

File diff suppressed because it is too large Load Diff

@ -1,9 +1,9 @@
module.exports = {
setupFiles: ["./jest.setup.js"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
transform: {
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
},
// testMatch: ["**/?(*.)+(test).[jt]s?(x)"],
testEnvironment: "jsdom",
setupFiles: ["./jest.setup.js"],
moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
transform: {
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
},
// testMatch: ["**/?(*.)+(test).[jt]s?(x)"],
testEnvironment: "jsdom",
};

39
package-lock.json generated

@ -5,7 +5,6 @@
"requires": true,
"packages": {
"": {
"name": "bitburner",
"version": "0.52.9",
"hasInstallScript": true,
"license": "SEE LICENSE IN license.txt",
@ -8205,7 +8204,6 @@
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
"peer": true,
"engines": {
"node": ">=6"
}
@ -14966,7 +14964,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.0.tgz",
"integrity": "sha512-D2EBNvUG+mJyhn+M1C858k0f2Fc4KxXvbEX2WCMXroV10212JwfYqaBJ336ECBSz5X9L5LRoamxb7AJtg3KaJA==",
"peer": true,
"dependencies": {
"esm": "^3.2.25",
"mhchemparser": "^4.1.0",
@ -15201,8 +15198,7 @@
"node_modules/mhchemparser": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz",
"integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==",
"peer": true
"integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA=="
},
"node_modules/micromatch": {
"version": "3.1.10",
@ -15455,8 +15451,7 @@
"node_modules/mj-context-menu": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==",
"peer": true
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA=="
},
"node_modules/mkdirp": {
"version": "0.5.1",
@ -20059,7 +20054,6 @@
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-3.3.3.tgz",
"integrity": "sha512-0exWw+0XauLjat+f/aFeo5T8SiDsO1JtwpY3qgJE4cWt+yL/Stl0WP4VNDWdh7lzGkubUD9lWP4J1ASnORXfyQ==",
"peer": true,
"dependencies": {
"commander": ">=7.0.0",
"wicked-good-xpath": "^1.3.0",
@ -20073,7 +20067,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.1.0.tgz",
"integrity": "sha512-mf45ldcuHSYShkplHHGKWb4TrmwQadxOn7v4WuhDJy0ZVoY5JFajaRDKD0PNe5qXzBX0rhovjTnP6Kz9LETcuA==",
"peer": true,
"engines": {
"node": ">= 12"
}
@ -23460,8 +23453,7 @@
"node_modules/wicked-good-xpath": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
"integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=",
"peer": true
"integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w="
},
"node_modules/wide-align": {
"version": "1.1.3",
@ -23608,7 +23600,6 @@
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz",
"integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==",
"peer": true,
"engines": {
"node": ">=0.1"
}
@ -30225,8 +30216,7 @@
"esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
"peer": true
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
},
"espree": {
"version": "7.3.1",
@ -35514,7 +35504,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.0.tgz",
"integrity": "sha512-D2EBNvUG+mJyhn+M1C858k0f2Fc4KxXvbEX2WCMXroV10212JwfYqaBJ336ECBSz5X9L5LRoamxb7AJtg3KaJA==",
"peer": true,
"requires": {
"esm": "^3.2.25",
"mhchemparser": "^4.1.0",
@ -35526,7 +35515,9 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/mathjax-react/-/mathjax-react-1.0.6.tgz",
"integrity": "sha512-GlkPAhaY0FKc95TMdo33mxNZHb+3xRgfgc3YcnQ0cZxvnM1UaF0o8mRI5y5xIwi3JnioeYuukZJWCbIZkACIVw==",
"requires": {}
"requires": {
"mathjax-full": "^3.0.4"
}
},
"mathml-tag-names": {
"version": "2.1.0",
@ -35691,8 +35682,7 @@
"mhchemparser": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz",
"integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==",
"peer": true
"integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA=="
},
"micromatch": {
"version": "3.1.10",
@ -35901,8 +35891,7 @@
"mj-context-menu": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==",
"peer": true
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA=="
},
"mkdirp": {
"version": "0.5.1",
@ -39798,7 +39787,6 @@
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-3.3.3.tgz",
"integrity": "sha512-0exWw+0XauLjat+f/aFeo5T8SiDsO1JtwpY3qgJE4cWt+yL/Stl0WP4VNDWdh7lzGkubUD9lWP4J1ASnORXfyQ==",
"peer": true,
"requires": {
"commander": ">=7.0.0",
"wicked-good-xpath": "^1.3.0",
@ -39808,8 +39796,7 @@
"commander": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.1.0.tgz",
"integrity": "sha512-mf45ldcuHSYShkplHHGKWb4TrmwQadxOn7v4WuhDJy0ZVoY5JFajaRDKD0PNe5qXzBX0rhovjTnP6Kz9LETcuA==",
"peer": true
"integrity": "sha512-mf45ldcuHSYShkplHHGKWb4TrmwQadxOn7v4WuhDJy0ZVoY5JFajaRDKD0PNe5qXzBX0rhovjTnP6Kz9LETcuA=="
}
}
},
@ -42606,8 +42593,7 @@
"wicked-good-xpath": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
"integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=",
"peer": true
"integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w="
},
"wide-align": {
"version": "1.1.3",
@ -42734,8 +42720,7 @@
"xmldom-sre": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz",
"integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==",
"peer": true
"integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw=="
},
"xregexp": {
"version": "4.0.0",

@ -1,432 +1,366 @@
module.exports = {
"env": {
"node": true,
"es6": true
env: {
node: true,
es6: true,
},
extends: "eslint:recommended",
parserOptions: {
ecmaVersion: 8,
sourceType: "module",
ecmaFeatures: {
experimentalObjectRestSpread: true,
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 8,
"sourceType": "module",
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
},
"rules": {
"accessor-pairs": [
"error",
{
"setWithoutGet": true,
"getWithoutSet": false
}
],
"array-bracket-newline": ["error"],
"array-bracket-spacing": ["error"],
"array-callback-return": ["error"],
"array-element-newline": ["error"],
"arrow-body-style": ["error"],
"arrow-parens": ["error"],
"arrow-spacing": ["error"],
"block-scoped-var": ["error"],
"block-spacing": ["error"],
"brace-style": ["error"],
"callback-return": ["error"],
"camelcase": ["error"],
"capitalized-comments": ["error"],
"class-methods-use-this": ["error"],
"comma-dangle": ["error"],
"comma-spacing": ["error"],
"comma-style": [
"error",
"last"
],
"complexity": ["error"],
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": ["error"],
"consistent-this": ["error"],
"constructor-super": ["error"],
"curly": ["error"],
"default-case": ["error"],
"dot-location": [
"error",
"property"
],
"dot-notation": ["error"],
"eol-last": ["error"],
"eqeqeq": ["error"],
"for-direction": ["error"],
"func-call-spacing": ["error"],
"func-name-matching": ["error"],
"func-names": [
"error",
"never"
],
"func-style": ["error"],
"function-paren-newline": ["error"],
"generator-star-spacing": [
"error",
"before"
],
"getter-return": [
"error",
{
"allowImplicit": false
}
],
"global-require": ["error"],
"guard-for-in": ["error"],
"handle-callback-err": ["error"],
"id-blacklist": ["error"],
"id-length": ["error"],
"id-match": ["error"],
"implicit-arrow-linebreak": [
"error",
"beside"
],
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"init-declarations": ["error"],
"jsx-quotes": ["error"],
"key-spacing": ["error"],
"keyword-spacing": ["error"],
"line-comment-position": ["error"],
"linebreak-style": [
"error",
"windows"
],
"lines-around-comment": ["error"],
"lines-between-class-members": ["error"],
"max-depth": ["error"],
"max-len": [
"error",
160
],
"max-lines": [
"error",
{
"skipBlankLines": true,
"skipComments": true
}
],
"max-nested-callbacks": ["error"],
"max-params": ["error"],
"max-statements": ["error"],
"max-statements-per-line": ["error"],
"multiline-comment-style": [
"off",
"starred-block"
],
"multiline-ternary": [
"error",
"never"
],
"new-cap": ["error"],
"new-parens": ["error"],
"newline-before-return": ["error" // TODO: configure this...
],
"newline-per-chained-call": ["error"],
"no-alert": ["error"],
"no-array-constructor": ["error"],
"no-await-in-loop": ["error"],
"no-bitwise": ["error"],
"no-buffer-constructor": ["error"],
"no-caller": ["error"],
"no-case-declarations": ["error"],
"no-catch-shadow": ["error"],
"no-class-assign": ["error"],
"no-compare-neg-zero": ["error"],
"no-cond-assign": [
"error",
"except-parens"
],
"no-confusing-arrow": ["error"],
"no-console": ["error"],
"no-const-assign": ["error"],
"no-constant-condition": [
"error",
{
"checkLoops": false
}
],
"no-continue": ["off"],
"no-control-regex": ["error"],
"no-debugger": ["error"],
"no-delete-var": ["error"],
"no-div-regex": ["error"],
"no-dupe-args": ["error"],
"no-dupe-class-members": ["error"],
"no-dupe-keys": ["error"],
"no-duplicate-case": ["error"],
"no-duplicate-imports": [
"error",
{
"includeExports": true
}
],
"no-else-return": ["error"],
"no-empty": [
"error",
{
"allowEmptyCatch": false
}
],
"no-empty-character-class": ["error"],
"no-empty-function": ["error"],
"no-empty-pattern": ["error"],
"no-eq-null": ["error"],
"no-ex-assign": ["error"],
"no-extra-boolean-cast": ["error"],
"no-extra-parens": [
"error",
"all",
{
"conditionalAssign": false
}
],
"no-extra-semi": ["error"],
"no-eval": ["error"],
"no-extend-native": ["error"],
"no-extra-bind": ["error"],
"no-extra-label": ["error"],
"no-extra-parens": ["error"],
"no-fallthrough": ["error"],
"no-floating-decimal": ["error"],
"no-func-assign": ["error"],
"no-global-assign": ["error"],
"no-implicit-coercion": ["error"],
"no-implicit-globals": ["error"],
"no-implied-eval": ["error"],
"no-inline-comments": ["error"],
"no-inner-declarations": [
"error",
"both"
],
"no-invalid-regexp": ["error"],
"no-invalid-this": ["error"],
"no-irregular-whitespace": [
"error",
{
"skipStrings": false,
"skipComments": false,
"skipRegExps": false,
"skipTemplates": false
}
],
"no-iterator": ["error"],
"no-label-var": ["error"],
"no-labels": ["error"],
"no-lone-blocks": ["error"],
"no-lonely-if": ["error"],
"no-loop-func": ["error"],
"no-magic-numbers": [
"error",
{
"ignore": [
-1,
0,
1
],
"ignoreArrayIndexes": true
}
],
"no-mixed-operators": ["error"],
"no-mixed-requires": ["error"],
"no-mixed-spaces-and-tabs": ["error"],
"no-multi-assign": ["error"],
"no-multi-spaces": ["error"],
"no-multi-str": ["error"],
"no-multiple-empty-lines": [
"error",
{
"max": 1
}
],
"no-native-reassign": ["error"],
"no-negated-condition": ["error"],
"no-negated-in-lhs": ["error"],
"no-nested-ternary": ["error"],
"no-new": ["error"],
"no-new-func": ["error"],
"no-new-object": ["error"],
"no-new-require": ["error"],
"no-new-symbol": ["error"],
"no-new-wrappers": ["error"],
"no-octal": ["error"],
"no-octal-escape": ["error"],
"no-obj-calls": ["error"],
"no-param-reassign": ["error"],
"no-path-concat": ["error"],
"no-plusplus": [
"error",
{
"allowForLoopAfterthoughts": true
}
],
"no-process-env": ["error"],
"no-process-exit": ["error"],
"no-proto": ["error"],
"no-prototype-builtins": ["error"],
"no-redeclare": ["error"],
"no-regex-spaces": ["error"],
"no-restricted-globals": ["error"],
"no-restricted-imports": ["error"],
"no-restricted-modules": ["error"],
"no-restricted-properties": [
"error",
{
"object": "console",
"property": "log",
"message": "'log' is too general, use an appropriate level when logging."
}
],
"no-restricted-syntax": ["error"],
"no-return-assign": ["error"],
"no-return-await": ["error"],
"no-script-url": ["error"],
"no-self-assign": [
"error",
{
"props": false
}
],
"no-self-compare": ["error"],
"no-sequences": ["error"],
"no-shadow": ["error"],
"no-shadow-restricted-names": ["error"],
"no-spaced-func": ["error"],
"no-sparse-arrays": ["error"],
"no-sync": ["error"],
"no-tabs": ["error"],
"no-template-curly-in-string": ["error"],
"no-ternary": ["off"],
"no-this-before-super": ["error"],
"no-throw-literal": ["error"],
"no-trailing-spaces": ["error"],
"no-undef": ["error"],
"no-undef-init": ["error"],
"no-undefined": ["error"],
"no-underscore-dangle": ["error"],
"no-unexpected-multiline": ["error"],
"no-unmodified-loop-condition": ["error"],
"no-unneeded-ternary": ["error"],
"no-unreachable": ["error"],
"no-unsafe-finally": ["error"],
"no-unsafe-negation": ["error"],
"no-unused-expressions": ["error"],
"no-unused-labels": ["error"],
"no-unused-vars": ["error"],
"no-use-before-define": ["error"],
"no-useless-call": ["error"],
"no-useless-computed-key": ["error"],
"no-useless-concat": ["error"],
"no-useless-constructor": ["error"],
"no-useless-escape": ["error"],
"no-useless-rename": [
"error",
{
"ignoreDestructuring": false,
"ignoreExport": false,
"ignoreImport": false
}
],
"no-useless-return": ["error"],
"no-var": ["error"],
"no-void": ["error"],
"no-warning-comments": ["error"],
"no-whitespace-before-property": ["error"],
"no-with": ["error"],
"nonblock-statement-body-position": [
"error",
"below"
],
"object-curly-newline": ["error"],
"object-curly-spacing": ["error"],
"object-property-newline": ["error"],
"object-shorthand": ["error"],
"one-var": ["off"],
"one-var-declaration-per-line": ["error"],
"operator-assignment": ["error"],
"operator-linebreak": [
"error",
"none"
],
"padded-blocks": ["off"],
"padding-line-between-statements": ["error"],
"prefer-arrow-callback": ["error"],
"prefer-const": ["error"],
"prefer-destructuring": ["off"],
"prefer-numeric-literals": ["error"],
"prefer-promise-reject-errors": ["off"],
"prefer-reflect": ["error"],
"prefer-rest-params": ["error"],
"prefer-spread": ["error"],
"prefer-template": ["error"],
"quote-props": ["error"],
"quotes": ["error"],
"radix": [
"error",
"as-needed"
],
"require-await": ["error"],
"require-jsdoc": ["off"],
"require-yield": ["error"],
"rest-spread-spacing": [
"error",
"never"
],
"semi": ["error"],
"semi-spacing": ["error"],
"semi-style": [
"error",
"last"
],
"sort-imports": ["error"],
"sort-keys": ["error"],
"sort-vars": ["error"],
"space-before-blocks": ["error"],
"space-before-function-paren": ["off"],
"space-in-parens": ["error"],
"space-infix-ops": ["error"],
"space-unary-ops": ["error"],
"spaced-comment": ["error"],
"strict": ["error"],
"switch-colon-spacing": [
"error",
{
"after": true,
"before": false
}
],
"symbol-description": ["error"],
"template-curly-spacing": ["error"],
"template-tag-spacing": ["error"],
"unicode-bom": [
"error",
"never"
],
"use-isnan": ["error"],
"valid-jsdoc": ["error"],
"valid-typeof": ["error"],
"vars-on-top": ["error"],
"wrap-iife": [
"error",
"any"
],
"wrap-regex": ["error"],
"yield-star-spacing": [
"error",
"before"
],
"yoda": [
"error",
"never"
]
}
},
rules: {
"accessor-pairs": [
"error",
{
setWithoutGet: true,
getWithoutSet: false,
},
],
"array-bracket-newline": ["error"],
"array-bracket-spacing": ["error"],
"array-callback-return": ["error"],
"array-element-newline": ["error"],
"arrow-body-style": ["error"],
"arrow-parens": ["error"],
"arrow-spacing": ["error"],
"block-scoped-var": ["error"],
"block-spacing": ["error"],
"brace-style": ["error"],
"callback-return": ["error"],
camelcase: ["error"],
"capitalized-comments": ["error"],
"class-methods-use-this": ["error"],
"comma-dangle": ["error"],
"comma-spacing": ["error"],
"comma-style": ["error", "last"],
complexity: ["error"],
"computed-property-spacing": ["error", "never"],
"consistent-return": ["error"],
"consistent-this": ["error"],
"constructor-super": ["error"],
curly: ["error"],
"default-case": ["error"],
"dot-location": ["error", "property"],
"dot-notation": ["error"],
"eol-last": ["error"],
eqeqeq: ["error"],
"for-direction": ["error"],
"func-call-spacing": ["error"],
"func-name-matching": ["error"],
"func-names": ["error", "never"],
"func-style": ["error"],
"function-paren-newline": ["error"],
"generator-star-spacing": ["error", "before"],
"getter-return": [
"error",
{
allowImplicit: false,
},
],
"global-require": ["error"],
"guard-for-in": ["error"],
"handle-callback-err": ["error"],
"id-blacklist": ["error"],
"id-length": ["error"],
"id-match": ["error"],
"implicit-arrow-linebreak": ["error", "beside"],
indent: [
"error",
4,
{
SwitchCase: 1,
},
],
"init-declarations": ["error"],
"jsx-quotes": ["error"],
"key-spacing": ["error"],
"keyword-spacing": ["error"],
"line-comment-position": ["error"],
"linebreak-style": ["error", "windows"],
"lines-around-comment": ["error"],
"lines-between-class-members": ["error"],
"max-depth": ["error"],
"max-len": ["error", 160],
"max-lines": [
"error",
{
skipBlankLines: true,
skipComments: true,
},
],
"max-nested-callbacks": ["error"],
"max-params": ["error"],
"max-statements": ["error"],
"max-statements-per-line": ["error"],
"multiline-comment-style": ["off", "starred-block"],
"multiline-ternary": ["error", "never"],
"new-cap": ["error"],
"new-parens": ["error"],
"newline-before-return": [
"error", // TODO: configure this...
],
"newline-per-chained-call": ["error"],
"no-alert": ["error"],
"no-array-constructor": ["error"],
"no-await-in-loop": ["error"],
"no-bitwise": ["error"],
"no-buffer-constructor": ["error"],
"no-caller": ["error"],
"no-case-declarations": ["error"],
"no-catch-shadow": ["error"],
"no-class-assign": ["error"],
"no-compare-neg-zero": ["error"],
"no-cond-assign": ["error", "except-parens"],
"no-confusing-arrow": ["error"],
"no-console": ["error"],
"no-const-assign": ["error"],
"no-constant-condition": [
"error",
{
checkLoops: false,
},
],
"no-continue": ["off"],
"no-control-regex": ["error"],
"no-debugger": ["error"],
"no-delete-var": ["error"],
"no-div-regex": ["error"],
"no-dupe-args": ["error"],
"no-dupe-class-members": ["error"],
"no-dupe-keys": ["error"],
"no-duplicate-case": ["error"],
"no-duplicate-imports": [
"error",
{
includeExports: true,
},
],
"no-else-return": ["error"],
"no-empty": [
"error",
{
allowEmptyCatch: false,
},
],
"no-empty-character-class": ["error"],
"no-empty-function": ["error"],
"no-empty-pattern": ["error"],
"no-eq-null": ["error"],
"no-ex-assign": ["error"],
"no-extra-boolean-cast": ["error"],
"no-extra-parens": [
"error",
"all",
{
conditionalAssign: false,
},
],
"no-extra-semi": ["error"],
"no-eval": ["error"],
"no-extend-native": ["error"],
"no-extra-bind": ["error"],
"no-extra-label": ["error"],
"no-extra-parens": ["error"],
"no-fallthrough": ["error"],
"no-floating-decimal": ["error"],
"no-func-assign": ["error"],
"no-global-assign": ["error"],
"no-implicit-coercion": ["error"],
"no-implicit-globals": ["error"],
"no-implied-eval": ["error"],
"no-inline-comments": ["error"],
"no-inner-declarations": ["error", "both"],
"no-invalid-regexp": ["error"],
"no-invalid-this": ["error"],
"no-irregular-whitespace": [
"error",
{
skipStrings: false,
skipComments: false,
skipRegExps: false,
skipTemplates: false,
},
],
"no-iterator": ["error"],
"no-label-var": ["error"],
"no-labels": ["error"],
"no-lone-blocks": ["error"],
"no-lonely-if": ["error"],
"no-loop-func": ["error"],
"no-magic-numbers": [
"error",
{
ignore: [-1, 0, 1],
ignoreArrayIndexes: true,
},
],
"no-mixed-operators": ["error"],
"no-mixed-requires": ["error"],
"no-mixed-spaces-and-tabs": ["error"],
"no-multi-assign": ["error"],
"no-multi-spaces": ["error"],
"no-multi-str": ["error"],
"no-multiple-empty-lines": [
"error",
{
max: 1,
},
],
"no-native-reassign": ["error"],
"no-negated-condition": ["error"],
"no-negated-in-lhs": ["error"],
"no-nested-ternary": ["error"],
"no-new": ["error"],
"no-new-func": ["error"],
"no-new-object": ["error"],
"no-new-require": ["error"],
"no-new-symbol": ["error"],
"no-new-wrappers": ["error"],
"no-octal": ["error"],
"no-octal-escape": ["error"],
"no-obj-calls": ["error"],
"no-param-reassign": ["error"],
"no-path-concat": ["error"],
"no-plusplus": [
"error",
{
allowForLoopAfterthoughts: true,
},
],
"no-process-env": ["error"],
"no-process-exit": ["error"],
"no-proto": ["error"],
"no-prototype-builtins": ["error"],
"no-redeclare": ["error"],
"no-regex-spaces": ["error"],
"no-restricted-globals": ["error"],
"no-restricted-imports": ["error"],
"no-restricted-modules": ["error"],
"no-restricted-properties": [
"error",
{
object: "console",
property: "log",
message: "'log' is too general, use an appropriate level when logging.",
},
],
"no-restricted-syntax": ["error"],
"no-return-assign": ["error"],
"no-return-await": ["error"],
"no-script-url": ["error"],
"no-self-assign": [
"error",
{
props: false,
},
],
"no-self-compare": ["error"],
"no-sequences": ["error"],
"no-shadow": ["error"],
"no-shadow-restricted-names": ["error"],
"no-spaced-func": ["error"],
"no-sparse-arrays": ["error"],
"no-sync": ["error"],
"no-tabs": ["error"],
"no-template-curly-in-string": ["error"],
"no-ternary": ["off"],
"no-this-before-super": ["error"],
"no-throw-literal": ["error"],
"no-trailing-spaces": ["error"],
"no-undef": ["error"],
"no-undef-init": ["error"],
"no-undefined": ["error"],
"no-underscore-dangle": ["error"],
"no-unexpected-multiline": ["error"],
"no-unmodified-loop-condition": ["error"],
"no-unneeded-ternary": ["error"],
"no-unreachable": ["error"],
"no-unsafe-finally": ["error"],
"no-unsafe-negation": ["error"],
"no-unused-expressions": ["error"],
"no-unused-labels": ["error"],
"no-unused-vars": ["error"],
"no-use-before-define": ["error"],
"no-useless-call": ["error"],
"no-useless-computed-key": ["error"],
"no-useless-concat": ["error"],
"no-useless-constructor": ["error"],
"no-useless-escape": ["error"],
"no-useless-rename": [
"error",
{
ignoreDestructuring: false,
ignoreExport: false,
ignoreImport: false,
},
],
"no-useless-return": ["error"],
"no-var": ["error"],
"no-void": ["error"],
"no-warning-comments": ["error"],
"no-whitespace-before-property": ["error"],
"no-with": ["error"],
"nonblock-statement-body-position": ["error", "below"],
"object-curly-newline": ["error"],
"object-curly-spacing": ["error"],
"object-property-newline": ["error"],
"object-shorthand": ["error"],
"one-var": ["off"],
"one-var-declaration-per-line": ["error"],
"operator-assignment": ["error"],
"operator-linebreak": ["error", "none"],
"padded-blocks": ["off"],
"padding-line-between-statements": ["error"],
"prefer-arrow-callback": ["error"],
"prefer-const": ["error"],
"prefer-destructuring": ["off"],
"prefer-numeric-literals": ["error"],
"prefer-promise-reject-errors": ["off"],
"prefer-reflect": ["error"],
"prefer-rest-params": ["error"],
"prefer-spread": ["error"],
"prefer-template": ["error"],
"quote-props": ["error"],
quotes: ["error"],
radix: ["error", "as-needed"],
"require-await": ["error"],
"require-jsdoc": ["off"],
"require-yield": ["error"],
"rest-spread-spacing": ["error", "never"],
semi: ["error"],
"semi-spacing": ["error"],
"semi-style": ["error", "last"],
"sort-imports": ["error"],
"sort-keys": ["error"],
"sort-vars": ["error"],
"space-before-blocks": ["error"],
"space-before-function-paren": ["off"],
"space-in-parens": ["error"],
"space-infix-ops": ["error"],
"space-unary-ops": ["error"],
"spaced-comment": ["error"],
strict: ["error"],
"switch-colon-spacing": [
"error",
{
after: true,
before: false,
},
],
"symbol-description": ["error"],
"template-curly-spacing": ["error"],
"template-tag-spacing": ["error"],
"unicode-bom": ["error", "never"],
"use-isnan": ["error"],
"valid-jsdoc": ["error"],
"valid-typeof": ["error"],
"vars-on-top": ["error"],
"wrap-iife": ["error", "any"],
"wrap-regex": ["error"],
"yield-star-spacing": ["error", "before"],
yoda: ["error", "never"],
},
};

@ -8,63 +8,74 @@ const path = require("path");
const exec = require("child_process").exec;
const semver = require("./semver");
const getPackageJson = () => new Promise((resolve, reject) => {
const getPackageJson = () =>
new Promise((resolve, reject) => {
try {
/* eslint-disable-next-line global-require */
resolve(require(path.resolve(process.cwd(), "package.json")));
/* eslint-disable-next-line global-require */
resolve(require(path.resolve(process.cwd(), "package.json")));
} catch (error) {
reject(error);
reject(error);
}
});
});
const getEngines = (data) => new Promise((resolve, reject) => {
const getEngines = (data) =>
new Promise((resolve, reject) => {
let versions = null;
if (data.engines) {
versions = data.engines;
versions = data.engines;
}
if (versions) {
resolve(versions);
resolve(versions);
} else {
reject("Missing or improper 'engines' property in 'package.json'");
reject("Missing or improper 'engines' property in 'package.json'");
}
});
});
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
const checkNpmVersion = (engines) =>
new Promise((resolve, reject) => {
exec("npm -v", (error, stdout, stderr) => {
if (error) {
reject(`Unable to find NPM version\n${stderr}`);
}
if (error) {
reject(`Unable to find NPM version\n${stderr}`);
}
const npmVersion = stdout.trim();
const engineVersion = engines.npm || ">=0";
const npmVersion = stdout.trim();
const engineVersion = engines.npm || ">=0";
if (semver.satisfies(npmVersion, engineVersion)) {
resolve();
} else {
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
}
if (semver.satisfies(npmVersion, engineVersion)) {
resolve();
} else {
reject(
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
);
}
});
});
});
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
const checkNodeVersion = (engines) =>
new Promise((resolve, reject) => {
const nodeVersion = process.version.substring(1);
if (semver.satisfies(nodeVersion, engines.node)) {
resolve(engines);
resolve(engines);
} else {
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
reject(
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
);
}
});
});
getPackageJson()
.then(getEngines)
.then(checkNodeVersion)
.then(checkNpmVersion)
.then(() => true, (error) => {
// Specifically disable these as the error message gets lost in the normal unhandled output.
/* eslint-disable no-console, no-process-exit */
console.error(error);
process.exit(1);
});
.then(getEngines)
.then(checkNodeVersion)
.then(checkNpmVersion)
.then(
() => true,
(error) => {
// Specifically disable these as the error message gets lost in the normal unhandled output.
/* eslint-disable no-console, no-process-exit */
console.error(error);
process.exit(1);
},
);

File diff suppressed because it is too large Load Diff

@ -5,89 +5,91 @@ export let Aliases: IMap<string> = {};
export let GlobalAliases: IMap<string> = {};
export function loadAliases(saveString: string): void {
if (saveString === "") {
Aliases = {};
} else {
Aliases = JSON.parse(saveString);
}
if (saveString === "") {
Aliases = {};
} else {
Aliases = JSON.parse(saveString);
}
}
export function loadGlobalAliases(saveString: string): void {
if (saveString === "") {
GlobalAliases = {};
} else {
GlobalAliases = JSON.parse(saveString);
}
if (saveString === "") {
GlobalAliases = {};
} else {
GlobalAliases = JSON.parse(saveString);
}
}
// Prints all aliases to terminal
export function printAliases(): void {
for (const name in Aliases) {
if (Aliases.hasOwnProperty(name)) {
post("alias " + name + "=" + Aliases[name]);
}
for (const name in Aliases) {
if (Aliases.hasOwnProperty(name)) {
post("alias " + name + "=" + Aliases[name]);
}
for (const name in GlobalAliases) {
if (GlobalAliases.hasOwnProperty(name)) {
post("global alias " + name + "=" + GlobalAliases[name]);
}
}
for (const name in GlobalAliases) {
if (GlobalAliases.hasOwnProperty(name)) {
post("global alias " + name + "=" + GlobalAliases[name]);
}
}
}
// Returns true if successful, false otherwise
export function parseAliasDeclaration(dec: string, global = false): boolean {
const re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
const matches = dec.match(re);
if (matches == null || matches.length != 3) {return false;}
if (global){
addGlobalAlias(matches[1],matches[2]);
} else {
addAlias(matches[1], matches[2]);
}
return true;
const re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
const matches = dec.match(re);
if (matches == null || matches.length != 3) {
return false;
}
if (global) {
addGlobalAlias(matches[1], matches[2]);
} else {
addAlias(matches[1], matches[2]);
}
return true;
}
function addAlias(name: string, value: string): void {
if (name in GlobalAliases) {
delete GlobalAliases[name];
}
Aliases[name] = value.trim();
if (name in GlobalAliases) {
delete GlobalAliases[name];
}
Aliases[name] = value.trim();
}
function addGlobalAlias(name: string, value: string): void {
if (name in Aliases){
delete Aliases[name];
}
GlobalAliases[name] = value.trim();
if (name in Aliases) {
delete Aliases[name];
}
GlobalAliases[name] = value.trim();
}
function getAlias(name: string): string | null {
if (Aliases.hasOwnProperty(name)) {
return Aliases[name];
}
if (Aliases.hasOwnProperty(name)) {
return Aliases[name];
}
return null;
return null;
}
function getGlobalAlias(name: string): string | null {
if (GlobalAliases.hasOwnProperty(name)) {
return GlobalAliases[name];
}
return null;
if (GlobalAliases.hasOwnProperty(name)) {
return GlobalAliases[name];
}
return null;
}
export function removeAlias(name: string): boolean {
if (Aliases.hasOwnProperty(name)) {
delete Aliases[name];
return true;
}
if (Aliases.hasOwnProperty(name)) {
delete Aliases[name];
return true;
}
if (GlobalAliases.hasOwnProperty(name)) {
delete GlobalAliases[name];
return true;
}
if (GlobalAliases.hasOwnProperty(name)) {
delete GlobalAliases[name];
return true;
}
return false;
return false;
}
/**
@ -95,33 +97,35 @@ export function removeAlias(name: string): boolean {
* Aliases are only applied to "whole words", one level deep
*/
export function substituteAliases(origCommand: string): string {
const commandArray = origCommand.split(" ");
if (commandArray.length > 0){
// For the alias and unalias commands, dont substite
if (commandArray[0] === "unalias" || commandArray[0] === "alias") { return commandArray.join(" "); }
let somethingSubstituted = true;
let depth = 0;
while(somethingSubstituted && depth < 10){
depth++;
somethingSubstituted = false
const alias = getAlias(commandArray[0])?.split(" ");
if (alias != null) {
somethingSubstituted = true
commandArray.splice(0, 1, ...alias);
//commandArray[0] = alias;
}
for (let i = 0; i < commandArray.length; ++i) {
const alias = getGlobalAlias(commandArray[i])?.split(" ");
if (alias != null) {
somethingSubstituted = true
commandArray.splice(i, 1, ...alias);
i += alias.length - 1;
//commandArray[i] = alias;
}
}
}
const commandArray = origCommand.split(" ");
if (commandArray.length > 0) {
// For the alias and unalias commands, dont substite
if (commandArray[0] === "unalias" || commandArray[0] === "alias") {
return commandArray.join(" ");
}
return commandArray.join(" ");
let somethingSubstituted = true;
let depth = 0;
while (somethingSubstituted && depth < 10) {
depth++;
somethingSubstituted = false;
const alias = getAlias(commandArray[0])?.split(" ");
if (alias != null) {
somethingSubstituted = true;
commandArray.splice(0, 1, ...alias);
//commandArray[0] = alias;
}
for (let i = 0; i < commandArray.length; ++i) {
const alias = getGlobalAlias(commandArray[i])?.split(" ");
if (alias != null) {
somethingSubstituted = true;
commandArray.splice(i, 1, ...alias);
i += alias.length - 1;
//commandArray[i] = alias;
}
}
}
}
return commandArray.join(" ");
}

@ -8,297 +8,580 @@ import { Factions } from "../Faction/Factions";
import { numeralWrapper } from "../ui/numeralFormat";
import { Money } from "../ui/React/Money";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
interface IConstructorParams {
info: string | JSX.Element;
stats?: JSX.Element;
isSpecial?: boolean;
moneyCost: number;
name: string;
prereqs?: string[];
repCost: number;
info: string | JSX.Element;
stats?: JSX.Element;
isSpecial?: boolean;
moneyCost: number;
name: string;
prereqs?: string[];
repCost: number;
hacking_mult?: number;
strength_mult?: number;
defense_mult?: number;
dexterity_mult?: number;
agility_mult?: number;
charisma_mult?: number;
hacking_exp_mult?: number;
strength_exp_mult?: number;
defense_exp_mult?: number;
dexterity_exp_mult?: number;
agility_exp_mult?: number;
charisma_exp_mult?: number;
hacking_chance_mult?: number;
hacking_speed_mult?: number;
hacking_money_mult?: number;
hacking_grow_mult?: number;
company_rep_mult?: number;
faction_rep_mult?: number;
crime_money_mult?: number;
crime_success_mult?: number;
work_money_mult?: number;
hacknet_node_money_mult?: number;
hacknet_node_purchase_cost_mult?: number;
hacknet_node_ram_cost_mult?: number;
hacknet_node_core_cost_mult?: number;
hacknet_node_level_cost_mult?: number;
bladeburner_max_stamina_mult?: number;
bladeburner_stamina_gain_mult?: number;
bladeburner_analysis_mult?: number;
bladeburner_success_chance_mult?: number;
hacking_mult?: number;
strength_mult?: number;
defense_mult?: number;
dexterity_mult?: number;
agility_mult?: number;
charisma_mult?: number;
hacking_exp_mult?: number;
strength_exp_mult?: number;
defense_exp_mult?: number;
dexterity_exp_mult?: number;
agility_exp_mult?: number;
charisma_exp_mult?: number;
hacking_chance_mult?: number;
hacking_speed_mult?: number;
hacking_money_mult?: number;
hacking_grow_mult?: number;
company_rep_mult?: number;
faction_rep_mult?: number;
crime_money_mult?: number;
crime_success_mult?: number;
work_money_mult?: number;
hacknet_node_money_mult?: number;
hacknet_node_purchase_cost_mult?: number;
hacknet_node_ram_cost_mult?: number;
hacknet_node_core_cost_mult?: number;
hacknet_node_level_cost_mult?: number;
bladeburner_max_stamina_mult?: number;
bladeburner_stamina_gain_mult?: number;
bladeburner_analysis_mult?: number;
bladeburner_success_chance_mult?: number;
startingMoney?: number;
programs?: string[];
startingMoney?: number;
programs?: string[];
}
function generateStatsDescription(mults: IMap<number>, programs?: string[], startingMoney?: number): JSX.Element {
const f = (x: number, decimals = 0): string => {
// look, I don't know how to make a "smart decimals"
// todo, make it smarter
if(x === 1.0777-1) return "7.77%";
if(x === 1.777-1) return "77.7%";
return numeralWrapper.formatPercentage(x, decimals);
};
let desc = <>Effects:</>;
function generateStatsDescription(
mults: IMap<number>,
programs?: string[],
startingMoney?: number,
): JSX.Element {
const f = (x: number, decimals = 0): string => {
// look, I don't know how to make a "smart decimals"
// todo, make it smarter
if (x === 1.0777 - 1) return "7.77%";
if (x === 1.777 - 1) return "77.7%";
return numeralWrapper.formatPercentage(x, decimals);
};
let desc = <>Effects:</>;
if(mults.hacking_mult &&
mults.hacking_mult == mults.strength_mult &&
mults.hacking_mult == mults.defense_mult &&
mults.hacking_mult == mults.dexterity_mult &&
mults.hacking_mult == mults.agility_mult &&
mults.hacking_mult == mults.charisma_mult){
desc = <>{desc}<br />+{f(mults.hacking_mult-1)} all skills</>
if (
mults.hacking_mult &&
mults.hacking_mult == mults.strength_mult &&
mults.hacking_mult == mults.defense_mult &&
mults.hacking_mult == mults.dexterity_mult &&
mults.hacking_mult == mults.agility_mult &&
mults.hacking_mult == mults.charisma_mult
) {
desc = (
<>
{desc}
<br />+{f(mults.hacking_mult - 1)} all skills
</>
);
} else {
if (mults.hacking_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacking_mult - 1)} hacking skill
</>
);
if (
mults.strength_mult &&
mults.strength_mult == mults.defense_mult &&
mults.strength_mult == mults.dexterity_mult &&
mults.strength_mult == mults.agility_mult
) {
desc = (
<>
{desc}
<br />+{f(mults.strength_mult - 1)} combat skills
</>
);
} else {
if(mults.hacking_mult)
desc = <>{desc}<br />+{f(mults.hacking_mult-1)} hacking skill</>
if(mults.strength_mult &&
mults.strength_mult == mults.defense_mult &&
mults.strength_mult == mults.dexterity_mult &&
mults.strength_mult == mults.agility_mult) {
desc = <>{desc}<br />+{f(mults.strength_mult-1)} combat skills</>
} else {
if(mults.strength_mult)
desc = <>{desc}<br />+{f(mults.strength_mult-1)} strength skill</>
if(mults.defense_mult)
desc = <>{desc}<br />+{f(mults.defense_mult-1)} defense skill</>
if(mults.dexterity_mult)
desc = <>{desc}<br />+{f(mults.dexterity_mult-1)} dexterity skill</>
if(mults.agility_mult)
desc = <>{desc}<br />+{f(mults.agility_mult-1)} agility skill</>
}
if(mults.charisma_mult)
desc = <>{desc}<br />+{f(mults.charisma_mult-1)} Charisma skill</>
if (mults.strength_mult)
desc = (
<>
{desc}
<br />+{f(mults.strength_mult - 1)} strength skill
</>
);
if (mults.defense_mult)
desc = (
<>
{desc}
<br />+{f(mults.defense_mult - 1)} defense skill
</>
);
if (mults.dexterity_mult)
desc = (
<>
{desc}
<br />+{f(mults.dexterity_mult - 1)} dexterity skill
</>
);
if (mults.agility_mult)
desc = (
<>
{desc}
<br />+{f(mults.agility_mult - 1)} agility skill
</>
);
}
if (mults.charisma_mult)
desc = (
<>
{desc}
<br />+{f(mults.charisma_mult - 1)} Charisma skill
</>
);
}
if(mults.hacking_exp_mult &&
mults.hacking_exp_mult === mults.strength_exp_mult &&
mults.hacking_exp_mult === mults.defense_exp_mult &&
mults.hacking_exp_mult === mults.dexterity_exp_mult &&
mults.hacking_exp_mult === mults.agility_exp_mult &&
mults.hacking_exp_mult === mults.charisma_exp_mult) {
desc = <>{desc}<br />+{f(mults.hacking_exp_mult-1)} exp for all skills</>
if (
mults.hacking_exp_mult &&
mults.hacking_exp_mult === mults.strength_exp_mult &&
mults.hacking_exp_mult === mults.defense_exp_mult &&
mults.hacking_exp_mult === mults.dexterity_exp_mult &&
mults.hacking_exp_mult === mults.agility_exp_mult &&
mults.hacking_exp_mult === mults.charisma_exp_mult
) {
desc = (
<>
{desc}
<br />+{f(mults.hacking_exp_mult - 1)} exp for all skills
</>
);
} else {
if (mults.hacking_exp_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacking_exp_mult - 1)} hacking exp
</>
);
if (
mults.strength_exp_mult &&
mults.strength_exp_mult === mults.defense_exp_mult &&
mults.strength_exp_mult === mults.dexterity_exp_mult &&
mults.strength_exp_mult === mults.agility_exp_mult
) {
desc = (
<>
{desc}
<br />+{f(mults.strength_exp_mult - 1)} combat exp
</>
);
} else {
if(mults.hacking_exp_mult)
desc = <>{desc}<br />+{f(mults.hacking_exp_mult-1)} hacking exp</>
if(mults.strength_exp_mult &&
mults.strength_exp_mult === mults.defense_exp_mult &&
mults.strength_exp_mult === mults.dexterity_exp_mult &&
mults.strength_exp_mult === mults.agility_exp_mult) {
desc = <>{desc}<br />+{f(mults.strength_exp_mult-1)} combat exp</>
} else {
if(mults.strength_exp_mult)
desc = <>{desc}<br />+{f(mults.strength_exp_mult-1)} strength exp</>
if(mults.defense_exp_mult)
desc = <>{desc}<br />+{f(mults.defense_exp_mult-1)} defense exp</>
if(mults.dexterity_exp_mult)
desc = <>{desc}<br />+{f(mults.dexterity_exp_mult-1)} dexterity exp</>
if(mults.agility_exp_mult)
desc = <>{desc}<br />+{f(mults.agility_exp_mult-1)} agility exp</>
}
if(mults.charisma_exp_mult)
desc = <>{desc}<br />+{f(mults.charisma_exp_mult-1)} charisma exp</>
if (mults.strength_exp_mult)
desc = (
<>
{desc}
<br />+{f(mults.strength_exp_mult - 1)} strength exp
</>
);
if (mults.defense_exp_mult)
desc = (
<>
{desc}
<br />+{f(mults.defense_exp_mult - 1)} defense exp
</>
);
if (mults.dexterity_exp_mult)
desc = (
<>
{desc}
<br />+{f(mults.dexterity_exp_mult - 1)} dexterity exp
</>
);
if (mults.agility_exp_mult)
desc = (
<>
{desc}
<br />+{f(mults.agility_exp_mult - 1)} agility exp
</>
);
}
if (mults.charisma_exp_mult)
desc = (
<>
{desc}
<br />+{f(mults.charisma_exp_mult - 1)} charisma exp
</>
);
}
if(mults.hacking_speed_mult)
desc = <>{desc}<br />+{f(mults.hacking_speed_mult-1)} faster hacking</>
if(mults.hacking_chance_mult)
desc = <>{desc}<br />+{f(mults.hacking_chance_mult-1)} hack() success chance</>
if(mults.hacking_money_mult)
desc = <>{desc}<br />+{f(mults.hacking_money_mult-1)} hack() power</>
if(mults.hacking_grow_mult)
desc = <>{desc}<br />+{f(mults.hacking_grow_mult-1)} grow() power</>
if (mults.hacking_speed_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacking_speed_mult - 1)} faster hacking
</>
);
if (mults.hacking_chance_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacking_chance_mult - 1)} hack() success chance
</>
);
if (mults.hacking_money_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacking_money_mult - 1)} hack() power
</>
);
if (mults.hacking_grow_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacking_grow_mult - 1)} grow() power
</>
);
if(mults.faction_rep_mult &&
mults.faction_rep_mult === mults.company_rep_mult) {
desc = <>{desc}<br />+{f(mults.faction_rep_mult-1)} reputation from factions and companies</>
} else {
if(mults.faction_rep_mult)
desc = <>{desc}<br />+{f(mults.faction_rep_mult-1)} reputation from factions</>
if(mults.company_rep_mult)
desc = <>{desc}<br />+{f(mults.company_rep_mult-1)} reputation from companies</>
}
if (
mults.faction_rep_mult &&
mults.faction_rep_mult === mults.company_rep_mult
) {
desc = (
<>
{desc}
<br />+{f(mults.faction_rep_mult - 1)} reputation from factions and
companies
</>
);
} else {
if (mults.faction_rep_mult)
desc = (
<>
{desc}
<br />+{f(mults.faction_rep_mult - 1)} reputation from factions
</>
);
if (mults.company_rep_mult)
desc = (
<>
{desc}
<br />+{f(mults.company_rep_mult - 1)} reputation from companies
</>
);
}
if(mults.crime_money_mult)
desc = <>{desc}<br />+{f(mults.crime_money_mult-1)} crime money</>
if(mults.crime_success_mult)
desc = <>{desc}<br />+{f(mults.crime_success_mult-1)} crime success rate</>
if(mults.work_money_mult)
desc = <>{desc}<br />+{f(mults.work_money_mult-1)} work money</>
if (mults.crime_money_mult)
desc = (
<>
{desc}
<br />+{f(mults.crime_money_mult - 1)} crime money
</>
);
if (mults.crime_success_mult)
desc = (
<>
{desc}
<br />+{f(mults.crime_success_mult - 1)} crime success rate
</>
);
if (mults.work_money_mult)
desc = (
<>
{desc}
<br />+{f(mults.work_money_mult - 1)} work money
</>
);
if(mults.hacknet_node_money_mult)
desc = <>{desc}<br />+{f(mults.hacknet_node_money_mult-1)} hacknet production</>
if(mults.hacknet_node_purchase_cost_mult)
desc = <>{desc}<br />-{f(-(mults.hacknet_node_purchase_cost_mult-1))} hacknet nodes cost</>
if(mults.hacknet_node_level_cost_mult)
desc = <>{desc}<br />-{f(-(mults.hacknet_node_level_cost_mult-1))} hacknet nodes upgrade cost</>
if (mults.hacknet_node_money_mult)
desc = (
<>
{desc}
<br />+{f(mults.hacknet_node_money_mult - 1)} hacknet production
</>
);
if (mults.hacknet_node_purchase_cost_mult)
desc = (
<>
{desc}
<br />-{f(-(mults.hacknet_node_purchase_cost_mult - 1))} hacknet nodes
cost
</>
);
if (mults.hacknet_node_level_cost_mult)
desc = (
<>
{desc}
<br />-{f(-(mults.hacknet_node_level_cost_mult - 1))} hacknet nodes
upgrade cost
</>
);
if(mults.bladeburner_max_stamina_mult)
desc = <>{desc}<br />+{f(mults.bladeburner_max_stamina_mult-1)} Bladeburner Max Stamina</>
if(mults.bladeburner_stamina_gain_mult)
desc = <>{desc}<br />+{f(mults.bladeburner_stamina_gain_mult-1)} Bladeburner Stamina gain</>
if(mults.bladeburner_analysis_mult)
desc = <>{desc}<br />+{f(mults.bladeburner_analysis_mult-1)} Bladeburner Field Analysis effectiveness</>
if(mults.bladeburner_success_chance_mult)
desc = <>{desc}<br />+{f(mults.bladeburner_success_chance_mult-1)} Bladeburner Contracts and Operations success chance</>
if (mults.bladeburner_max_stamina_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_max_stamina_mult - 1)} Bladeburner Max
Stamina
</>
);
if (mults.bladeburner_stamina_gain_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_stamina_gain_mult - 1)} Bladeburner Stamina
gain
</>
);
if (mults.bladeburner_analysis_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_analysis_mult - 1)} Bladeburner Field
Analysis effectiveness
</>
);
if (mults.bladeburner_success_chance_mult)
desc = (
<>
{desc}
<br />+{f(mults.bladeburner_success_chance_mult - 1)} Bladeburner
Contracts and Operations success chance
</>
);
if(startingMoney)
desc = <>{desc}<br />Start with <Money money={startingMoney} /> after installing Augmentations.</>
if (startingMoney)
desc = (
<>
{desc}
<br />
Start with <Money money={startingMoney} /> after installing
Augmentations.
</>
);
if(programs)
desc = <>{desc}<br />Start with {programs.join(' and ')} after installing Augmentations.</>
return desc;
if (programs)
desc = (
<>
{desc}
<br />
Start with {programs.join(" and ")} after installing Augmentations.
</>
);
return desc;
}
export class Augmentation {
// How much money this costs to buy
baseCost = 0;
// How much money this costs to buy
baseCost = 0;
// How much faction reputation is required to unlock this
baseRepRequirement = 0;
// How much faction reputation is required to unlock this
baseRepRequirement = 0;
// Description of what this Aug is and what it does
info: string | JSX.Element;
// Description of what this Aug is and what it does
info: string | JSX.Element;
// Description of the stats, often autogenerated, sometimes manually written.
stats: JSX.Element;
// Description of the stats, often autogenerated, sometimes manually written.
stats: JSX.Element;
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
isSpecial = false;
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
isSpecial = false;
// Augmentation level - for repeatable Augs like NeuroFlux Governor
level = 0;
// Augmentation level - for repeatable Augs like NeuroFlux Governor
level = 0;
// Name of Augmentation
name = "";
// Name of Augmentation
name = "";
// Whether the player owns this Augmentation
owned = false;
// Whether the player owns this Augmentation
owned = false;
// Array of names of all prerequisites
prereqs: string[] = [];
// Array of names of all prerequisites
prereqs: string[] = [];
// Multipliers given by this Augmentation. Must match the property name in
// The Player/Person classes
mults: IMap<number> = {};
// Multipliers given by this Augmentation. Must match the property name in
// The Player/Person classes
mults: IMap<number> = {}
// Initial cost. Doesn't change when you purchase multiple Augmentation
startingCost = 0;
// Initial cost. Doesn't change when you purchase multiple Augmentation
startingCost = 0;
constructor(
params: IConstructorParams = {
info: "",
moneyCost: 0,
name: "",
repCost: 0,
},
) {
this.name = params.name;
this.info = params.info;
this.prereqs = params.prereqs ? params.prereqs : [];
constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) {
this.name = params.name;
this.info = params.info;
this.prereqs = params.prereqs ? params.prereqs : [];
this.baseRepRequirement =
params.repCost * BitNodeMultipliers.AugmentationRepCost;
this.baseCost = params.moneyCost * BitNodeMultipliers.AugmentationMoneyCost;
this.startingCost = this.baseCost;
this.baseRepRequirement = params.repCost * BitNodeMultipliers.AugmentationRepCost;
this.baseCost = params.moneyCost * BitNodeMultipliers.AugmentationMoneyCost;
this.startingCost = this.baseCost;
if (params.isSpecial) {
this.isSpecial = true;
}
if (params.isSpecial) {
this.isSpecial = true;
this.level = 0;
// Set multipliers
if (params.hacking_mult) {
this.mults.hacking_mult = params.hacking_mult;
}
if (params.strength_mult) {
this.mults.strength_mult = params.strength_mult;
}
if (params.defense_mult) {
this.mults.defense_mult = params.defense_mult;
}
if (params.dexterity_mult) {
this.mults.dexterity_mult = params.dexterity_mult;
}
if (params.agility_mult) {
this.mults.agility_mult = params.agility_mult;
}
if (params.charisma_mult) {
this.mults.charisma_mult = params.charisma_mult;
}
if (params.hacking_exp_mult) {
this.mults.hacking_exp_mult = params.hacking_exp_mult;
}
if (params.strength_exp_mult) {
this.mults.strength_exp_mult = params.strength_exp_mult;
}
if (params.defense_exp_mult) {
this.mults.defense_exp_mult = params.defense_exp_mult;
}
if (params.dexterity_exp_mult) {
this.mults.dexterity_exp_mult = params.dexterity_exp_mult;
}
if (params.agility_exp_mult) {
this.mults.agility_exp_mult = params.agility_exp_mult;
}
if (params.charisma_exp_mult) {
this.mults.charisma_exp_mult = params.charisma_exp_mult;
}
if (params.hacking_chance_mult) {
this.mults.hacking_chance_mult = params.hacking_chance_mult;
}
if (params.hacking_speed_mult) {
this.mults.hacking_speed_mult = params.hacking_speed_mult;
}
if (params.hacking_money_mult) {
this.mults.hacking_money_mult = params.hacking_money_mult;
}
if (params.hacking_grow_mult) {
this.mults.hacking_grow_mult = params.hacking_grow_mult;
}
if (params.company_rep_mult) {
this.mults.company_rep_mult = params.company_rep_mult;
}
if (params.faction_rep_mult) {
this.mults.faction_rep_mult = params.faction_rep_mult;
}
if (params.crime_money_mult) {
this.mults.crime_money_mult = params.crime_money_mult;
}
if (params.crime_success_mult) {
this.mults.crime_success_mult = params.crime_success_mult;
}
if (params.work_money_mult) {
this.mults.work_money_mult = params.work_money_mult;
}
if (params.hacknet_node_money_mult) {
this.mults.hacknet_node_money_mult = params.hacknet_node_money_mult;
}
if (params.hacknet_node_purchase_cost_mult) {
this.mults.hacknet_node_purchase_cost_mult =
params.hacknet_node_purchase_cost_mult;
}
if (params.hacknet_node_ram_cost_mult) {
this.mults.hacknet_node_ram_cost_mult = params.hacknet_node_ram_cost_mult;
}
if (params.hacknet_node_core_cost_mult) {
this.mults.hacknet_node_core_cost_mult =
params.hacknet_node_core_cost_mult;
}
if (params.hacknet_node_level_cost_mult) {
this.mults.hacknet_node_level_cost_mult =
params.hacknet_node_level_cost_mult;
}
if (params.bladeburner_max_stamina_mult) {
this.mults.bladeburner_max_stamina_mult =
params.bladeburner_max_stamina_mult;
}
if (params.bladeburner_stamina_gain_mult) {
this.mults.bladeburner_stamina_gain_mult =
params.bladeburner_stamina_gain_mult;
}
if (params.bladeburner_analysis_mult) {
this.mults.bladeburner_analysis_mult = params.bladeburner_analysis_mult;
}
if (params.bladeburner_success_chance_mult) {
this.mults.bladeburner_success_chance_mult =
params.bladeburner_success_chance_mult;
}
if (params.stats) this.stats = params.stats;
else
this.stats = generateStatsDescription(
this.mults,
params.programs,
params.startingMoney,
);
}
// Adds this Augmentation to the specified Factions
addToFactions(factionList: string[]): void {
for (let i = 0; i < factionList.length; ++i) {
const faction: Faction | null = Factions[factionList[i]];
if (faction == null) {
console.warn(
`In Augmentation.addToFactions(), could not find faction with this name: ${factionList[i]}`,
);
continue;
}
faction.augmentations.push(this.name);
}
}
// Adds this Augmentation to all Factions
addToAllFactions(): void {
for (const fac in Factions) {
if (Factions.hasOwnProperty(fac)) {
const facObj: Faction | null = Factions[fac];
if (facObj == null) {
console.warn(
`Invalid Faction object in addToAllFactions(). Key value: ${fac}`,
);
continue;
}
this.level = 0;
// Set multipliers
if (params.hacking_mult) { this.mults.hacking_mult = params.hacking_mult; }
if (params.strength_mult) { this.mults.strength_mult = params.strength_mult; }
if (params.defense_mult) { this.mults.defense_mult = params.defense_mult; }
if (params.dexterity_mult) { this.mults.dexterity_mult = params.dexterity_mult; }
if (params.agility_mult) { this.mults.agility_mult = params.agility_mult; }
if (params.charisma_mult) { this.mults.charisma_mult = params.charisma_mult; }
if (params.hacking_exp_mult) { this.mults.hacking_exp_mult = params.hacking_exp_mult; }
if (params.strength_exp_mult) { this.mults.strength_exp_mult = params.strength_exp_mult; }
if (params.defense_exp_mult) { this.mults.defense_exp_mult = params.defense_exp_mult; }
if (params.dexterity_exp_mult) { this.mults.dexterity_exp_mult = params.dexterity_exp_mult; }
if (params.agility_exp_mult) { this.mults.agility_exp_mult = params.agility_exp_mult; }
if (params.charisma_exp_mult) { this.mults.charisma_exp_mult = params.charisma_exp_mult; }
if (params.hacking_chance_mult) { this.mults.hacking_chance_mult = params.hacking_chance_mult; }
if (params.hacking_speed_mult) { this.mults.hacking_speed_mult = params.hacking_speed_mult; }
if (params.hacking_money_mult) { this.mults.hacking_money_mult = params.hacking_money_mult; }
if (params.hacking_grow_mult) { this.mults.hacking_grow_mult = params.hacking_grow_mult; }
if (params.company_rep_mult) { this.mults.company_rep_mult = params.company_rep_mult; }
if (params.faction_rep_mult) { this.mults.faction_rep_mult = params.faction_rep_mult; }
if (params.crime_money_mult) { this.mults.crime_money_mult = params.crime_money_mult; }
if (params.crime_success_mult) { this.mults.crime_success_mult = params.crime_success_mult; }
if (params.work_money_mult) { this.mults.work_money_mult = params.work_money_mult; }
if (params.hacknet_node_money_mult) { this.mults.hacknet_node_money_mult = params.hacknet_node_money_mult; }
if (params.hacknet_node_purchase_cost_mult) { this.mults.hacknet_node_purchase_cost_mult = params.hacknet_node_purchase_cost_mult; }
if (params.hacknet_node_ram_cost_mult) { this.mults.hacknet_node_ram_cost_mult = params.hacknet_node_ram_cost_mult; }
if (params.hacknet_node_core_cost_mult) { this.mults.hacknet_node_core_cost_mult = params.hacknet_node_core_cost_mult; }
if (params.hacknet_node_level_cost_mult) { this.mults.hacknet_node_level_cost_mult = params.hacknet_node_level_cost_mult; }
if (params.bladeburner_max_stamina_mult) { this.mults.bladeburner_max_stamina_mult = params.bladeburner_max_stamina_mult; }
if (params.bladeburner_stamina_gain_mult) { this.mults.bladeburner_stamina_gain_mult = params.bladeburner_stamina_gain_mult; }
if (params.bladeburner_analysis_mult) { this.mults.bladeburner_analysis_mult = params.bladeburner_analysis_mult; }
if (params.bladeburner_success_chance_mult) { this.mults.bladeburner_success_chance_mult = params.bladeburner_success_chance_mult; }
if(params.stats)
this.stats = params.stats;
else
this.stats = generateStatsDescription(this.mults, params.programs, params.startingMoney);
facObj.augmentations.push(this.name);
}
}
}
// Adds this Augmentation to the specified Factions
addToFactions(factionList: string[]): void {
for (let i = 0; i < factionList.length; ++i) {
const faction: Faction | null = Factions[factionList[i]];
if (faction == null) {
console.warn(`In Augmentation.addToFactions(), could not find faction with this name: ${factionList[i]}`);
continue;
}
faction.augmentations.push(this.name);
}
}
// Serialize the current object to a JSON save state.
toJSON(): any {
return Generic_toJSON("Augmentation", this);
}
// Adds this Augmentation to all Factions
addToAllFactions(): void {
for (const fac in Factions) {
if (Factions.hasOwnProperty(fac)) {
const facObj: Faction | null = Factions[fac];
if (facObj == null) {
console.warn(`Invalid Faction object in addToAllFactions(). Key value: ${fac}`);
continue;
}
facObj.augmentations.push(this.name);
}
}
}
// Serialize the current object to a JSON save state.
toJSON(): any {
return Generic_toJSON("Augmentation", this);
}
// Initiatizes a Augmentation object from a JSON save state.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Augmentation {
return Generic_fromJSON(Augmentation, value.data);
}
// Initiatizes a Augmentation object from a JSON save state.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Augmentation {
return Generic_fromJSON(Augmentation, value.data);
}
}
Reviver.constructors.Augmentation = Augmentation;

File diff suppressed because it is too large Load Diff

@ -1,13 +1,13 @@
export class PlayerOwnedAugmentation {
level = 1;
name = "";
level = 1;
name = "";
constructor(name = "") {
this.name = name;
}
constructor(name = "") {
this.name = name;
}
}
export interface IPlayerOwnedAugmentation {
level: number;
name: string;
level: number;
name: string;
}

@ -1,118 +1,118 @@
import { IMap } from "../../types";
export const AugmentationNames: IMap<string> = {
Targeting1: "Augmented Targeting I",
Targeting2: "Augmented Targeting II",
Targeting3: "Augmented Targeting III",
SyntheticHeart: "Synthetic Heart",
SynfibrilMuscle: "Synfibril Muscle",
CombatRib1: "Combat Rib I",
CombatRib2: "Combat Rib II",
CombatRib3: "Combat Rib III",
NanofiberWeave: "Nanofiber Weave",
SubdermalArmor: "NEMEAN Subdermal Weave",
WiredReflexes: "Wired Reflexes",
GrapheneBoneLacings: "Graphene Bone Lacings",
BionicSpine: "Bionic Spine",
GrapheneBionicSpine: "Graphene Bionic Spine Upgrade",
BionicLegs: "Bionic Legs",
GrapheneBionicLegs: "Graphene Bionic Legs Upgrade",
SpeechProcessor: "Speech Processor Implant",
TITN41Injection: "TITN-41 Gene-Modification Injection",
EnhancedSocialInteractionImplant: "Enhanced Social Interaction Implant",
BitWire: "BitWire",
ArtificialBioNeuralNetwork: "Artificial Bio-neural Network Implant",
ArtificialSynapticPotentiation: "Artificial Synaptic Potentiation",
EnhancedMyelinSheathing: "Enhanced Myelin Sheathing",
SynapticEnhancement: "Synaptic Enhancement Implant",
NeuralRetentionEnhancement: "Neural-Retention Enhancement",
DataJack: "DataJack",
ENM: "Embedded Netburner Module",
ENMCore: "Embedded Netburner Module Core Implant",
ENMCoreV2: "Embedded Netburner Module Core V2 Upgrade",
ENMCoreV3: "Embedded Netburner Module Core V3 Upgrade",
ENMAnalyzeEngine: "Embedded Netburner Module Analyze Engine",
ENMDMA: "Embedded Netburner Module Direct Memory Access Upgrade",
Neuralstimulator: "Neuralstimulator",
NeuralAccelerator: "Neural Accelerator",
CranialSignalProcessorsG1: "Cranial Signal Processors - Gen I",
CranialSignalProcessorsG2: "Cranial Signal Processors - Gen II",
CranialSignalProcessorsG3: "Cranial Signal Processors - Gen III",
CranialSignalProcessorsG4: "Cranial Signal Processors - Gen IV",
CranialSignalProcessorsG5: "Cranial Signal Processors - Gen V",
NeuronalDensification: "Neuronal Densification",
NuoptimalInjectorImplant: "Nuoptimal Nootropic Injector Implant",
SpeechEnhancement: "Speech Enhancement",
FocusWire: "FocusWire",
PCDNI: "PC Direct-Neural Interface",
PCDNIOptimizer: "PC Direct-Neural Interface Optimization Submodule",
PCDNINeuralNetwork: "PC Direct-Neural Interface NeuroNet Injector",
PCMatrix: "PCMatrix",
ADRPheromone1: "ADR-V1 Pheromone Gene",
ADRPheromone2: "ADR-V2 Pheromone Gene",
ShadowsSimulacrum: "The Shadow's Simulacrum",
HacknetNodeCPUUpload: "Hacknet Node CPU Architecture Neural-Upload",
HacknetNodeCacheUpload: "Hacknet Node Cache Architecture Neural-Upload",
HacknetNodeNICUpload: "Hacknet Node NIC Architecture Neural-Upload",
HacknetNodeKernelDNI: "Hacknet Node Kernel Direct-Neural Interface",
HacknetNodeCoreDNI: "Hacknet Node Core Direct-Neural Interface",
NeuroFluxGovernor: "NeuroFlux Governor",
Neurotrainer1: "Neurotrainer I",
Neurotrainer2: "Neurotrainer II",
Neurotrainer3: "Neurotrainer III",
Hypersight: "HyperSight Corneal Implant",
LuminCloaking1: "LuminCloaking-V1 Skin Implant",
LuminCloaking2: "LuminCloaking-V2 Skin Implant",
HemoRecirculator: "HemoRecirculator",
SmartSonar: "SmartSonar Implant",
PowerRecirculator: "Power Recirculation Core",
QLink: "QLink",
TheRedPill: "The Red Pill",
SPTN97: "SPTN-97 Gene Modification",
HiveMind: "ECorp HVMind Implant",
CordiARCReactor: "CordiARC Fusion Reactor",
SmartJaw: "SmartJaw",
Neotra: "Neotra",
Xanipher: "Xanipher",
nextSENS: "nextSENS Gene Modification",
OmniTekInfoLoad: "OmniTek InfoLoad",
PhotosyntheticCells: "Photosynthetic Cells",
Neurolink: "BitRunners Neurolink",
TheBlackHand: "The Black Hand",
UnstableCircadianModulator: "Unstable Circadian Modulator",
CRTX42AA: "CRTX42-AA Gene Modification",
Neuregen: "Neuregen Gene Modification",
CashRoot: "CashRoot Starter Kit",
NutriGen: "NutriGen Implant",
INFRARet: "INFRARET Enhancement",
DermaForce: "DermaForce Particle Barrier",
GrapheneBrachiBlades: "Graphene BranchiBlades Upgrade",
GrapheneBionicArms: "Graphene Bionic Arms Upgrade",
BrachiBlades: "BrachiBlades",
BionicArms: "Bionic Arms",
SNA: "Social Negotiation Assistant (S.N.A)",
HydroflameLeftArm: "Hydroflame Left Arm",
EsperEyewear: "EsperTech Bladeburner Eyewear",
EMS4Recombination: "EMS-4 Recombination",
OrionShoulder: "ORION-MKIV Shoulder",
HyperionV1: "Hyperion Plasma Cannon V1",
HyperionV2: "Hyperion Plasma Cannon V2",
GolemSerum: "GOLEM Serum",
VangelisVirus: "Vangelis Virus",
VangelisVirus3: "Vangelis Virus 3.0",
INTERLINKED: "I.N.T.E.R.L.I.N.K.E.D",
BladeRunner: "Blade's Runners",
BladeArmor: "BLADE-51b Tesla Armor",
BladeArmorPowerCells: "BLADE-51b Tesla Armor: Power Cells Upgrade",
BladeArmorEnergyShielding: "BLADE-51b Tesla Armor: Energy Shielding Upgrade",
BladeArmorUnibeam: "BLADE-51b Tesla Armor: Unibeam Upgrade",
BladeArmorOmnibeam: "BLADE-51b Tesla Armor: Omnibeam Upgrade",
BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade",
BladesSimulacrum: "The Blade's Simulacrum",
Targeting1: "Augmented Targeting I",
Targeting2: "Augmented Targeting II",
Targeting3: "Augmented Targeting III",
SyntheticHeart: "Synthetic Heart",
SynfibrilMuscle: "Synfibril Muscle",
CombatRib1: "Combat Rib I",
CombatRib2: "Combat Rib II",
CombatRib3: "Combat Rib III",
NanofiberWeave: "Nanofiber Weave",
SubdermalArmor: "NEMEAN Subdermal Weave",
WiredReflexes: "Wired Reflexes",
GrapheneBoneLacings: "Graphene Bone Lacings",
BionicSpine: "Bionic Spine",
GrapheneBionicSpine: "Graphene Bionic Spine Upgrade",
BionicLegs: "Bionic Legs",
GrapheneBionicLegs: "Graphene Bionic Legs Upgrade",
SpeechProcessor: "Speech Processor Implant",
TITN41Injection: "TITN-41 Gene-Modification Injection",
EnhancedSocialInteractionImplant: "Enhanced Social Interaction Implant",
BitWire: "BitWire",
ArtificialBioNeuralNetwork: "Artificial Bio-neural Network Implant",
ArtificialSynapticPotentiation: "Artificial Synaptic Potentiation",
EnhancedMyelinSheathing: "Enhanced Myelin Sheathing",
SynapticEnhancement: "Synaptic Enhancement Implant",
NeuralRetentionEnhancement: "Neural-Retention Enhancement",
DataJack: "DataJack",
ENM: "Embedded Netburner Module",
ENMCore: "Embedded Netburner Module Core Implant",
ENMCoreV2: "Embedded Netburner Module Core V2 Upgrade",
ENMCoreV3: "Embedded Netburner Module Core V3 Upgrade",
ENMAnalyzeEngine: "Embedded Netburner Module Analyze Engine",
ENMDMA: "Embedded Netburner Module Direct Memory Access Upgrade",
Neuralstimulator: "Neuralstimulator",
NeuralAccelerator: "Neural Accelerator",
CranialSignalProcessorsG1: "Cranial Signal Processors - Gen I",
CranialSignalProcessorsG2: "Cranial Signal Processors - Gen II",
CranialSignalProcessorsG3: "Cranial Signal Processors - Gen III",
CranialSignalProcessorsG4: "Cranial Signal Processors - Gen IV",
CranialSignalProcessorsG5: "Cranial Signal Processors - Gen V",
NeuronalDensification: "Neuronal Densification",
NuoptimalInjectorImplant: "Nuoptimal Nootropic Injector Implant",
SpeechEnhancement: "Speech Enhancement",
FocusWire: "FocusWire",
PCDNI: "PC Direct-Neural Interface",
PCDNIOptimizer: "PC Direct-Neural Interface Optimization Submodule",
PCDNINeuralNetwork: "PC Direct-Neural Interface NeuroNet Injector",
PCMatrix: "PCMatrix",
ADRPheromone1: "ADR-V1 Pheromone Gene",
ADRPheromone2: "ADR-V2 Pheromone Gene",
ShadowsSimulacrum: "The Shadow's Simulacrum",
HacknetNodeCPUUpload: "Hacknet Node CPU Architecture Neural-Upload",
HacknetNodeCacheUpload: "Hacknet Node Cache Architecture Neural-Upload",
HacknetNodeNICUpload: "Hacknet Node NIC Architecture Neural-Upload",
HacknetNodeKernelDNI: "Hacknet Node Kernel Direct-Neural Interface",
HacknetNodeCoreDNI: "Hacknet Node Core Direct-Neural Interface",
NeuroFluxGovernor: "NeuroFlux Governor",
Neurotrainer1: "Neurotrainer I",
Neurotrainer2: "Neurotrainer II",
Neurotrainer3: "Neurotrainer III",
Hypersight: "HyperSight Corneal Implant",
LuminCloaking1: "LuminCloaking-V1 Skin Implant",
LuminCloaking2: "LuminCloaking-V2 Skin Implant",
HemoRecirculator: "HemoRecirculator",
SmartSonar: "SmartSonar Implant",
PowerRecirculator: "Power Recirculation Core",
QLink: "QLink",
TheRedPill: "The Red Pill",
SPTN97: "SPTN-97 Gene Modification",
HiveMind: "ECorp HVMind Implant",
CordiARCReactor: "CordiARC Fusion Reactor",
SmartJaw: "SmartJaw",
Neotra: "Neotra",
Xanipher: "Xanipher",
nextSENS: "nextSENS Gene Modification",
OmniTekInfoLoad: "OmniTek InfoLoad",
PhotosyntheticCells: "Photosynthetic Cells",
Neurolink: "BitRunners Neurolink",
TheBlackHand: "The Black Hand",
UnstableCircadianModulator: "Unstable Circadian Modulator",
CRTX42AA: "CRTX42-AA Gene Modification",
Neuregen: "Neuregen Gene Modification",
CashRoot: "CashRoot Starter Kit",
NutriGen: "NutriGen Implant",
INFRARet: "INFRARET Enhancement",
DermaForce: "DermaForce Particle Barrier",
GrapheneBrachiBlades: "Graphene BranchiBlades Upgrade",
GrapheneBionicArms: "Graphene Bionic Arms Upgrade",
BrachiBlades: "BrachiBlades",
BionicArms: "Bionic Arms",
SNA: "Social Negotiation Assistant (S.N.A)",
HydroflameLeftArm: "Hydroflame Left Arm",
EsperEyewear: "EsperTech Bladeburner Eyewear",
EMS4Recombination: "EMS-4 Recombination",
OrionShoulder: "ORION-MKIV Shoulder",
HyperionV1: "Hyperion Plasma Cannon V1",
HyperionV2: "Hyperion Plasma Cannon V2",
GolemSerum: "GOLEM Serum",
VangelisVirus: "Vangelis Virus",
VangelisVirus3: "Vangelis Virus 3.0",
INTERLINKED: "I.N.T.E.R.L.I.N.K.E.D",
BladeRunner: "Blade's Runners",
BladeArmor: "BLADE-51b Tesla Armor",
BladeArmorPowerCells: "BLADE-51b Tesla Armor: Power Cells Upgrade",
BladeArmorEnergyShielding: "BLADE-51b Tesla Armor: Energy Shielding Upgrade",
BladeArmorUnibeam: "BLADE-51b Tesla Armor: Unibeam Upgrade",
BladeArmorOmnibeam: "BLADE-51b Tesla Armor: Omnibeam Upgrade",
BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade",
BladesSimulacrum: "The Blade's Simulacrum",
//Wasteland Augs
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System
//PepBoyForceField Generates plasma force fields
//PepBoyBlasts Generate high density plasma concussive blasts
//PepBoyDataStorage STore more data on pep boy,
}
//Wasteland Augs
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System
//PepBoyForceField Generates plasma force fields
//PepBoyBlasts Generate high density plasma concussive blasts
//PepBoyDataStorage STore more data on pep boy,
};

@ -13,30 +13,31 @@ import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
export function InstalledAugmentations(): React.ReactElement {
const sourceAugs = Player.augmentations.slice();
const sourceAugs = Player.augmentations.slice();
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
sourceAugs.sort((aug1, aug2) => {
return aug1.name <= aug2.name ? -1 : 1;
});
if (
Settings.OwnedAugmentationsOrder ===
OwnedAugmentationsOrderSetting.Alphabetically
) {
sourceAugs.sort((aug1, aug2) => {
return aug1.name <= aug2.name ? -1 : 1;
});
}
const augs = sourceAugs.map((e) => {
const aug = Augmentations[e.name];
let level = null;
if (e.name === AugmentationNames.NeuroFluxGovernor) {
level = e.level;
}
const augs = sourceAugs.map((e) => {
const aug = Augmentations[e.name];
let level = null;
if (e.name === AugmentationNames.NeuroFluxGovernor) {
level = e.level;
}
return (
<li key={e.name}>
<AugmentationAccordion aug={aug} level={level} />
</li>
)
});
return (
<>{augs}</>
)
<li key={e.name}>
<AugmentationAccordion aug={aug} level={level} />
</li>
);
});
return <>{augs}</>;
}

@ -16,96 +16,105 @@ import { Settings } from "../../Settings/Settings";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
type IProps = {
// nothing special.
}
// nothing special.
};
type IState = {
rerenderFlag: boolean;
}
export class InstalledAugmentationsAndSourceFiles extends React.Component<IProps, IState> {
listRef: React.RefObject<HTMLUListElement>;
constructor(props: IProps) {
super(props);
this.state = {
rerenderFlag: false,
}
this.collapseAllHeaders = this.collapseAllHeaders.bind(this);
this.expandAllHeaders = this.expandAllHeaders.bind(this);
this.sortByAcquirementTime = this.sortByAcquirementTime.bind(this);
this.sortInOrder = this.sortInOrder.bind(this);
this.listRef = React.createRef();
}
collapseAllHeaders(): void {
const ul = this.listRef.current;
if (ul == null) { return; }
const tickers = ul.getElementsByClassName("accordion-header");
for (let i = 0; i < tickers.length; ++i) {
const ticker = tickers[i];
if (!(ticker instanceof HTMLButtonElement)) {
continue;
}
if (ticker.classList.contains("active")) {
ticker.click();
}
}
}
expandAllHeaders(): void {
const ul = this.listRef.current;
if (ul == null) { return; }
const tickers = ul.getElementsByClassName("accordion-header");
for (let i = 0; i < tickers.length; ++i) {
const ticker = tickers[i];
if (!(ticker instanceof HTMLButtonElement)) {
continue;
}
if (!ticker.classList.contains("active")) {
ticker.click();
}
}
}
rerender(): void {
this.setState((prevState) => {
return {
rerenderFlag: !prevState.rerenderFlag,
}
});
}
sortByAcquirementTime(): void {
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime;
this.rerender();
}
sortInOrder(): void {
Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically
this.rerender();
}
render(): React.ReactNode {
return (
<>
<ListConfiguration
collapseAllButtonsFn={this.collapseAllHeaders}
expandAllButtonsFn={this.expandAllHeaders}
sortByAcquirementTimeFn={this.sortByAcquirementTime}
sortInOrderFn={this.sortInOrder}
/>
<ul className="augmentations-list" ref={this.listRef}>
<SourceFileMinus1 />
<OwnedSourceFiles />
<InstalledAugmentations />
</ul>
</>
)
}
rerenderFlag: boolean;
};
export class InstalledAugmentationsAndSourceFiles extends React.Component<
IProps,
IState
> {
listRef: React.RefObject<HTMLUListElement>;
constructor(props: IProps) {
super(props);
this.state = {
rerenderFlag: false,
};
this.collapseAllHeaders = this.collapseAllHeaders.bind(this);
this.expandAllHeaders = this.expandAllHeaders.bind(this);
this.sortByAcquirementTime = this.sortByAcquirementTime.bind(this);
this.sortInOrder = this.sortInOrder.bind(this);
this.listRef = React.createRef();
}
collapseAllHeaders(): void {
const ul = this.listRef.current;
if (ul == null) {
return;
}
const tickers = ul.getElementsByClassName("accordion-header");
for (let i = 0; i < tickers.length; ++i) {
const ticker = tickers[i];
if (!(ticker instanceof HTMLButtonElement)) {
continue;
}
if (ticker.classList.contains("active")) {
ticker.click();
}
}
}
expandAllHeaders(): void {
const ul = this.listRef.current;
if (ul == null) {
return;
}
const tickers = ul.getElementsByClassName("accordion-header");
for (let i = 0; i < tickers.length; ++i) {
const ticker = tickers[i];
if (!(ticker instanceof HTMLButtonElement)) {
continue;
}
if (!ticker.classList.contains("active")) {
ticker.click();
}
}
}
rerender(): void {
this.setState((prevState) => {
return {
rerenderFlag: !prevState.rerenderFlag,
};
});
}
sortByAcquirementTime(): void {
Settings.OwnedAugmentationsOrder =
OwnedAugmentationsOrderSetting.AcquirementTime;
this.rerender();
}
sortInOrder(): void {
Settings.OwnedAugmentationsOrder =
OwnedAugmentationsOrderSetting.Alphabetically;
this.rerender();
}
render(): React.ReactNode {
return (
<>
<ListConfiguration
collapseAllButtonsFn={this.collapseAllHeaders}
expandAllButtonsFn={this.expandAllHeaders}
sortByAcquirementTimeFn={this.sortByAcquirementTime}
sortInOrderFn={this.sortInOrder}
/>
<ul className="augmentations-list" ref={this.listRef}>
<SourceFileMinus1 />
<OwnedSourceFiles />
<InstalledAugmentations />
</ul>
</>
);
}
}

@ -7,33 +7,27 @@ import * as React from "react";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
collapseAllButtonsFn: () => void;
expandAllButtonsFn: () => void;
sortByAcquirementTimeFn: () => void;
sortInOrderFn: () => void;
}
collapseAllButtonsFn: () => void;
expandAllButtonsFn: () => void;
sortByAcquirementTimeFn: () => void;
sortInOrderFn: () => void;
};
export function ListConfiguration(props: IProps): React.ReactElement {
return (
<>
<StdButton
onClick={props.expandAllButtonsFn}
text="Expand All"
/>
<StdButton
onClick={props.collapseAllButtonsFn}
text="Collapse All"
/>
<StdButton
onClick={props.sortInOrderFn}
text="Sort in Order"
tooltip="Sorts the Augmentations alphabetically and Source-Files in numeral order"
/>
<StdButton
onClick={props.sortByAcquirementTimeFn}
text="Sort by Acquirement Time"
tooltip="Sorts the Augmentations and Source-Files based on when you acquired them (same as default)"
/>
</>
)
return (
<>
<StdButton onClick={props.expandAllButtonsFn} text="Expand All" />
<StdButton onClick={props.collapseAllButtonsFn} text="Collapse All" />
<StdButton
onClick={props.sortInOrderFn}
text="Sort in Order"
tooltip="Sorts the Augmentations alphabetically and Source-Files in numeral order"
/>
<StdButton
onClick={props.sortByAcquirementTimeFn}
text="Sort by Acquirement Time"
tooltip="Sorts the Augmentations and Source-Files based on when you acquired them (same as default)"
/>
</>
);
}

@ -12,30 +12,31 @@ import { SourceFiles } from "../../SourceFile/SourceFiles";
import { SourceFileAccordion } from "../../ui/React/SourceFileAccordion";
export function OwnedSourceFiles(): React.ReactElement {
const sourceSfs = Player.sourceFiles.slice();
const sourceSfs = Player.sourceFiles.slice();
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
sourceSfs.sort((sf1, sf2) => {
return sf1.n - sf2.n;
});
if (
Settings.OwnedAugmentationsOrder ===
OwnedAugmentationsOrderSetting.Alphabetically
) {
sourceSfs.sort((sf1, sf2) => {
return sf1.n - sf2.n;
});
}
const sfs = sourceSfs.map((e) => {
const srcFileKey = "SourceFile" + e.n;
const sfObj = SourceFiles[srcFileKey];
if (sfObj == null) {
console.error(`Invalid source file number: ${e.n}`);
return null;
}
const sfs = sourceSfs.map((e) => {
const srcFileKey = "SourceFile" + e.n;
const sfObj = SourceFiles[srcFileKey];
if (sfObj == null) {
console.error(`Invalid source file number: ${e.n}`);
return null;
}
return (
<li key={e.n}>
<SourceFileAccordion level={e.lvl} sf={sfObj} />
</li>
)
});
return (
<>{sfs}</>
<li key={e.n}>
<SourceFileAccordion level={e.lvl} sf={sfObj} />
</li>
);
});
return <>{sfs}</>;
}

@ -5,118 +5,269 @@ import * as React from "react";
import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Augmentations} from "../Augmentations";
import { Augmentations } from "../Augmentations";
function calculateAugmentedStats(): any {
const augP: any = {};
for(const aug of Player.queuedAugmentations) {
const augObj = Augmentations[aug.name];
for (const mult in augObj.mults) {
const v = augP[mult] ? augP[mult] : 1;
augP[mult] = v * augObj.mults[mult];
}
const augP: any = {};
for (const aug of Player.queuedAugmentations) {
const augObj = Augmentations[aug.name];
for (const mult in augObj.mults) {
const v = augP[mult] ? augP[mult] : 1;
augP[mult] = v * augObj.mults[mult];
}
return augP;
}
return augP;
}
export function PlayerMultipliers(): React.ReactElement {
const mults = calculateAugmentedStats();
function MultiplierTable(rows: any[]): React.ReactElement {
function improvements(r: number): JSX.Element[] {
let elems: JSX.Element[] = [];
if(r) {
elems = [
<td key="2">&nbsp;{"=>"}&nbsp;</td>,
<td key="3">{numeralWrapper.formatPercentage(r)}</td>,
];
}
return elems;
}
return <table>
<tbody>
{rows.map((r: any) => <tr key={r[0]}>
<td key="0"><span>{r[0]} multiplier:&nbsp;</span></td>
<td key="1" style={{textAlign: 'right'}}>{numeralWrapper.formatPercentage(r[1])}</td>
{improvements(r[2])}
</tr>)}
</tbody>
</table>
}
function BladeburnerMults(): React.ReactElement {
if(!Player.canAccessBladeburner()) return (<></>);
return (<>
{MultiplierTable([
['Bladeburner Success Chance', Player.bladeburner_success_chance_mult, Player.bladeburner_success_chance_mult*mults.bladeburner_success_chance_mult],
['Bladeburner Max Stamina', Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult*mults.bladeburner_max_stamina_mult],
['Bladeburner Stamina Gain', Player.bladeburner_stamina_gain_mult, Player.bladeburner_stamina_gain_mult*mults.bladeburner_stamina_gain_mult],
['Bladeburner Field Analysis', Player.bladeburner_analysis_mult, Player.bladeburner_analysis_mult*mults.bladeburner_analysis_mult],
])}<br />
</>);
const mults = calculateAugmentedStats();
function MultiplierTable(rows: any[]): React.ReactElement {
function improvements(r: number): JSX.Element[] {
let elems: JSX.Element[] = [];
if (r) {
elems = [
<td key="2">&nbsp;{"=>"}&nbsp;</td>,
<td key="3">{numeralWrapper.formatPercentage(r)}</td>,
];
}
return elems;
}
return (
<>
<p><strong><u>Multipliers:</u></strong></p><br />
<table>
<tbody>
{rows.map((r: any) => (
<tr key={r[0]}>
<td key="0">
<span>{r[0]} multiplier:&nbsp;</span>
</td>
<td key="1" style={{ textAlign: "right" }}>
{numeralWrapper.formatPercentage(r[1])}
</td>
{improvements(r[2])}
</tr>
))}
</tbody>
</table>
);
}
function BladeburnerMults(): React.ReactElement {
if (!Player.canAccessBladeburner()) return <></>;
return (
<>
{MultiplierTable([
['Hacking Chance ', Player.hacking_chance_mult, Player.hacking_chance_mult*mults.hacking_chance_mult],
['Hacking Speed ', Player.hacking_speed_mult, Player.hacking_speed_mult*mults.hacking_speed_mult],
['Hacking Money ', Player.hacking_money_mult, Player.hacking_money_mult*mults.hacking_money_mult],
['Hacking Growth ', Player.hacking_grow_mult, Player.hacking_grow_mult*mults.hacking_grow_mult],
])}<br />
[
"Bladeburner Success Chance",
Player.bladeburner_success_chance_mult,
Player.bladeburner_success_chance_mult *
mults.bladeburner_success_chance_mult,
],
[
"Bladeburner Max Stamina",
Player.bladeburner_max_stamina_mult,
Player.bladeburner_max_stamina_mult *
mults.bladeburner_max_stamina_mult,
],
[
"Bladeburner Stamina Gain",
Player.bladeburner_stamina_gain_mult,
Player.bladeburner_stamina_gain_mult *
mults.bladeburner_stamina_gain_mult,
],
[
"Bladeburner Field Analysis",
Player.bladeburner_analysis_mult,
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
],
])}
<br />
</>
);
}
{MultiplierTable([
['Hacking Level ', Player.hacking_mult, Player.hacking_mult*mults.hacking_mult],
['Hacking Experience ', Player.hacking_exp_mult, Player.hacking_exp_mult*mults.hacking_exp_mult],
])}<br />
return (
<>
<p>
<strong>
<u>Multipliers:</u>
</strong>
</p>
<br />
{MultiplierTable([
[
"Hacking Chance ",
Player.hacking_chance_mult,
Player.hacking_chance_mult * mults.hacking_chance_mult,
],
[
"Hacking Speed ",
Player.hacking_speed_mult,
Player.hacking_speed_mult * mults.hacking_speed_mult,
],
[
"Hacking Money ",
Player.hacking_money_mult,
Player.hacking_money_mult * mults.hacking_money_mult,
],
[
"Hacking Growth ",
Player.hacking_grow_mult,
Player.hacking_grow_mult * mults.hacking_grow_mult,
],
])}
<br />
{MultiplierTable([
[
"Hacking Level ",
Player.hacking_mult,
Player.hacking_mult * mults.hacking_mult,
],
[
"Hacking Experience ",
Player.hacking_exp_mult,
Player.hacking_exp_mult * mults.hacking_exp_mult,
],
])}
<br />
{MultiplierTable([
['Strength Level ', Player.strength_mult, Player.strength_mult*mults.strength_mult],
['Strength Experience ', Player.strength_exp_mult, Player.strength_exp_mult*mults.strength_exp_mult],
])}<br />
{MultiplierTable([
[
"Strength Level ",
Player.strength_mult,
Player.strength_mult * mults.strength_mult,
],
[
"Strength Experience ",
Player.strength_exp_mult,
Player.strength_exp_mult * mults.strength_exp_mult,
],
])}
<br />
{MultiplierTable([
['Defense Level ', Player.defense_mult, Player.defense_mult*mults.defense_mult],
['Defense Experience ', Player.defense_exp_mult, Player.defense_exp_mult*mults.defense_exp_mult],
])}<br />
{MultiplierTable([
[
"Defense Level ",
Player.defense_mult,
Player.defense_mult * mults.defense_mult,
],
[
"Defense Experience ",
Player.defense_exp_mult,
Player.defense_exp_mult * mults.defense_exp_mult,
],
])}
<br />
{MultiplierTable([
['Dexterity Level ', Player.dexterity_mult, Player.dexterity_mult*mults.dexterity_mult],
['Dexterity Experience ', Player.dexterity_exp_mult, Player.dexterity_exp_mult*mults.dexterity_exp_mult],
])}<br />
{MultiplierTable([
[
"Dexterity Level ",
Player.dexterity_mult,
Player.dexterity_mult * mults.dexterity_mult,
],
[
"Dexterity Experience ",
Player.dexterity_exp_mult,
Player.dexterity_exp_mult * mults.dexterity_exp_mult,
],
])}
<br />
{MultiplierTable([
['Agility Level ', Player.agility_mult, Player.agility_mult*mults.agility_mult],
['Agility Experience ', Player.agility_exp_mult, Player.agility_exp_mult*mults.agility_exp_mult],
])}<br />
{MultiplierTable([
[
"Agility Level ",
Player.agility_mult,
Player.agility_mult * mults.agility_mult,
],
[
"Agility Experience ",
Player.agility_exp_mult,
Player.agility_exp_mult * mults.agility_exp_mult,
],
])}
<br />
{MultiplierTable([
['Charisma Level ', Player.charisma_mult, Player.charisma_mult*mults.charisma_mult],
['Charisma Experience ', Player.charisma_exp_mult, Player.charisma_exp_mult*mults.charisma_exp_mult],
])}<br />
{MultiplierTable([
[
"Charisma Level ",
Player.charisma_mult,
Player.charisma_mult * mults.charisma_mult,
],
[
"Charisma Experience ",
Player.charisma_exp_mult,
Player.charisma_exp_mult * mults.charisma_exp_mult,
],
])}
<br />
{MultiplierTable([
['Hacknet Node production ', Player.hacknet_node_money_mult, Player.hacknet_node_money_mult*mults.hacknet_node_money_mult],
['Hacknet Node purchase cost ', Player.hacknet_node_purchase_cost_mult, Player.hacknet_node_purchase_cost_mult*mults.hacknet_node_purchase_cost_mult],
['Hacknet Node RAM upgrade cost ', Player.hacknet_node_ram_cost_mult, Player.hacknet_node_ram_cost_mult*mults.hacknet_node_ram_cost_mult],
['Hacknet Node Core purchase cost ', Player.hacknet_node_core_cost_mult, Player.hacknet_node_core_cost_mult*mults.hacknet_node_core_cost_mult],
['Hacknet Node level upgrade cost ', Player.hacknet_node_level_cost_mult, Player.hacknet_node_level_cost_mult*mults.hacknet_node_level_cost_mult],
])}<br />
{MultiplierTable([
[
"Hacknet Node production ",
Player.hacknet_node_money_mult,
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
],
[
"Hacknet Node purchase cost ",
Player.hacknet_node_purchase_cost_mult,
Player.hacknet_node_purchase_cost_mult *
mults.hacknet_node_purchase_cost_mult,
],
[
"Hacknet Node RAM upgrade cost ",
Player.hacknet_node_ram_cost_mult,
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
],
[
"Hacknet Node Core purchase cost ",
Player.hacknet_node_core_cost_mult,
Player.hacknet_node_core_cost_mult *
mults.hacknet_node_core_cost_mult,
],
[
"Hacknet Node level upgrade cost ",
Player.hacknet_node_level_cost_mult,
Player.hacknet_node_level_cost_mult *
mults.hacknet_node_level_cost_mult,
],
])}
<br />
{MultiplierTable([
['Company reputation gain ', Player.company_rep_mult, Player.company_rep_mult*mults.company_rep_mult],
['Faction reputation gain ', Player.faction_rep_mult, Player.faction_rep_mult*mults.faction_rep_mult],
['Salary ', Player.work_money_mult, Player.work_money_mult*mults.work_money_mult],
])}<br />
{MultiplierTable([
[
"Company reputation gain ",
Player.company_rep_mult,
Player.company_rep_mult * mults.company_rep_mult,
],
[
"Faction reputation gain ",
Player.faction_rep_mult,
Player.faction_rep_mult * mults.faction_rep_mult,
],
[
"Salary ",
Player.work_money_mult,
Player.work_money_mult * mults.work_money_mult,
],
])}
<br />
{MultiplierTable([
['Crime success ', Player.crime_success_mult, Player.crime_success_mult*mults.crime_success_mult],
['Crime money ', Player.crime_money_mult, Player.crime_money_mult*mults.crime_money_mult],
])}<br />
{MultiplierTable([
[
"Crime success ",
Player.crime_success_mult,
Player.crime_success_mult * mults.crime_success_mult,
],
[
"Crime money ",
Player.crime_money_mult,
Player.crime_money_mult * mults.crime_money_mult,
],
])}
<br />
<BladeburnerMults />
</>
)
<BladeburnerMults />
</>
);
}

@ -11,32 +11,33 @@ import { Player } from "../../Player";
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
export function PurchasedAugmentations(): React.ReactElement {
const augs: React.ReactElement[] = [];
// Only render the last NeuroFlux (there are no findLastIndex btw)
let nfgIndex = -1;
for(let i = Player.queuedAugmentations.length-1; i >= 0; i--) {
if(Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor) {
nfgIndex = i;
break;
}
const augs: React.ReactElement[] = [];
// Only render the last NeuroFlux (there are no findLastIndex btw)
let nfgIndex = -1;
for (let i = Player.queuedAugmentations.length - 1; i >= 0; i--) {
if (
Player.queuedAugmentations[i].name === AugmentationNames.NeuroFluxGovernor
) {
nfgIndex = i;
break;
}
for (let i = 0; i < Player.queuedAugmentations.length; i++) {
const ownedAug = Player.queuedAugmentations[i];
if(ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
const aug = Augmentations[ownedAug.name];
let level = null;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
level = ownedAug.level;
}
augs.push(
<li key={`${ownedAug.name}${ownedAug.level}`}>
<AugmentationAccordion aug={aug} level={level} />
</li>,
)
}
for (let i = 0; i < Player.queuedAugmentations.length; i++) {
const ownedAug = Player.queuedAugmentations[i];
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex)
continue;
const aug = Augmentations[ownedAug.name];
let level = null;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
level = ownedAug.level;
}
return (
<ul className="augmentations-list">{augs}</ul>
)
augs.push(
<li key={`${ownedAug.name}${ownedAug.level}`}>
<AugmentationAccordion aug={aug} level={level} />
</li>,
);
}
return <ul className="augmentations-list">{augs}</ul>;
}

@ -13,88 +13,85 @@ import { StdButton } from "../../ui/React/StdButton";
import { canGetBonus } from "../../ExportBonus";
type IProps = {
exportGameFn: () => void;
installAugmentationsFn: () => void;
}
exportGameFn: () => void;
installAugmentationsFn: () => void;
};
type IState = {
rerender: boolean;
}
rerender: boolean;
};
export class AugmentationsRoot extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
rerender: false,
};
this.export = this.export.bind(this);
constructor(props: IProps) {
super(props);
this.state = {
rerender: false,
};
this.export = this.export.bind(this);
}
export(): void {
this.props.exportGameFn();
this.setState({
rerender: !this.state.rerender,
});
}
render(): React.ReactNode {
function exportBonusStr(): string {
if (canGetBonus()) return "(+1 favor to all factions)";
return "";
}
export(): void {
this.props.exportGameFn();
this.setState({
rerender: !this.state.rerender,
});
}
render(): React.ReactNode {
function exportBonusStr(): string {
if(canGetBonus()) return "(+1 favor to all factions)";
return "";
}
return (
<div id="augmentations-content">
<h1>Purchased Augmentations</h1>
<p>
Below is a list of all Augmentations you have purchased but not
yet installed. Click the button below to install them.
</p>
<p>
WARNING: Installing your Augmentations resets most of your progress,
including:
</p><br />
<p>- Stats/Skill levels and Experience</p>
<p>- Money</p>
<p>- Scripts on every computer but your home computer</p>
<p>- Purchased servers</p>
<p>- Hacknet Nodes</p>
<p>- Faction/Company reputation</p>
<p>- Stocks</p><br />
<p>
Installing Augmentations lets you start over with the perks and
benefits granted by all of the Augmentations you have ever
installed. Also, you will keep any scripts and RAM/Core upgrades
on your home computer (but you will lose all programs besides
NUKE.exe)
</p>
<StdButton
onClick={this.props.installAugmentationsFn}
text="Install Augmentations"
tooltip="'I never asked for this'"
/>
<StdButton
addClasses="flashing-button"
onClick={this.export}
text={`Backup Save ${exportBonusStr()}`}
tooltip="It's always a good idea to backup/export your save!"
/>
<PurchasedAugmentations />
<h1>Installed Augmentations</h1>
<p>
{
`List of all Augmentations ${Player.sourceFiles.length > 0 ? "and Source Files " : ""} ` +
`that have been installed. You have gained the effects of these.`
}
</p>
<InstalledAugmentationsAndSourceFiles />
<br /> <br />
<PlayerMultipliers />
</div>
)
}
return (
<div id="augmentations-content">
<h1>Purchased Augmentations</h1>
<p>
Below is a list of all Augmentations you have purchased but not yet
installed. Click the button below to install them.
</p>
<p>
WARNING: Installing your Augmentations resets most of your progress,
including:
</p>
<br />
<p>- Stats/Skill levels and Experience</p>
<p>- Money</p>
<p>- Scripts on every computer but your home computer</p>
<p>- Purchased servers</p>
<p>- Hacknet Nodes</p>
<p>- Faction/Company reputation</p>
<p>- Stocks</p>
<br />
<p>
Installing Augmentations lets you start over with the perks and
benefits granted by all of the Augmentations you have ever installed.
Also, you will keep any scripts and RAM/Core upgrades on your home
computer (but you will lose all programs besides NUKE.exe)
</p>
<StdButton
onClick={this.props.installAugmentationsFn}
text="Install Augmentations"
tooltip="'I never asked for this'"
/>
<StdButton
addClasses="flashing-button"
onClick={this.export}
text={`Backup Save ${exportBonusStr()}`}
tooltip="It's always a good idea to backup/export your save!"
/>
<PurchasedAugmentations />
<h1>Installed Augmentations</h1>
<p>
{`List of all Augmentations ${
Player.sourceFiles.length > 0 ? "and Source Files " : ""
} ` +
`that have been installed. You have gained the effects of these.`}
</p>
<InstalledAugmentationsAndSourceFiles />
<br /> <br />
<PlayerMultipliers />
</div>
);
}
}

@ -10,32 +10,40 @@ import { Exploit, ExploitName } from "../../Exploits/Exploit";
import { Accordion } from "../../ui/React/Accordion";
export function SourceFileMinus1(): React.ReactElement {
const exploits = Player.exploits;
const exploits = Player.exploits;
if(exploits.length === 0) {
return <></>
}
if (exploits.length === 0) {
return <></>;
}
return (<li key={-1}>
<Accordion
headerContent={
<>
Source-File -1: Exploits in the BitNodes
<br />
Level {exploits.length} / ?
</>
}
panelContent={
<>
<p>This Source-File can only be acquired with obscure knowledge of the game, javascript, and the web ecosystem.</p>
<p>It increases all of the player's multipliers by 0.1%</p><br />
return (
<li key={-1}>
<Accordion
headerContent={
<>
Source-File -1: Exploits in the BitNodes
<br />
Level {exploits.length} / ?
</>
}
panelContent={
<>
<p>
This Source-File can only be acquired with obscure knowledge of
the game, javascript, and the web ecosystem.
</p>
<p>It increases all of the player's multipliers by 0.1%</p>
<br />
<p>You have found the following exploits:</p>
<ul>
{exploits.map((c: Exploit) => <li key={c}>* {ExploitName(c)}</li>)}
</ul>
</>
}
/>
</li>)
<p>You have found the following exploits:</p>
<ul>
{exploits.map((c: Exploit) => (
<li key={c}>* {ExploitName(c)}</li>
))}
</ul>
</>
}
/>
</li>
);
}

File diff suppressed because it is too large Load Diff

@ -4,216 +4,216 @@
* player toward the intended strategy. Unless they really want to play the long, slow game of waiting...
*/
interface IBitNodeMultipliers {
/**
* Influences how quickly the player's agility level (not exp) scales
*/
AgilityLevelMultiplier: number;
/**
* Influences how quickly the player's agility level (not exp) scales
*/
AgilityLevelMultiplier: number;
/**
* Influences the base cost to purchase an augmentation.
*/
AugmentationMoneyCost: number;
/**
* Influences the base cost to purchase an augmentation.
*/
AugmentationMoneyCost: number;
/**
* Influences the base rep the player must have with a faction to purchase an augmentation.
*/
AugmentationRepCost: number;
/**
* Influences the base rep the player must have with a faction to purchase an augmentation.
*/
AugmentationRepCost: number;
/**
* Influences how quickly the player can gain rank within Bladeburner.
*/
BladeburnerRank: number;
/**
* Influences how quickly the player can gain rank within Bladeburner.
*/
BladeburnerRank: number;
/**
* Influences the cost of skill levels from Bladeburner.
*/
BladeburnerSkillCost: number;
/**
* Influences the cost of skill levels from Bladeburner.
*/
BladeburnerSkillCost: number;
/**
* Influences how quickly the player's charisma level (not exp) scales
*/
CharismaLevelMultiplier: number;
/**
* Influences how quickly the player's charisma level (not exp) scales
*/
CharismaLevelMultiplier: number;
/**
* Influences the experience gained for each ability when a player completes a class.
*/
ClassGymExpGain: number;
/**
* Influences the experience gained for each ability when a player completes a class.
*/
ClassGymExpGain: number;
/**
* Influences the amount of money gained from completing Coding Contracts
**/
CodingContractMoney: number;
/**
* Influences the amount of money gained from completing Coding Contracts
**/
CodingContractMoney: number;
/**
* Influences the experience gained for each ability when the player completes working their job.
*/
CompanyWorkExpGain: number;
/**
* Influences the experience gained for each ability when the player completes working their job.
*/
CompanyWorkExpGain: number;
/**
* Influences how much money the player earns when completing working their job.
*/
CompanyWorkMoney: number;
/**
* Influences how much money the player earns when completing working their job.
*/
CompanyWorkMoney: number;
/**
* Influences the valuation of corporations created by the player.
*/
CorporationValuation: number;
/**
* Influences the valuation of corporations created by the player.
*/
CorporationValuation: number;
/**
* Influences the base experience gained for each ability when the player commits a crime.
*/
CrimeExpGain: number;
/**
* Influences the base experience gained for each ability when the player commits a crime.
*/
CrimeExpGain: number;
/**
* Influences the base money gained when the player commits a crime.
*/
CrimeMoney: number;
/**
* Influences the base money gained when the player commits a crime.
*/
CrimeMoney: number;
/**
* Influences how many Augmentations you need in order to get invited to the Daedalus faction
*/
DaedalusAugsRequirement: number;
/**
* Influences how many Augmentations you need in order to get invited to the Daedalus faction
*/
DaedalusAugsRequirement: number;
/**
* Influences how quickly the player's defense level (not exp) scales
*/
DefenseLevelMultiplier: number;
/**
* Influences how quickly the player's defense level (not exp) scales
*/
DefenseLevelMultiplier: number;
/**
* Influences how quickly the player's dexterity level (not exp) scales
*/
DexterityLevelMultiplier: number;
/**
* Influences how quickly the player's dexterity level (not exp) scales
*/
DexterityLevelMultiplier: number;
/**
* Influences how much rep the player gains in each faction simply by being a member.
*/
FactionPassiveRepGain: number;
/**
* Influences how much rep the player gains in each faction simply by being a member.
*/
FactionPassiveRepGain: number;
/**
* Influences the experience gained for each ability when the player completes work for a Faction.
*/
FactionWorkExpGain: number;
/**
* Influences the experience gained for each ability when the player completes work for a Faction.
*/
FactionWorkExpGain: number;
/**
* Influences how much rep the player gains when performing work for a faction.
*/
FactionWorkRepGain: number;
/**
* Influences how much rep the player gains when performing work for a faction.
*/
FactionWorkRepGain: number;
/**
* Influences how much it costs to unlock the stock market's 4S Market Data API
*/
FourSigmaMarketDataApiCost: number;
/**
* Influences how much it costs to unlock the stock market's 4S Market Data API
*/
FourSigmaMarketDataApiCost: number;
/**
* Influences how much it costs to unlock the stock market's 4S Market Data (NOT API)
*/
FourSigmaMarketDataCost: number;
/**
* Influences how much it costs to unlock the stock market's 4S Market Data (NOT API)
*/
FourSigmaMarketDataCost: number;
/**
* Influences how much negative karma is required to create a gang in this bitnode.
*/
GangKarmaRequirement: number;
/**
* Influences how much negative karma is required to create a gang in this bitnode.
*/
GangKarmaRequirement: number;
/**
* Influences the experienced gained when hacking a server.
*/
HackExpGain: number;
/**
* Influences the experienced gained when hacking a server.
*/
HackExpGain: number;
/**
* Influences how quickly the player's hacking level (not experience) scales
*/
HackingLevelMultiplier: number;
/**
* Influences how quickly the player's hacking level (not experience) scales
*/
HackingLevelMultiplier: number;
/**
* Influences how much money is produced by Hacknet Nodes.
* Influeces the hash rate of Hacknet Servers (unlocked in BitNode-9)
*/
HacknetNodeMoney: number;
/**
* Influences how much money is produced by Hacknet Nodes.
* Influeces the hash rate of Hacknet Servers (unlocked in BitNode-9)
*/
HacknetNodeMoney: number;
/**
* Influences how much money it costs to upgrade your home computer's RAM
*/
HomeComputerRamCost: number;
/**
* Influences how much money it costs to upgrade your home computer's RAM
*/
HomeComputerRamCost: number;
/**
* Influences how much money is gained when the player infiltrates a company.
*/
InfiltrationMoney: number;
/**
* Influences how much money is gained when the player infiltrates a company.
*/
InfiltrationMoney: number;
/**
* Influences how much rep the player can gain from factions when selling stolen documents and secrets
*/
InfiltrationRep: number;
/**
* Influences how much rep the player can gain from factions when selling stolen documents and secrets
*/
InfiltrationRep: number;
/**
* Influences how much money can be stolen from a server when the player performs a hack against it through
* the Terminal.
*/
ManualHackMoney: number;
/**
* Influences how much money can be stolen from a server when the player performs a hack against it through
* the Terminal.
*/
ManualHackMoney: number;
/**
* Influence how much it costs to purchase a server
*/
PurchasedServerCost: number;
/**
* Influence how much it costs to purchase a server
*/
PurchasedServerCost: number;
/**
* Influences the maximum number of purchased servers you can have
*/
PurchasedServerLimit: number;
/**
* Influences the maximum number of purchased servers you can have
*/
PurchasedServerLimit: number;
/**
* Influences the maximum allowed RAM for a purchased server
*/
PurchasedServerMaxRam: number;
/**
* Influences the minimum favor the player must have with a faction before they can donate to gain rep.
*/
RepToDonateToFaction: number;
/**
* Influences the maximum allowed RAM for a purchased server
*/
PurchasedServerMaxRam: number;
/**
* Influences the minimum favor the player must have with a faction before they can donate to gain rep.
*/
RepToDonateToFaction: number;
/**
* Influences how much money can be stolen from a server when a script performs a hack against it.
*/
ScriptHackMoney: number;
/**
* Influences how much money can be stolen from a server when a script performs a hack against it.
*/
ScriptHackMoney: number;
/**
* The amount of money actually gained when script hack a server. This is
* different than the above because you can reduce the amount of money but
* not gain that same amount.
*/
ScriptHackMoneyGain: number;
/**
* The amount of money actually gained when script hack a server. This is
* different than the above because you can reduce the amount of money but
* not gain that same amount.
*/
ScriptHackMoneyGain: number;
/**
* Influences the growth percentage per cycle against a server.
*/
ServerGrowthRate: number;
/**
* Influences the growth percentage per cycle against a server.
*/
ServerGrowthRate: number;
/**
* Influences the maxmimum money that a server can grow to.
*/
ServerMaxMoney: number;
/**
* Influences the maxmimum money that a server can grow to.
*/
ServerMaxMoney: number;
/**
* Influences the initial money that a server starts with.
*/
ServerStartingMoney: number;
/**
* Influences the initial money that a server starts with.
*/
ServerStartingMoney: number;
/**
* Influences the initial security level (hackDifficulty) of a server.
*/
ServerStartingSecurity: number;
/**
* Influences the initial security level (hackDifficulty) of a server.
*/
ServerStartingSecurity: number;
/**
* Influences the weaken amount per invocation against a server.
*/
ServerWeakenRate: number;
/**
* Influences the weaken amount per invocation against a server.
*/
ServerWeakenRate: number;
/**
* Influences how quickly the player's strength level (not exp) scales
*/
StrengthLevelMultiplier: number;
/**
* Influences how quickly the player's strength level (not exp) scales
*/
StrengthLevelMultiplier: number;
// Index signature
[key: string]: number;
// Index signature
[key: string]: number;
}
/**
@ -221,57 +221,57 @@ interface IBitNodeMultipliers {
*/
// tslint:disable-next-line:variable-name
export const BitNodeMultipliers: IBitNodeMultipliers = {
HackingLevelMultiplier: 1,
StrengthLevelMultiplier: 1,
DefenseLevelMultiplier: 1,
DexterityLevelMultiplier: 1,
AgilityLevelMultiplier: 1,
CharismaLevelMultiplier: 1,
HackingLevelMultiplier: 1,
StrengthLevelMultiplier: 1,
DefenseLevelMultiplier: 1,
DexterityLevelMultiplier: 1,
AgilityLevelMultiplier: 1,
CharismaLevelMultiplier: 1,
ServerGrowthRate: 1,
ServerMaxMoney: 1,
ServerStartingMoney: 1,
ServerStartingSecurity: 1,
ServerWeakenRate: 1,
ServerGrowthRate: 1,
ServerMaxMoney: 1,
ServerStartingMoney: 1,
ServerStartingSecurity: 1,
ServerWeakenRate: 1,
HomeComputerRamCost: 1,
HomeComputerRamCost: 1,
PurchasedServerCost: 1,
PurchasedServerLimit: 1,
PurchasedServerMaxRam: 1,
PurchasedServerCost: 1,
PurchasedServerLimit: 1,
PurchasedServerMaxRam: 1,
CompanyWorkMoney: 1,
CrimeMoney: 1,
HacknetNodeMoney: 1,
ManualHackMoney: 1,
ScriptHackMoney: 1,
ScriptHackMoneyGain: 1,
CodingContractMoney: 1,
CompanyWorkMoney: 1,
CrimeMoney: 1,
HacknetNodeMoney: 1,
ManualHackMoney: 1,
ScriptHackMoney: 1,
ScriptHackMoneyGain: 1,
CodingContractMoney: 1,
ClassGymExpGain: 1,
CompanyWorkExpGain: 1,
CrimeExpGain: 1,
FactionWorkExpGain: 1,
HackExpGain: 1,
ClassGymExpGain: 1,
CompanyWorkExpGain: 1,
CrimeExpGain: 1,
FactionWorkExpGain: 1,
HackExpGain: 1,
FactionPassiveRepGain: 1,
FactionWorkRepGain: 1,
RepToDonateToFaction: 1,
FactionPassiveRepGain: 1,
FactionWorkRepGain: 1,
RepToDonateToFaction: 1,
AugmentationMoneyCost: 1,
AugmentationRepCost: 1,
AugmentationMoneyCost: 1,
AugmentationRepCost: 1,
InfiltrationMoney: 1,
InfiltrationRep: 1,
InfiltrationMoney: 1,
InfiltrationRep: 1,
FourSigmaMarketDataCost: 1,
FourSigmaMarketDataApiCost: 1,
FourSigmaMarketDataCost: 1,
FourSigmaMarketDataApiCost: 1,
CorporationValuation: 1,
CorporationValuation: 1,
BladeburnerRank: 1,
BladeburnerSkillCost: 1,
BladeburnerRank: 1,
BladeburnerSkillCost: 1,
DaedalusAugsRequirement: 1,
GangKarmaRequirement: 1,
DaedalusAugsRequirement: 1,
GangKarmaRequirement: 1,
};

@ -1,284 +1,351 @@
import { Player } from "../Player";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { addOffset } from "../../utils/helpers/addOffset";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { BladeburnerConstants } from "./data/Constants";
import { IBladeburner } from "./IBladeburner";
import { IAction, ISuccessChanceParams } from "./IAction";
class StatsMultiplier {
[key: string]: number;
[key: string]: number;
hack = 0;
str = 0;
def = 0;
dex = 0;
agi = 0;
cha = 0;
int = 0;
hack = 0;
str = 0;
def = 0;
dex = 0;
agi = 0;
cha = 0;
int = 0;
}
export interface IActionParams {
name?: string;
desc?: string;
level?: number;
maxLevel?: number;
autoLevel?: boolean;
baseDifficulty?: number;
difficultyFac?: number;
rewardFac?: number;
successes?: number;
failures?: number;
rankGain?: number;
rankLoss?: number;
hpLoss?: number;
hpLost?: number;
isStealth?: boolean;
isKill?: boolean;
count?: number;
countGrowth?: number;
weights?: StatsMultiplier;
decays?: StatsMultiplier;
teamCount?: number;
name?: string;
desc?: string;
level?: number;
maxLevel?: number;
autoLevel?: boolean;
baseDifficulty?: number;
difficultyFac?: number;
rewardFac?: number;
successes?: number;
failures?: number;
rankGain?: number;
rankLoss?: number;
hpLoss?: number;
hpLost?: number;
isStealth?: boolean;
isKill?: boolean;
count?: number;
countGrowth?: number;
weights?: StatsMultiplier;
decays?: StatsMultiplier;
teamCount?: number;
}
export class Action implements IAction {
name = "";
desc = "";
name = "";
desc = "";
// Difficulty scales with level. See getDifficulty() method
level = 1;
maxLevel = 1;
autoLevel = true;
baseDifficulty = 100;
difficultyFac = 1.01;
// Difficulty scales with level. See getDifficulty() method
level = 1;
maxLevel = 1;
autoLevel = true;
baseDifficulty = 100;
difficultyFac = 1.01;
// Rank increase/decrease is affected by this exponent
rewardFac = 1.02;
// Rank increase/decrease is affected by this exponent
rewardFac = 1.02;
successes = 0;
failures = 0;
successes = 0;
failures = 0;
// All of these scale with level/difficulty
rankGain = 0;
rankLoss = 0;
hpLoss = 0;
hpLost = 0;
// All of these scale with level/difficulty
rankGain = 0;
rankLoss = 0;
hpLoss = 0;
hpLost = 0;
// Action Category. Current categories are stealth and kill
isStealth = false;
isKill = false;
// Action Category. Current categories are stealth and kill
isStealth = false;
isKill = false;
/**
* Number of this contract remaining, and its growth rate
* Growth rate is an integer and the count will increase by that integer every "cycle"
*/
count: number = getRandomInt(1e3, 25e3);
countGrowth: number = getRandomInt(1, 5);
/**
* Number of this contract remaining, and its growth rate
* Growth rate is an integer and the count will increase by that integer every "cycle"
*/
count: number = getRandomInt(1e3, 25e3);
countGrowth: number = getRandomInt(1, 5);
// Weighting of each stat in determining action success rate
weights: StatsMultiplier = {hack:1/7,str:1/7,def:1/7,dex:1/7,agi:1/7,cha:1/7,int:1/7};
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
decays: StatsMultiplier = { hack: 0.9, str: 0.9, def: 0.9, dex: 0.9, agi: 0.9, cha: 0.9, int: 0.9 };
teamCount = 0;
// Weighting of each stat in determining action success rate
weights: StatsMultiplier = {
hack: 1 / 7,
str: 1 / 7,
def: 1 / 7,
dex: 1 / 7,
agi: 1 / 7,
cha: 1 / 7,
int: 1 / 7,
};
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
decays: StatsMultiplier = {
hack: 0.9,
str: 0.9,
def: 0.9,
dex: 0.9,
agi: 0.9,
cha: 0.9,
int: 0.9,
};
teamCount = 0;
// Base Class for Contracts, Operations, and BlackOps
constructor(params: IActionParams| null = null) { // | null = null
if(params && params.name) this.name = params.name;
if(params && params.desc) this.desc = params.desc;
// Base Class for Contracts, Operations, and BlackOps
constructor(params: IActionParams | null = null) {
// | null = null
if (params && params.name) this.name = params.name;
if (params && params.desc) this.desc = params.desc;
if(params && params.baseDifficulty) this.baseDifficulty = addOffset(params.baseDifficulty, 10);
if(params && params.difficultyFac) this.difficultyFac = params.difficultyFac;
if (params && params.baseDifficulty)
this.baseDifficulty = addOffset(params.baseDifficulty, 10);
if (params && params.difficultyFac)
this.difficultyFac = params.difficultyFac;
if(params && params.rewardFac) this.rewardFac = params.rewardFac;
if(params && params.rankGain) this.rankGain = params.rankGain;
if(params && params.rankLoss) this.rankLoss = params.rankLoss;
if(params && params.hpLoss) this.hpLoss = params.hpLoss;
if (params && params.rewardFac) this.rewardFac = params.rewardFac;
if (params && params.rankGain) this.rankGain = params.rankGain;
if (params && params.rankLoss) this.rankLoss = params.rankLoss;
if (params && params.hpLoss) this.hpLoss = params.hpLoss;
if(params && params.isStealth) this.isStealth = params.isStealth;
if(params && params.isKill) this.isKill = params.isKill;
if (params && params.isStealth) this.isStealth = params.isStealth;
if (params && params.isKill) this.isKill = params.isKill;
if(params && params.count) this.count = params.count;
if(params && params.countGrowth) this.countGrowth = params.countGrowth;
if (params && params.count) this.count = params.count;
if (params && params.countGrowth) this.countGrowth = params.countGrowth;
if(params && params.weights) this.weights = params.weights;
if(params && params.decays) this.decays = params.decays;
if (params && params.weights) this.weights = params.weights;
if (params && params.decays) this.decays = params.decays;
// Check to make sure weights are summed properly
let sum = 0;
for (const weight in this.weights) {
if (this.weights.hasOwnProperty(weight)) {
sum += this.weights[weight];
}
// Check to make sure weights are summed properly
let sum = 0;
for (const weight in this.weights) {
if (this.weights.hasOwnProperty(weight)) {
sum += this.weights[weight];
}
}
if (sum - 1 >= 10 * Number.EPSILON) {
throw new Error(
"Invalid weights when constructing Action " +
this.name +
". The weights should sum up to 1. They sum up to :" +
1,
);
}
for (const decay in this.decays) {
if (this.decays.hasOwnProperty(decay)) {
if (this.decays[decay] > 1) {
throw new Error(
"Invalid decays when constructing " +
"Action " +
this.name +
". " +
"Decay value cannot be greater than 1",
);
}
if (sum - 1 >= 10 * Number.EPSILON) {
throw new Error("Invalid weights when constructing Action " + this.name +
". The weights should sum up to 1. They sum up to :" + 1);
}
}
}
getDifficulty(): number {
const difficulty =
this.baseDifficulty * Math.pow(this.difficultyFac, this.level - 1);
if (isNaN(difficulty)) {
throw new Error("Calculated NaN in Action.getDifficulty()");
}
return difficulty;
}
/**
* Tests for success. Should be called when an action has completed
* @param inst {Bladeburner} - Bladeburner instance
*/
attempt(inst: IBladeburner): boolean {
return Math.random() < this.getSuccessChance(inst);
}
// To be implemented by subtypes
getActionTimePenalty(): number {
return 1;
}
getActionTime(inst: IBladeburner): number {
const difficulty = this.getDifficulty();
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
const skillFac = inst.skillMultipliers.actionTime; // Always < 1
const effAgility = Player.agility * inst.skillMultipliers.effAgi;
const effDexterity = Player.dexterity * inst.skillMultipliers.effDex;
const statFac =
0.5 *
(Math.pow(effAgility, BladeburnerConstants.EffAgiExponentialFactor) +
Math.pow(effDexterity, BladeburnerConstants.EffDexExponentialFactor) +
effAgility / BladeburnerConstants.EffAgiLinearFactor +
effDexterity / BladeburnerConstants.EffDexLinearFactor); // Always > 1
baseTime = Math.max(1, (baseTime * skillFac) / statFac);
return Math.ceil(baseTime * this.getActionTimePenalty());
}
// For actions that have teams. To be implemented by subtypes.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getTeamSuccessBonus(inst: IBladeburner): number {
return 1;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return 1;
}
getChaosCompetencePenalty(
inst: IBladeburner,
params: ISuccessChanceParams,
): number {
const city = inst.getCurrentCity();
if (params.est) {
return Math.pow(
city.popEst / BladeburnerConstants.PopulationThreshold,
BladeburnerConstants.PopulationExponent,
);
} else {
return Math.pow(
city.pop / BladeburnerConstants.PopulationThreshold,
BladeburnerConstants.PopulationExponent,
);
}
}
getChaosDifficultyBonus(
inst: IBladeburner /*, params: ISuccessChanceParams*/,
): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
const mult = Math.pow(diff, 0.1);
return mult;
}
return 1;
}
getEstSuccessChance(inst: IBladeburner): number[] {
function clamp(x: number): number {
return Math.max(0, Math.min(x, 1));
}
const est = this.getSuccessChance(inst, { est: true });
const real = this.getSuccessChance(inst);
const diff = Math.abs(real - est);
let low = real - diff;
let high = real + diff;
const city = inst.getCurrentCity();
const r = city.pop / city.popEst;
if (r < 1) low *= r;
else high *= r;
return [clamp(low), clamp(high)];
}
/**
* @inst - Bladeburner Object
* @params - options:
* est (bool): Get success chance estimate instead of real success chance
*/
getSuccessChance(
inst: IBladeburner,
params: ISuccessChanceParams = { est: false },
): number {
if (inst == null) {
throw new Error(
"Invalid Bladeburner instance passed into Action.getSuccessChance",
);
}
let difficulty = this.getDifficulty();
let competence = 0;
for (const stat in this.weights) {
if (this.weights.hasOwnProperty(stat)) {
const playerStatLvl = Player.queryStatFromString(stat);
const key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
let effMultiplier = inst.skillMultipliers[key];
if (effMultiplier == null) {
console.error(
`Failed to find Bladeburner Skill multiplier for: ${stat}`,
);
effMultiplier = 1;
}
competence +=
this.weights[stat] *
Math.pow(effMultiplier * playerStatLvl, this.decays[stat]);
}
}
competence *= Player.getIntelligenceBonus(0.75);
competence *= inst.calculateStaminaPenalty();
for (const decay in this.decays) {
if (this.decays.hasOwnProperty(decay)) {
if (this.decays[decay] > 1) {
throw new Error("Invalid decays when constructing " +
"Action " + this.name + ". " +
"Decay value cannot be greater than 1");
}
}
}
competence *= this.getTeamSuccessBonus(inst);
competence *= this.getChaosCompetencePenalty(inst, params);
difficulty *= this.getChaosDifficultyBonus(inst);
if (this.name == "Raid" && inst.getCurrentCity().comms <= 0) {
return 0;
}
getDifficulty(): number {
const difficulty = this.baseDifficulty * Math.pow(this.difficultyFac, this.level-1);
if (isNaN(difficulty)) {throw new Error("Calculated NaN in Action.getDifficulty()");}
return difficulty;
// Factor skill multipliers into success chance
competence *= inst.skillMultipliers.successChanceAll;
competence *= this.getActionTypeSkillSuccessBonus(inst);
if (this.isStealth) {
competence *= inst.skillMultipliers.successChanceStealth;
}
if (this.isKill) {
competence *= inst.skillMultipliers.successChanceKill;
}
/**
* Tests for success. Should be called when an action has completed
* @param inst {Bladeburner} - Bladeburner instance
*/
attempt(inst: IBladeburner): boolean {
return (Math.random() < this.getSuccessChance(inst));
// Augmentation multiplier
competence *= Player.bladeburner_success_chance_mult;
if (isNaN(competence)) {
throw new Error(
"Competence calculated as NaN in Action.getSuccessChance()",
);
}
return Math.min(1, competence / difficulty);
}
// To be implemented by subtypes
getActionTimePenalty(): number {
return 1;
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number {
return Math.ceil(
0.5 * this.maxLevel * (2 * baseSuccessesPerLevel + (this.maxLevel - 1)),
);
}
setMaxLevel(baseSuccessesPerLevel: number): void {
if (
this.successes >=
this.getSuccessesNeededForNextLevel(baseSuccessesPerLevel)
) {
++this.maxLevel;
}
}
getActionTime(inst: IBladeburner): number {
const difficulty = this.getDifficulty();
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
const skillFac = inst.skillMultipliers.actionTime; // Always < 1
toJSON(): any {
return Generic_toJSON("Action", this);
}
const effAgility = Player.agility * inst.skillMultipliers.effAgi;
const effDexterity = Player.dexterity * inst.skillMultipliers.effDex;
const statFac = 0.5 * (Math.pow(effAgility, BladeburnerConstants.EffAgiExponentialFactor) +
Math.pow(effDexterity, BladeburnerConstants.EffDexExponentialFactor) +
(effAgility / BladeburnerConstants.EffAgiLinearFactor) +
(effDexterity / BladeburnerConstants.EffDexLinearFactor)); // Always > 1
baseTime = Math.max(1, baseTime * skillFac / statFac);
return Math.ceil(baseTime*this.getActionTimePenalty());
}
// For actions that have teams. To be implemented by subtypes.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getTeamSuccessBonus(inst: IBladeburner): number {
return 1;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return 1;
}
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number {
const city = inst.getCurrentCity();
if (params.est) {
return Math.pow((city.popEst / BladeburnerConstants.PopulationThreshold), BladeburnerConstants.PopulationExponent);
} else {
return Math.pow((city.pop / BladeburnerConstants.PopulationThreshold), BladeburnerConstants.PopulationExponent);
}
}
getChaosDifficultyBonus(inst: IBladeburner/*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
const mult = Math.pow(diff, 0.1);
return mult;
}
return 1;
}
getEstSuccessChance(inst: IBladeburner): number[] {
function clamp(x: number): number {
return Math.max(0, Math.min(x, 1));
}
const est = this.getSuccessChance(inst, {est: true});
const real = this.getSuccessChance(inst);
const diff = Math.abs(real-est);
let low = real-diff;
let high = real+diff;
const city = inst.getCurrentCity();
const r = city.pop / city.popEst;
if(r < 1) low *= r;
else high *= r;
return [clamp(low), clamp(high)];
}
/**
* @inst - Bladeburner Object
* @params - options:
* est (bool): Get success chance estimate instead of real success chance
*/
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams={est: false}): number {
if (inst == null) {throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");}
let difficulty = this.getDifficulty();
let competence = 0;
for (const stat in this.weights) {
if (this.weights.hasOwnProperty(stat)) {
const playerStatLvl = Player.queryStatFromString(stat);
const key = "eff" + stat.charAt(0).toUpperCase() + stat.slice(1);
let effMultiplier = inst.skillMultipliers[key];
if (effMultiplier == null) {
console.error(`Failed to find Bladeburner Skill multiplier for: ${stat}`);
effMultiplier = 1;
}
competence += (this.weights[stat] * Math.pow(effMultiplier*playerStatLvl, this.decays[stat]));
}
}
competence *= Player.getIntelligenceBonus(0.75);
competence *= inst.calculateStaminaPenalty();
competence *= this.getTeamSuccessBonus(inst);
competence *= this.getChaosCompetencePenalty(inst, params);
difficulty *= this.getChaosDifficultyBonus(inst);
if(this.name == "Raid" && inst.getCurrentCity().comms <= 0) {
return 0;
}
// Factor skill multipliers into success chance
competence *= inst.skillMultipliers.successChanceAll;
competence *= this.getActionTypeSkillSuccessBonus(inst);
if (this.isStealth) {
competence *= inst.skillMultipliers.successChanceStealth;
}
if (this.isKill) {
competence *= inst.skillMultipliers.successChanceKill;
}
// Augmentation multiplier
competence *= Player.bladeburner_success_chance_mult;
if (isNaN(competence)) {throw new Error("Competence calculated as NaN in Action.getSuccessChance()");}
return Math.min(1, competence / difficulty);
}
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number {
return Math.ceil((0.5) * (this.maxLevel) * (2 * baseSuccessesPerLevel + (this.maxLevel-1)));
}
setMaxLevel(baseSuccessesPerLevel: number): void {
if (this.successes >= this.getSuccessesNeededForNextLevel(baseSuccessesPerLevel)) {
++this.maxLevel;
}
}
toJSON(): any {
return Generic_toJSON("Action", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Action {
return Generic_fromJSON(Action, value.data);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Action {
return Generic_fromJSON(Action, value.data);
}
}
Reviver.constructors.Action = Action;
Reviver.constructors.Action = Action;

@ -1,28 +1,32 @@
import { IActionIdentifier } from "./IActionIdentifier";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
interface IParams {
name?: string;
type?: number;
name?: string;
type?: number;
}
export class ActionIdentifier implements IActionIdentifier {
name = "";
type = -1;
name = "";
type = -1;
constructor(params: IParams = {}) {
if (params.name) this.name = params.name;
if (params.type) this.type = params.type;
}
constructor(params: IParams = {}) {
if (params.name) this.name = params.name;
if (params.type) this.type = params.type;
}
toJSON(): any {
return Generic_toJSON("ActionIdentifier", this);
}
toJSON(): any {
return Generic_toJSON("ActionIdentifier", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): ActionIdentifier {
return Generic_fromJSON(ActionIdentifier, value.data);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): ActionIdentifier {
return Generic_fromJSON(ActionIdentifier, value.data);
}
}
Reviver.constructors.ActionIdentifier = ActionIdentifier;

@ -1,34 +1,38 @@
import { Operation, IOperationParams } from "./Operation";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
export class BlackOperation extends Operation {
constructor(params: IOperationParams | null = null) {
super(params);
this.count = 1;
this.countGrowth = 0;
}
constructor(params: IOperationParams | null = null) {
super(params);
this.count = 1;
this.countGrowth = 0;
}
// To be implemented by subtypes
getActionTimePenalty(): number {
return 1.5;
}
// To be implemented by subtypes
getActionTimePenalty(): number {
return 1.5;
}
getChaosCompetencePenalty(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1;
}
getChaosCompetencePenalty(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1;
}
getChaosDifficultyBonus(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1;
}
getChaosDifficultyBonus(/*inst: IBladeburner, params: ISuccessChanceParams*/): number {
return 1;
}
toJSON(): any {
return Generic_toJSON("BlackOperation", this);
}
toJSON(): any {
return Generic_toJSON("BlackOperation", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Operation {
return Generic_fromJSON(BlackOperation, value.data);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Operation {
return Generic_fromJSON(BlackOperation, value.data);
}
}
Reviver.constructors.BlackOperation = BlackOperation;
Reviver.constructors.BlackOperation = BlackOperation;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,173 +1,231 @@
import { BladeburnerConstants } from "./data/Constants";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
import { addOffset } from "../../utils/helpers/addOffset";
interface IChangePopulationByCountParams {
estChange: number;
estOffset: number;
estChange: number;
estOffset: number;
}
interface IChangePopulationByPercentageParams {
nonZero: boolean;
changeEstEqually: boolean;
nonZero: boolean;
changeEstEqually: boolean;
}
export class City {
/**
* Name of the city.
*/
name = "";
/**
* Name of the city.
*/
name = "";
/**
* Population of the city.
*/
pop = 0;
/**
* Population of the city.
*/
pop = 0;
/**
* Population estimation of the city.
*/
popEst = 0;
/**
* Population estimation of the city.
*/
popEst = 0;
/**
* Number of communities in the city.
*/
comms = 0;
/**
* Number of communities in the city.
*/
comms = 0;
/**
* Estimated number of communities in the city.
*/
commsEst = 0;
/**
* Estimated number of communities in the city.
*/
commsEst = 0;
/**
* Chaos level of the city.
*/
chaos = 0;
/**
* Chaos level of the city.
*/
chaos = 0;
constructor(name: string = BladeburnerConstants.CityNames[2]) {
this.name = name;
constructor(name: string = BladeburnerConstants.CityNames[2]) {
this.name = name;
// Synthoid population and estimate
this.pop = getRandomInt(
BladeburnerConstants.PopulationThreshold,
1.5 * BladeburnerConstants.PopulationThreshold,
);
this.popEst = this.pop * (Math.random() + 0.5);
// Synthoid population and estimate
this.pop = getRandomInt(BladeburnerConstants.PopulationThreshold, 1.5 * BladeburnerConstants.PopulationThreshold);
this.popEst = this.pop * (Math.random() + 0.5);
// Number of Synthoid communities population and estimate
this.comms = getRandomInt(5, 150);
this.commsEst = this.comms + getRandomInt(-5, 5);
if (this.commsEst < 0) this.commsEst = 0;
this.chaos = 0;
}
// Number of Synthoid communities population and estimate
this.comms = getRandomInt(5, 150)
this.commsEst = this.comms + getRandomInt(-5, 5);
if (this.commsEst < 0) this.commsEst = 0;
this.chaos = 0;
/**
* p is the percentage, not the multiplier (e.g. pass in p = 5 for 5%)
*/
changeChaosByPercentage(p: number): void {
if (isNaN(p)) {
throw new Error("NaN passed into City.chaosChaosByPercentage()");
}
if (p === 0) {
return;
}
this.chaos += this.chaos * (p / 100);
if (this.chaos < 0) {
this.chaos = 0;
}
}
improvePopulationEstimateByCount(n: number): void {
if (isNaN(n)) {
throw new Error(
"NaN passeed into City.improvePopulationEstimateByCount()",
);
}
if (this.popEst < this.pop) {
this.popEst += n;
if (this.popEst > this.pop) {
this.popEst = this.pop;
}
} else if (this.popEst > this.pop) {
this.popEst -= n;
if (this.popEst < this.pop) {
this.popEst = this.pop;
}
}
}
/**
* p is the percentage, not the multiplier (e.g. pass in p = 5 for 5%)
*/
improvePopulationEstimateByPercentage(p: number, skillMult = 1): void {
p = p * skillMult;
if (isNaN(p)) {
throw new Error(
"NaN passed into City.improvePopulationEstimateByPercentage()",
);
}
if (this.popEst < this.pop) {
++this.popEst; // In case estimate is 0
this.popEst *= 1 + p / 100;
if (this.popEst > this.pop) {
this.popEst = this.pop;
}
} else if (this.popEst > this.pop) {
this.popEst *= 1 - p / 100;
if (this.popEst < this.pop) {
this.popEst = this.pop;
}
}
}
improveCommunityEstimate(n = 1): void {
if (isNaN(n)) {
throw new Error("NaN passed into City.improveCommunityEstimate()");
}
if (this.commsEst < this.comms) {
this.commsEst += n;
if (this.commsEst > this.comms) {
this.commsEst = this.comms;
}
} else if (this.commsEst > this.comms) {
this.commsEst -= n;
if (this.commsEst < this.comms) {
this.commsEst = this.comms;
}
}
}
/**
* @params options:
* estChange(int): How much the estimate should change by
* estOffset(int): Add offset to estimate (offset by percentage)
*/
changePopulationByCount(
n: number,
params: IChangePopulationByCountParams = { estChange: 0, estOffset: 0 },
): void {
if (isNaN(n)) {
throw new Error("NaN passed into City.changePopulationByCount()");
}
this.pop += n;
if (params.estChange && !isNaN(params.estChange)) {
this.popEst += params.estChange;
}
if (params.estOffset) {
this.popEst = addOffset(this.popEst, params.estOffset);
}
this.popEst = Math.max(this.popEst, 0);
}
/**
* @p is the percentage, not the multiplier. e.g. pass in p = 5 for 5%
* @params options:
* changeEstEqually(bool) - Change the population estimate by an equal amount
* nonZero (bool) - Set to true to ensure that population always changes by at least 1
*/
changePopulationByPercentage(
p: number,
params: IChangePopulationByPercentageParams = {
nonZero: false,
changeEstEqually: false,
},
): number {
if (isNaN(p)) {
throw new Error("NaN passed into City.changePopulationByPercentage()");
}
if (p === 0) {
return 0;
}
let change = Math.round(this.pop * (p / 100));
// Population always changes by at least 1
if (params.nonZero && change === 0) {
p > 0 ? (change = 1) : (change = -1);
}
/**
* p is the percentage, not the multiplier (e.g. pass in p = 5 for 5%)
*/
changeChaosByPercentage(p: number): void {
if (isNaN(p)) {throw new Error("NaN passed into City.chaosChaosByPercentage()");}
if (p === 0) {return;}
this.chaos += this.chaos * (p/100);
if (this.chaos < 0) {this.chaos = 0;}
this.pop += change;
if (params.changeEstEqually) {
this.popEst += change;
if (this.popEst < 0) {
this.popEst = 0;
}
}
return change;
}
improvePopulationEstimateByCount(n: number): void {
if (isNaN(n)) {throw new Error("NaN passeed into City.improvePopulationEstimateByCount()");}
if (this.popEst < this.pop) {
this.popEst += n;
if (this.popEst > this.pop) {this.popEst = this.pop;}
} else if (this.popEst > this.pop) {
this.popEst -= n;
if (this.popEst < this.pop) {this.popEst = this.pop;}
}
changeChaosByCount(n: number): void {
if (isNaN(n)) {
throw new Error("NaN passed into City.changeChaosByCount()");
}
/**
* p is the percentage, not the multiplier (e.g. pass in p = 5 for 5%)
*/
improvePopulationEstimateByPercentage(p: number, skillMult=1): void {
p = p*skillMult;
if (isNaN(p)) {throw new Error("NaN passed into City.improvePopulationEstimateByPercentage()");}
if (this.popEst < this.pop) {
++this.popEst; // In case estimate is 0
this.popEst *= (1 + (p/100));
if (this.popEst > this.pop) {this.popEst = this.pop;}
} else if (this.popEst > this.pop) {
this.popEst *= (1 - (p/100));
if (this.popEst < this.pop) {this.popEst = this.pop;}
}
if (n === 0) {
return;
}
improveCommunityEstimate(n=1): void {
if (isNaN(n)) {throw new Error("NaN passed into City.improveCommunityEstimate()");}
if (this.commsEst < this.comms) {
this.commsEst += n;
if (this.commsEst > this.comms) {this.commsEst = this.comms;}
} else if (this.commsEst > this.comms) {
this.commsEst -= n;
if (this.commsEst < this.comms) {this.commsEst = this.comms;}
}
this.chaos += n;
if (this.chaos < 0) {
this.chaos = 0;
}
}
/**
* @params options:
* estChange(int): How much the estimate should change by
* estOffset(int): Add offset to estimate (offset by percentage)
*/
changePopulationByCount(n: number, params: IChangePopulationByCountParams = {estChange: 0, estOffset: 0}): void {
if (isNaN(n)) {throw new Error("NaN passed into City.changePopulationByCount()");}
this.pop += n;
if (params.estChange && !isNaN(params.estChange)) {this.popEst += params.estChange;}
if (params.estOffset) {
this.popEst = addOffset(this.popEst, params.estOffset);
}
this.popEst = Math.max(this.popEst, 0);
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("City", this);
}
/**
* @p is the percentage, not the multiplier. e.g. pass in p = 5 for 5%
* @params options:
* changeEstEqually(bool) - Change the population estimate by an equal amount
* nonZero (bool) - Set to true to ensure that population always changes by at least 1
*/
changePopulationByPercentage(p: number, params: IChangePopulationByPercentageParams={nonZero: false, changeEstEqually: false}): number {
if (isNaN(p)) {throw new Error("NaN passed into City.changePopulationByPercentage()");}
if (p === 0) {return 0;}
let change = Math.round(this.pop * (p/100));
// Population always changes by at least 1
if (params.nonZero && change === 0) {
p > 0 ? change = 1 : change = -1;
}
this.pop += change;
if (params.changeEstEqually) {
this.popEst += change;
if (this.popEst < 0) {this.popEst = 0;}
}
return change;
}
changeChaosByCount(n: number): void {
if (isNaN(n)) {throw new Error("NaN passed into City.changeChaosByCount()");}
if (n === 0) {return;}
this.chaos += n;
if (this.chaos < 0) {this.chaos = 0;}
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("City", this);
}
/**
* Initiatizes a City object from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): City {
return Generic_fromJSON(City, value.data);
}
/**
* Initiatizes a City object from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): City {
return Generic_fromJSON(City, value.data);
}
}
Reviver.constructors.City = City;

@ -1,25 +1,28 @@
import { IBladeburner } from "./IBladeburner";
import { Action, IActionParams } from "./Action";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
export class Contract extends Action {
constructor(params: IActionParams | null = null) {
super(params);
}
constructor(params: IActionParams | null = null) {
super(params);
}
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceContract;
}
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceContract;
}
toJSON(): any {
return Generic_toJSON("Contract", this);
}
toJSON(): any {
return Generic_toJSON("Contract", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Contract {
return Generic_fromJSON(Contract, value.data);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Contract {
return Generic_fromJSON(Contract, value.data);
}
}
Reviver.constructors.Contract = Contract;
Reviver.constructors.Contract = Contract;

@ -3,47 +3,52 @@ import { IMap } from "../types";
export const GeneralActions: IMap<Action> = {};
(function() {
// General Actions
let actionName;
actionName = "Training";
GeneralActions[actionName] = new Action({
name:actionName,
desc:"Improve your abilities at the Bladeburner unit's specialized training " +
"center. Doing this gives experience for all combat stats and also " +
"increases your max stamina.",
});
(function () {
// General Actions
let actionName;
actionName = "Training";
GeneralActions[actionName] = new Action({
name: actionName,
desc:
"Improve your abilities at the Bladeburner unit's specialized training " +
"center. Doing this gives experience for all combat stats and also " +
"increases your max stamina.",
});
actionName = "Field Analysis";
GeneralActions[actionName] = new Action({
name:actionName,
desc:"Mine and analyze Synthoid-related data. This improves the " +
"Bladeburner's unit intelligence on Synthoid locations and " +
"activities. Completing this action will improve the accuracy " +
"of your Synthoid population estimated in the current city.<br><br>" +
"Does NOT require stamina.",
});
actionName = "Field Analysis";
GeneralActions[actionName] = new Action({
name: actionName,
desc:
"Mine and analyze Synthoid-related data. This improves the " +
"Bladeburner's unit intelligence on Synthoid locations and " +
"activities. Completing this action will improve the accuracy " +
"of your Synthoid population estimated in the current city.<br><br>" +
"Does NOT require stamina.",
});
actionName = "Recruitment";
GeneralActions[actionName] = new Action({
name:actionName,
desc:"Attempt to recruit members for your Bladeburner team. These members " +
"can help you conduct operations.<br><br>" +
"Does NOT require stamina.",
});
actionName = "Recruitment";
GeneralActions[actionName] = new Action({
name: actionName,
desc:
"Attempt to recruit members for your Bladeburner team. These members " +
"can help you conduct operations.<br><br>" +
"Does NOT require stamina.",
});
actionName = "Diplomacy";
GeneralActions[actionName] = new Action({
name: actionName,
desc: "Improve diplomatic relations with the Synthoid population. " +
"Completing this action will reduce the Chaos level in your current city.<br><br>" +
"Does NOT require stamina.",
});
actionName = "Diplomacy";
GeneralActions[actionName] = new Action({
name: actionName,
desc:
"Improve diplomatic relations with the Synthoid population. " +
"Completing this action will reduce the Chaos level in your current city.<br><br>" +
"Does NOT require stamina.",
});
actionName = "Hyperbolic Regeneration Chamber";
GeneralActions[actionName] = new Action({
name: actionName,
desc: "Enter cryogenic stasis using the Bladeburner division's hi-tech Regeneration Chamber. " +
"This will slowly heal your wounds and slightly increase your stamina.<br><br>",
});
})()
actionName = "Hyperbolic Regeneration Chamber";
GeneralActions[actionName] = new Action({
name: actionName,
desc:
"Enter cryogenic stasis using the Bladeburner division's hi-tech Regeneration Chamber. " +
"This will slowly heal your wounds and slightly increase your stamina.<br><br>",
});
})();

@ -1,72 +1,75 @@
import { IBladeburner } from "./IBladeburner";
export interface IStatsMultiplier {
[key: string]: number;
[key: string]: number;
hack: number;
str: number;
def: number;
dex: number;
agi: number;
cha: number;
int: number;
hack: number;
str: number;
def: number;
dex: number;
agi: number;
cha: number;
int: number;
}
export interface ISuccessChanceParams {
est: boolean;
est: boolean;
}
export interface IAction {
name: string;
desc: string;
name: string;
desc: string;
// Difficulty scales with level. See getDifficulty() method
level: number;
maxLevel: number;
autoLevel: boolean;
baseDifficulty: number;
difficultyFac: number;
// Difficulty scales with level. See getDifficulty() method
level: number;
maxLevel: number;
autoLevel: boolean;
baseDifficulty: number;
difficultyFac: number;
// Rank increase/decrease is affected by this exponent
rewardFac: number;
// Rank increase/decrease is affected by this exponent
rewardFac: number;
successes: number;
failures: number;
successes: number;
failures: number;
// All of these scale with level/difficulty
rankGain: number;
rankLoss: number;
hpLoss: number;
hpLost: number;
// All of these scale with level/difficulty
rankGain: number;
rankLoss: number;
hpLoss: number;
hpLost: number;
// Action Category. Current categories are stealth and kill
isStealth: boolean;
isKill: boolean;
// Action Category. Current categories are stealth and kill
isStealth: boolean;
isKill: boolean;
/**
* Number of this contract remaining, and its growth rate
* Growth rate is an integer and the count will increase by that integer every "cycle"
*/
count: number;
countGrowth: number;
/**
* Number of this contract remaining, and its growth rate
* Growth rate is an integer and the count will increase by that integer every "cycle"
*/
count: number;
countGrowth: number;
// Weighting of each stat in determining action success rate
weights: IStatsMultiplier;
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
decays: IStatsMultiplier;
teamCount: number;
// Weighting of each stat in determining action success rate
weights: IStatsMultiplier;
// Diminishing returns of stats (stat ^ decay where 0 <= decay <= 1)
decays: IStatsMultiplier;
teamCount: number;
getDifficulty(): number;
attempt(inst: IBladeburner): boolean;
getActionTimePenalty(): number;
getActionTime(inst: IBladeburner): number;
getTeamSuccessBonus(inst: IBladeburner): number;
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
getChaosDifficultyBonus(inst: IBladeburner): number;
getEstSuccessChance(inst: IBladeburner): number[];
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams): number;
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
setMaxLevel(baseSuccessesPerLevel: number): void;
toJSON(): any;
}
getDifficulty(): number;
attempt(inst: IBladeburner): boolean;
getActionTimePenalty(): number;
getActionTime(inst: IBladeburner): number;
getTeamSuccessBonus(inst: IBladeburner): number;
getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
getChaosCompetencePenalty(
inst: IBladeburner,
params: ISuccessChanceParams,
): number;
getChaosDifficultyBonus(inst: IBladeburner): number;
getEstSuccessChance(inst: IBladeburner): number[];
getSuccessChance(inst: IBladeburner, params: ISuccessChanceParams): number;
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
setMaxLevel(baseSuccessesPerLevel: number): void;
toJSON(): any;
}

@ -1,4 +1,4 @@
export interface IActionIdentifier {
name: string;
type: number;
}
name: string;
type: number;
}

@ -6,100 +6,143 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { WorkerScript } from "../Netscript/WorkerScript";
export interface IBladeburner {
numHosp: number;
moneyLost: number;
rank: number;
maxRank: number;
numHosp: number;
moneyLost: number;
rank: number;
maxRank: number;
skillPoints: number;
totalSkillPoints: number;
skillPoints: number;
totalSkillPoints: number;
teamSize: number;
teamLost: number;
hpLost: number;
teamSize: number;
teamLost: number;
hpLost: number;
storedCycles: number;
storedCycles: number;
randomEventCounter: number;
randomEventCounter: number;
actionTimeToComplete: number;
actionTimeCurrent: number;
actionTimeOverflow: number;
actionTimeToComplete: number;
actionTimeCurrent: number;
actionTimeOverflow: number;
action: IActionIdentifier;
action: IActionIdentifier;
cities: any;
city: string;
skills: any;
skillMultipliers: any;
staminaBonus: number;
maxStamina: number;
stamina: number;
contracts: any;
operations: any;
blackops: any;
logging: any;
automateEnabled: boolean;
automateActionHigh: IActionIdentifier;
automateThreshHigh: number;
automateActionLow: IActionIdentifier;
automateThreshLow: number;
consoleHistory: string[];
consoleLogs: string[];
cities: any;
city: string;
skills: any;
skillMultipliers: any;
staminaBonus: number;
maxStamina: number;
stamina: number;
contracts: any;
operations: any;
blackops: any;
logging: any;
automateEnabled: boolean;
automateActionHigh: IActionIdentifier;
automateThreshHigh: number;
automateActionLow: IActionIdentifier;
automateThreshLow: number;
consoleHistory: string[];
consoleLogs: string[];
getCurrentCity(): City;
calculateStaminaPenalty(): number;
startAction(player: IPlayer, action: IActionIdentifier): void;
upgradeSkill(skill: Skill): void;
executeConsoleCommands(player: IPlayer, command: string): void;
postToConsole(input: string, saveToLogs?: boolean): void;
log(input: string): void;
resetAction(): void;
clearConsole(): void;
getCurrentCity(): City;
calculateStaminaPenalty(): number;
startAction(player: IPlayer, action: IActionIdentifier): void;
upgradeSkill(skill: Skill): void;
executeConsoleCommands(player: IPlayer, command: string): void;
postToConsole(input: string, saveToLogs?: boolean): void;
log(input: string): void;
resetAction(): void;
clearConsole(): void;
prestige(): void;
storeCycles(numCycles?: number): void;
getTypeAndNameFromActionId(actionId: IActionIdentifier): {type: string; name: string};
getContractNamesNetscriptFn(): string[];
getOperationNamesNetscriptFn(): string[];
getBlackOpNamesNetscriptFn(): string[];
getGeneralActionNamesNetscriptFn(): string[];
getSkillNamesNetscriptFn(): string[];
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean;
getActionTimeNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): number;
getActionEstimatedSuccessChanceNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): number[];
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number;
getSkillUpgradeCostNetscriptFn(skillName: string, workerScript: WorkerScript): number;
upgradeSkillNetscriptFn(skillName: string, workerScript: WorkerScript): boolean;
getTeamSizeNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
setTeamSizeNetscriptFn(type: string, name: string, size: number, workerScript: WorkerScript): number;
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean;
getActionIdFromTypeAndName(type: string, name: string): IActionIdentifier | null;
executeStartConsoleCommand(player: IPlayer, args: string[]): void;
executeSkillConsoleCommand(args: string[]): void;
executeLogConsoleCommand(args: string[]): void;
executeHelpConsoleCommand(args: string[]): void;
executeAutomateConsoleCommand(args: string[]): void;
parseCommandArguments(command: string): string[];
executeConsoleCommand(player: IPlayer, command: string): void;
triggerMigration(sourceCityName: string): void;
triggerPotentialMigration(sourceCityName: string, chance: number): void;
randomEvent(): void;
gainActionStats(player: IPlayer, action: IAction, success: boolean): void;
getDiplomacyEffectiveness(player: IPlayer): number;
getRecruitmentSuccessChance(player: IPlayer): number;
getRecruitmentTime(player: IPlayer): number;
resetSkillMultipliers(): void;
updateSkillMultipliers(): void;
completeOperation(success: boolean): void;
getActionObject(actionId: IActionIdentifier): IAction | null;
completeContract(success: boolean): void;
completeAction(player: IPlayer): void;
changeRank(player: IPlayer, change: number): void;
processAction(player: IPlayer, seconds: number): void;
calculateStaminaGainPerSecond(player: IPlayer): number;
calculateMaxStamina(player: IPlayer): void;
create(): void;
process(player: IPlayer): void;
}
prestige(): void;
storeCycles(numCycles?: number): void;
getTypeAndNameFromActionId(actionId: IActionIdentifier): {
type: string;
name: string;
};
getContractNamesNetscriptFn(): string[];
getOperationNamesNetscriptFn(): string[];
getBlackOpNamesNetscriptFn(): string[];
getGeneralActionNamesNetscriptFn(): string[];
getSkillNamesNetscriptFn(): string[];
startActionNetscriptFn(
player: IPlayer,
type: string,
name: string,
workerScript: WorkerScript,
): boolean;
getActionTimeNetscriptFn(
player: IPlayer,
type: string,
name: string,
workerScript: WorkerScript,
): number;
getActionEstimatedSuccessChanceNetscriptFn(
player: IPlayer,
type: string,
name: string,
workerScript: WorkerScript,
): number[];
getActionCountRemainingNetscriptFn(
type: string,
name: string,
workerScript: WorkerScript,
): number;
getSkillLevelNetscriptFn(
skillName: string,
workerScript: WorkerScript,
): number;
getSkillUpgradeCostNetscriptFn(
skillName: string,
workerScript: WorkerScript,
): number;
upgradeSkillNetscriptFn(
skillName: string,
workerScript: WorkerScript,
): boolean;
getTeamSizeNetscriptFn(
type: string,
name: string,
workerScript: WorkerScript,
): number;
setTeamSizeNetscriptFn(
type: string,
name: string,
size: number,
workerScript: WorkerScript,
): number;
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean;
getActionIdFromTypeAndName(
type: string,
name: string,
): IActionIdentifier | null;
executeStartConsoleCommand(player: IPlayer, args: string[]): void;
executeSkillConsoleCommand(args: string[]): void;
executeLogConsoleCommand(args: string[]): void;
executeHelpConsoleCommand(args: string[]): void;
executeAutomateConsoleCommand(args: string[]): void;
parseCommandArguments(command: string): string[];
executeConsoleCommand(player: IPlayer, command: string): void;
triggerMigration(sourceCityName: string): void;
triggerPotentialMigration(sourceCityName: string, chance: number): void;
randomEvent(): void;
gainActionStats(player: IPlayer, action: IAction, success: boolean): void;
getDiplomacyEffectiveness(player: IPlayer): number;
getRecruitmentSuccessChance(player: IPlayer): number;
getRecruitmentTime(player: IPlayer): number;
resetSkillMultipliers(): void;
updateSkillMultipliers(): void;
completeOperation(success: boolean): void;
getActionObject(actionId: IActionIdentifier): IAction | null;
completeContract(success: boolean): void;
completeAction(player: IPlayer): void;
changeRank(player: IPlayer, change: number): void;
processAction(player: IPlayer, seconds: number): void;
calculateStaminaGainPerSecond(player: IPlayer): number;
calculateMaxStamina(player: IPlayer): void;
create(): void;
process(player: IPlayer): void;
}

@ -1,57 +1,63 @@
import { IBladeburner } from "./IBladeburner";
import { BladeburnerConstants } from "./data/Constants";
import { Action, IActionParams } from "./Action";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
export interface IOperationParams extends IActionParams {
reqdRank?: number;
teamCount?: number;
reqdRank?: number;
teamCount?: number;
}
export class Operation extends Action {
reqdRank = 100;
teamCount = 0;
reqdRank = 100;
teamCount = 0;
constructor(params: IOperationParams | null = null) {
super(params);
if(params && params.reqdRank) this.reqdRank = params.reqdRank;
if(params && params.teamCount) this.teamCount = params.teamCount;
constructor(params: IOperationParams | null = null) {
super(params);
if (params && params.reqdRank) this.reqdRank = params.reqdRank;
if (params && params.teamCount) this.teamCount = params.teamCount;
}
// For actions that have teams. To be implemented by subtypes.
getTeamSuccessBonus(inst: IBladeburner): number {
if (this.teamCount && this.teamCount > 0) {
this.teamCount = Math.min(this.teamCount, inst.teamSize);
const teamMultiplier = Math.pow(this.teamCount, 0.05);
return teamMultiplier;
}
// For actions that have teams. To be implemented by subtypes.
getTeamSuccessBonus(inst: IBladeburner): number {
if (this.teamCount && this.teamCount > 0) {
this.teamCount = Math.min(this.teamCount, inst.teamSize);
const teamMultiplier = Math.pow(this.teamCount, 0.05);
return teamMultiplier;
}
return 1;
}
return 1;
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceOperation;
}
getChaosDifficultyBonus(
inst: IBladeburner /*, params: ISuccessChanceParams*/,
): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
const mult = Math.pow(diff, 0.1);
return mult;
}
getActionTypeSkillSuccessBonus(inst: IBladeburner): number {
return inst.skillMultipliers.successChanceOperation;
}
return 1;
}
getChaosDifficultyBonus(inst: IBladeburner/*, params: ISuccessChanceParams*/): number {
const city = inst.getCurrentCity();
if (city.chaos > BladeburnerConstants.ChaosThreshold) {
const diff = 1 + (city.chaos - BladeburnerConstants.ChaosThreshold);
const mult = Math.pow(diff, 0.1);
return mult;
}
toJSON(): any {
return Generic_toJSON("Operation", this);
}
return 1;
}
toJSON(): any {
return Generic_toJSON("Operation", this);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Operation {
return Generic_fromJSON(Operation, value.data);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): Operation {
return Generic_fromJSON(Operation, value.data);
}
}
Reviver.constructors.Operation = Operation;
Reviver.constructors.Operation = Operation;

@ -1,130 +1,169 @@
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
interface ISkillParams {
name: string;
desc: string;
name: string;
desc: string;
baseCost?: number;
costInc?: number;
maxLvl?: number;
baseCost?: number;
costInc?: number;
maxLvl?: number;
successChanceAll?: number;
successChanceStealth?: number;
successChanceKill?: number;
successChanceContract?: number;
successChanceOperation?: number;
successChanceEstimate?: number;
successChanceAll?: number;
successChanceStealth?: number;
successChanceKill?: number;
successChanceContract?: number;
successChanceOperation?: number;
successChanceEstimate?: number;
actionTime?: number;
actionTime?: number;
effHack?: number;
effStr?: number;
effDef?: number;
effDex?: number;
effAgi?: number;
effCha?: number;
effHack?: number;
effStr?: number;
effDef?: number;
effDex?: number;
effAgi?: number;
effCha?: number;
stamina?: number;
money?: number;
expGain?: number;
stamina?: number;
money?: number;
expGain?: number;
}
export class Skill {
name: string;
desc: string;
// Cost is in Skill Points
baseCost = 1;
// Additive cost increase per level
costInc = 1;
maxLvl = 0;
name: string;
desc: string;
// Cost is in Skill Points
baseCost = 1;
// Additive cost increase per level
costInc = 1;
maxLvl = 0;
/**
* These benefits are additive. So total multiplier will be level (handled externally) times the
* effects below
*/
successChanceAll = 0;
successChanceStealth = 0;
successChanceKill = 0;
successChanceContract = 0;
successChanceOperation = 0;
/**
* These benefits are additive. So total multiplier will be level (handled externally) times the
* effects below
*/
successChanceAll = 0;
successChanceStealth = 0;
successChanceKill = 0;
successChanceContract = 0;
successChanceOperation = 0;
/**
* This multiplier affects everything that increases synthoid population/community estimate
* e.g. Field analysis, Investigation Op, Undercover Op
*/
successChanceEstimate = 0;
actionTime = 0;
effHack = 0;
effStr = 0;
effDef = 0;
effDex = 0;
effAgi = 0;
effCha = 0;
stamina = 0;
money = 0;
expGain = 0;
/**
* This multiplier affects everything that increases synthoid population/community estimate
* e.g. Field analysis, Investigation Op, Undercover Op
*/
successChanceEstimate = 0;
actionTime = 0;
effHack = 0;
effStr = 0;
effDef = 0;
effDex = 0;
effAgi = 0;
effCha = 0;
stamina = 0;
money = 0;
expGain = 0;
constructor(params: ISkillParams={name:"foo", desc:"foo"}) {
if (!params.name) {
throw new Error("Failed to initialize Bladeburner Skill. No name was specified in ctor");
}
if (!params.desc) {
throw new Error("Failed to initialize Bladeburner Skills. No desc was specified in ctor");
}
this.name = params.name;
this.desc = params.desc;
this.baseCost = params.baseCost ? params.baseCost : 1;
this.costInc = params.costInc ? params.costInc : 1;
constructor(params: ISkillParams = { name: "foo", desc: "foo" }) {
if (!params.name) {
throw new Error(
"Failed to initialize Bladeburner Skill. No name was specified in ctor",
);
}
if (!params.desc) {
throw new Error(
"Failed to initialize Bladeburner Skills. No desc was specified in ctor",
);
}
this.name = params.name;
this.desc = params.desc;
this.baseCost = params.baseCost ? params.baseCost : 1;
this.costInc = params.costInc ? params.costInc : 1;
if (params.maxLvl) {this.maxLvl = params.maxLvl;}
if (params.successChanceAll) {this.successChanceAll = params.successChanceAll;}
if (params.successChanceStealth) {this.successChanceStealth = params.successChanceStealth;}
if (params.successChanceKill) {this.successChanceKill = params.successChanceKill;}
if (params.successChanceContract) {this.successChanceContract = params.successChanceContract;}
if (params.successChanceOperation) {this.successChanceOperation = params.successChanceOperation;}
if (params.successChanceEstimate) {this.successChanceEstimate = params.successChanceEstimate;}
if (params.actionTime) {this.actionTime = params.actionTime;}
if (params.effHack) {this.effHack = params.effHack;}
if (params.effStr) {this.effStr = params.effStr;}
if (params.effDef) {this.effDef = params.effDef;}
if (params.effDex) {this.effDex = params.effDex;}
if (params.effAgi) {this.effAgi = params.effAgi;}
if (params.effCha) {this.effCha = params.effCha;}
if (params.stamina) {this.stamina = params.stamina;}
if (params.money) {this.money = params.money;}
if (params.expGain) {this.expGain = params.expGain;}
if (params.maxLvl) {
this.maxLvl = params.maxLvl;
}
calculateCost(currentLevel: number): number {
return Math.floor((this.baseCost + (currentLevel * this.costInc)) * BitNodeMultipliers.BladeburnerSkillCost);
if (params.successChanceAll) {
this.successChanceAll = params.successChanceAll;
}
if (params.successChanceStealth) {
this.successChanceStealth = params.successChanceStealth;
}
if (params.successChanceKill) {
this.successChanceKill = params.successChanceKill;
}
if (params.successChanceContract) {
this.successChanceContract = params.successChanceContract;
}
if (params.successChanceOperation) {
this.successChanceOperation = params.successChanceOperation;
}
getMultiplier(name: string): number {
if(name === "successChanceAll") return this.successChanceAll;
if(name === "successChanceStealth") return this.successChanceStealth;
if(name === "successChanceKill") return this.successChanceKill;
if(name === "successChanceContract") return this.successChanceContract;
if(name === "successChanceOperation") return this.successChanceOperation;
if(name === "successChanceEstimate") return this.successChanceEstimate;
if(name === "actionTime") return this.actionTime;
if(name === "effHack") return this.effHack;
if(name === "effStr") return this.effStr;
if(name === "effDef") return this.effDef;
if(name === "effDex") return this.effDex;
if(name === "effAgi") return this.effAgi;
if(name === "effCha") return this.effCha;
if(name === "stamina") return this.stamina;
if(name === "money") return this.money;
if(name === "expGain") return this.expGain;
return 0;
if (params.successChanceEstimate) {
this.successChanceEstimate = params.successChanceEstimate;
}
if (params.actionTime) {
this.actionTime = params.actionTime;
}
if (params.effHack) {
this.effHack = params.effHack;
}
if (params.effStr) {
this.effStr = params.effStr;
}
if (params.effDef) {
this.effDef = params.effDef;
}
if (params.effDex) {
this.effDex = params.effDex;
}
if (params.effAgi) {
this.effAgi = params.effAgi;
}
if (params.effCha) {
this.effCha = params.effCha;
}
if (params.stamina) {
this.stamina = params.stamina;
}
if (params.money) {
this.money = params.money;
}
if (params.expGain) {
this.expGain = params.expGain;
}
}
calculateCost(currentLevel: number): number {
return Math.floor(
(this.baseCost + currentLevel * this.costInc) *
BitNodeMultipliers.BladeburnerSkillCost,
);
}
getMultiplier(name: string): number {
if (name === "successChanceAll") return this.successChanceAll;
if (name === "successChanceStealth") return this.successChanceStealth;
if (name === "successChanceKill") return this.successChanceKill;
if (name === "successChanceContract") return this.successChanceContract;
if (name === "successChanceOperation") return this.successChanceOperation;
if (name === "successChanceEstimate") return this.successChanceEstimate;
if (name === "actionTime") return this.actionTime;
if (name === "effHack") return this.effHack;
if (name === "effStr") return this.effStr;
if (name === "effDef") return this.effDef;
if (name === "effDex") return this.effDex;
if (name === "effAgi") return this.effAgi;
if (name === "effCha") return this.effCha;
if (name === "stamina") return this.stamina;
if (name === "money") return this.money;
if (name === "expGain") return this.expGain;
return 0;
}
}

@ -4,87 +4,112 @@ import { IMap } from "../types";
export const Skills: IMap<Skill> = {};
(function(){
Skills[SkillNames.BladesIntuition] = new Skill({
name:SkillNames.BladesIntuition,
desc:"Each level of this skill increases your success chance " +
"for all Contracts, Operations, and BlackOps by 3%",
baseCost: 3, costInc: 2.1,
successChanceAll:3,
});
Skills[SkillNames.Cloak] = new Skill({
name:SkillNames.Cloak,
desc:"Each level of this skill increases your " +
"success chance in stealth-related Contracts, Operations, and BlackOps by 5.5%",
baseCost: 2, costInc: 1.1,
successChanceStealth:5.5,
});
Skills[SkillNames.ShortCircuit] = new Skill({
name:SkillNames.ShortCircuit,
desc:"Each level of this skill increases your success chance " +
"in Contracts, Operations, and BlackOps that involve retirement by 5.5%",
baseCost: 2, costInc: 2.1,
successChanceKill:5.5,
});
Skills[SkillNames.DigitalObserver] = new Skill({
name:SkillNames.DigitalObserver,
desc:"Each level of this skill increases your success chance in " +
"all Operations and BlackOps by 4%",
baseCost: 2, costInc: 2.1,
successChanceOperation:4,
});
Skills[SkillNames.Tracer] = new Skill({
name:SkillNames.Tracer,
desc:"Each level of this skill increases your success chance in " +
"all Contracts by 4%",
baseCost: 2, costInc: 2.1,
successChanceContract:4,
});
Skills[SkillNames.Overclock] = new Skill({
name:SkillNames.Overclock,
desc:"Each level of this skill decreases the time it takes " +
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 90)",
baseCost: 3, costInc: 1.4, maxLvl: 90,
actionTime:1,
});
Skills[SkillNames.Reaper] = new Skill({
name: SkillNames.Reaper,
desc: "Each level of this skill increases your effective combat stats for Bladeburner actions by 2%",
baseCost: 2, costInc: 2.1,
effStr: 2, effDef: 2, effDex: 2, effAgi: 2,
});
Skills[SkillNames.EvasiveSystem] = new Skill({
name:SkillNames.EvasiveSystem,
desc:"Each level of this skill increases your effective " +
"dexterity and agility for Bladeburner actions by 4%",
baseCost: 2, costInc: 2.1,
effDex: 4, effAgi: 4,
});
Skills[SkillNames.Datamancer] = new Skill({
name:SkillNames.Datamancer,
desc:"Each level of this skill increases your effectiveness in " +
"synthoid population analysis and investigation by 5%. " +
"This affects all actions that can potentially increase " +
"the accuracy of your synthoid population/community estimates.",
baseCost:3, costInc:1,
successChanceEstimate:5,
});
Skills[SkillNames.CybersEdge] = new Skill({
name:SkillNames.CybersEdge,
desc:"Each level of this skill increases your max stamina by 2%",
baseCost:1, costInc:3,
stamina:2,
});
Skills[SkillNames.HandsOfMidas] = new Skill({
name: SkillNames.HandsOfMidas,
desc: "Each level of this skill increases the amount of money you receive from Contracts by 10%",
baseCost: 2, costInc: 2.5,
money: 10,
});
Skills[SkillNames.Hyperdrive] = new Skill({
name: SkillNames.Hyperdrive,
desc: "Each level of this skill increases the experience earned from Contracts, Operations, and BlackOps by 10%",
baseCost: 1, costInc: 2.5,
expGain: 10,
});
})()
(function () {
Skills[SkillNames.BladesIntuition] = new Skill({
name: SkillNames.BladesIntuition,
desc:
"Each level of this skill increases your success chance " +
"for all Contracts, Operations, and BlackOps by 3%",
baseCost: 3,
costInc: 2.1,
successChanceAll: 3,
});
Skills[SkillNames.Cloak] = new Skill({
name: SkillNames.Cloak,
desc:
"Each level of this skill increases your " +
"success chance in stealth-related Contracts, Operations, and BlackOps by 5.5%",
baseCost: 2,
costInc: 1.1,
successChanceStealth: 5.5,
});
Skills[SkillNames.ShortCircuit] = new Skill({
name: SkillNames.ShortCircuit,
desc:
"Each level of this skill increases your success chance " +
"in Contracts, Operations, and BlackOps that involve retirement by 5.5%",
baseCost: 2,
costInc: 2.1,
successChanceKill: 5.5,
});
Skills[SkillNames.DigitalObserver] = new Skill({
name: SkillNames.DigitalObserver,
desc:
"Each level of this skill increases your success chance in " +
"all Operations and BlackOps by 4%",
baseCost: 2,
costInc: 2.1,
successChanceOperation: 4,
});
Skills[SkillNames.Tracer] = new Skill({
name: SkillNames.Tracer,
desc:
"Each level of this skill increases your success chance in " +
"all Contracts by 4%",
baseCost: 2,
costInc: 2.1,
successChanceContract: 4,
});
Skills[SkillNames.Overclock] = new Skill({
name: SkillNames.Overclock,
desc:
"Each level of this skill decreases the time it takes " +
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 90)",
baseCost: 3,
costInc: 1.4,
maxLvl: 90,
actionTime: 1,
});
Skills[SkillNames.Reaper] = new Skill({
name: SkillNames.Reaper,
desc: "Each level of this skill increases your effective combat stats for Bladeburner actions by 2%",
baseCost: 2,
costInc: 2.1,
effStr: 2,
effDef: 2,
effDex: 2,
effAgi: 2,
});
Skills[SkillNames.EvasiveSystem] = new Skill({
name: SkillNames.EvasiveSystem,
desc:
"Each level of this skill increases your effective " +
"dexterity and agility for Bladeburner actions by 4%",
baseCost: 2,
costInc: 2.1,
effDex: 4,
effAgi: 4,
});
Skills[SkillNames.Datamancer] = new Skill({
name: SkillNames.Datamancer,
desc:
"Each level of this skill increases your effectiveness in " +
"synthoid population analysis and investigation by 5%. " +
"This affects all actions that can potentially increase " +
"the accuracy of your synthoid population/community estimates.",
baseCost: 3,
costInc: 1,
successChanceEstimate: 5,
});
Skills[SkillNames.CybersEdge] = new Skill({
name: SkillNames.CybersEdge,
desc: "Each level of this skill increases your max stamina by 2%",
baseCost: 1,
costInc: 3,
stamina: 2,
});
Skills[SkillNames.HandsOfMidas] = new Skill({
name: SkillNames.HandsOfMidas,
desc: "Each level of this skill increases the amount of money you receive from Contracts by 10%",
baseCost: 2,
costInc: 2.5,
money: 10,
});
Skills[SkillNames.Hyperdrive] = new Skill({
name: SkillNames.Hyperdrive,
desc: "Each level of this skill increases the experience earned from Contracts, Operations, and BlackOps by 10%",
baseCost: 1,
costInc: 2.5,
expGain: 10,
});
})();

@ -1,27 +1,27 @@
// Action Identifier enum
export const ActionTypes: {
[key: string]: number;
"Idle": number;
"Contract": number;
"Operation": number;
"BlackOp": number;
"BlackOperation": number;
"Training": number;
"Recruitment": number;
"FieldAnalysis": number;
"Field Analysis": number;
"Diplomacy": number;
"Hyperbolic Regeneration Chamber": number;
[key: string]: number;
Idle: number;
Contract: number;
Operation: number;
BlackOp: number;
BlackOperation: number;
Training: number;
Recruitment: number;
FieldAnalysis: number;
"Field Analysis": number;
Diplomacy: number;
"Hyperbolic Regeneration Chamber": number;
} = {
"Idle": 1,
"Contract": 2,
"Operation": 3,
"BlackOp": 4,
"BlackOperation": 4,
"Training": 5,
"Recruitment": 6,
"FieldAnalysis": 7,
"Field Analysis": 7,
"Diplomacy": 8,
"Hyperbolic Regeneration Chamber": 9,
};
Idle: 1,
Contract: 2,
Operation: 3,
BlackOp: 4,
BlackOperation: 4,
Training: 5,
Recruitment: 6,
FieldAnalysis: 7,
"Field Analysis": 7,
Diplomacy: 8,
"Hyperbolic Regeneration Chamber": 9,
};

@ -1,79 +1,86 @@
export const BladeburnerConstants: {
CityNames: string[];
CyclesPerSecond: number;
StaminaGainPerSecond: number;
BaseStaminaLoss: number;
MaxStaminaToGainFactor: number;
DifficultyToTimeFactor: number;
DiffMultExponentialFactor: number;
DiffMultLinearFactor: number;
EffAgiLinearFactor: number;
EffDexLinearFactor: number;
EffAgiExponentialFactor: number;
EffDexExponentialFactor: number;
BaseRecruitmentTimeNeeded: number;
PopulationThreshold: number;
PopulationExponent: number;
ChaosThreshold: number;
BaseStatGain: number;
BaseIntGain: number;
ActionCountGrowthPeriod: number;
RankToFactionRepFactor: number;
RankNeededForFaction: number;
ContractSuccessesPerLevel: number;
OperationSuccessesPerLevel: number;
RanksPerSkillPoint: number;
ContractBaseMoneyGain: number;
HrcHpGain: number;
HrcStaminaGain: number;
CityNames: string[];
CyclesPerSecond: number;
StaminaGainPerSecond: number;
BaseStaminaLoss: number;
MaxStaminaToGainFactor: number;
DifficultyToTimeFactor: number;
DiffMultExponentialFactor: number;
DiffMultLinearFactor: number;
EffAgiLinearFactor: number;
EffDexLinearFactor: number;
EffAgiExponentialFactor: number;
EffDexExponentialFactor: number;
BaseRecruitmentTimeNeeded: number;
PopulationThreshold: number;
PopulationExponent: number;
ChaosThreshold: number;
BaseStatGain: number;
BaseIntGain: number;
ActionCountGrowthPeriod: number;
RankToFactionRepFactor: number;
RankNeededForFaction: number;
ContractSuccessesPerLevel: number;
OperationSuccessesPerLevel: number;
RanksPerSkillPoint: number;
ContractBaseMoneyGain: number;
HrcHpGain: number;
HrcStaminaGain: number;
} = {
CityNames: ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"],
CyclesPerSecond: 5, // Game cycle is 200 ms
CityNames: [
"Aevum",
"Chongqing",
"Sector-12",
"New Tokyo",
"Ishima",
"Volhaven",
],
CyclesPerSecond: 5, // Game cycle is 200 ms
StaminaGainPerSecond: 0.0085,
BaseStaminaLoss: 0.285, // Base stamina loss per action. Increased based on difficulty
MaxStaminaToGainFactor: 70000, // Max Stamina is divided by this to get bonus stamina gain
StaminaGainPerSecond: 0.0085,
BaseStaminaLoss: 0.285, // Base stamina loss per action. Increased based on difficulty
MaxStaminaToGainFactor: 70000, // Max Stamina is divided by this to get bonus stamina gain
DifficultyToTimeFactor: 10, // Action Difficulty divided by this to get base action time
DifficultyToTimeFactor: 10, // Action Difficulty divided by this to get base action time
/**
* The difficulty multiplier affects stamina loss and hp loss of an action. Also affects
* experience gain. Its formula is:
* difficulty ^ exponentialFactor + difficulty / linearFactor
*/
DiffMultExponentialFactor: 0.28,
DiffMultLinearFactor: 650,
/**
* The difficulty multiplier affects stamina loss and hp loss of an action. Also affects
* experience gain. Its formula is:
* difficulty ^ exponentialFactor + difficulty / linearFactor
*/
DiffMultExponentialFactor: 0.28,
DiffMultLinearFactor: 650,
/**
* These factors are used to calculate action time.
* They affect how much action time is reduced based on your agility and dexterity
*/
EffAgiLinearFactor: 10e3,
EffDexLinearFactor: 10e3,
EffAgiExponentialFactor: 0.04,
EffDexExponentialFactor: 0.035,
/**
* These factors are used to calculate action time.
* They affect how much action time is reduced based on your agility and dexterity
*/
EffAgiLinearFactor: 10e3,
EffDexLinearFactor: 10e3,
EffAgiExponentialFactor: 0.04,
EffDexExponentialFactor: 0.035,
BaseRecruitmentTimeNeeded: 300, // Base time needed (s) to complete a Recruitment action
BaseRecruitmentTimeNeeded: 300, // Base time needed (s) to complete a Recruitment action
PopulationThreshold: 1e9, // Population which determines baseline success rate
PopulationExponent: 0.7, // Exponent that influences how different populations affect success rate
ChaosThreshold: 50, // City chaos level after which it starts making tasks harder
PopulationThreshold: 1e9, // Population which determines baseline success rate
PopulationExponent: 0.7, // Exponent that influences how different populations affect success rate
ChaosThreshold: 50, // City chaos level after which it starts making tasks harder
BaseStatGain: 1, // Base stat gain per second
BaseIntGain: 0.003, // Base intelligence stat gain
BaseStatGain: 1, // Base stat gain per second
BaseIntGain: 0.003, // Base intelligence stat gain
ActionCountGrowthPeriod: 480, // Time (s) it takes for action count to grow by its specified value
ActionCountGrowthPeriod: 480, // Time (s) it takes for action count to grow by its specified value
RankToFactionRepFactor: 2, // Delta Faction Rep = this * Delta Rank
RankNeededForFaction: 25,
RankToFactionRepFactor: 2, // Delta Faction Rep = this * Delta Rank
RankNeededForFaction: 25,
ContractSuccessesPerLevel: 3, // How many successes you need to level up a contract
OperationSuccessesPerLevel: 2.5, // How many successes you need to level up an op
ContractSuccessesPerLevel: 3, // How many successes you need to level up a contract
OperationSuccessesPerLevel: 2.5, // How many successes you need to level up an op
RanksPerSkillPoint: 3, // How many ranks needed to get 1 Skill Point
RanksPerSkillPoint: 3, // How many ranks needed to get 1 Skill Point
ContractBaseMoneyGain: 250e3, // Base Money Gained per contract
ContractBaseMoneyGain: 250e3, // Base Money Gained per contract
HrcHpGain: 2, // HP Gained from Hyperbolic Regeneration chamber
HrcStaminaGain: 1, // Percentage Stamina gained from Hyperbolic Regeneration Chamber
}
HrcHpGain: 2, // HP Gained from Hyperbolic Regeneration chamber
HrcStaminaGain: 1, // Percentage Stamina gained from Hyperbolic Regeneration Chamber
};

@ -10,118 +10,105 @@ export const ConsoleHelpText: {
start: string[];
stop: string[];
} = {
helpList: [
"Use 'help [command]' to get more information about a particular Bladeburner console command.",
"",
" automate [var] [val] [hi/low] Configure simple automation for Bladeburner tasks",
" clear/cls Clear the console",
" help [cmd] Display this help text, or help text for a specific command",
" log [en/dis] [type] Enable or disable logging for events and actions",
" skill [action] [name] Level or display info about your Bladeburner skills",
" start [type] [name] Start a Bladeburner action/task" ,
" stop Stops your current Bladeburner action/task",
],
automate: [
"automate [var] [val] [hi/low]",
"",
"A simple way to automate your Bladeburner actions. This console command can be used " +
helpList: [
"Use 'help [command]' to get more information about a particular Bladeburner console command.",
"",
" automate [var] [val] [hi/low] Configure simple automation for Bladeburner tasks",
" clear/cls Clear the console",
" help [cmd] Display this help text, or help text for a specific command",
" log [en/dis] [type] Enable or disable logging for events and actions",
" skill [action] [name] Level or display info about your Bladeburner skills",
" start [type] [name] Start a Bladeburner action/task",
" stop Stops your current Bladeburner action/task",
],
automate: [
"automate [var] [val] [hi/low]",
"",
"A simple way to automate your Bladeburner actions. This console command can be used " +
"to automatically start an action when your stamina rises above a certain threshold, and " +
"automatically switch to another action when your stamina drops below another threshold.",
" automate status - Check the current status of your automation and get a brief description of what it'll do",
" automate en - Enable the automation feature",
" automate dis - Disable the automation feature",
"",
"There are four properties that must be set for this automation to work properly. Here is how to set them:",
"",
" automate stamina 100 high",
" automate contract Tracking high",
" automate stamina 50 low",
" automate general 'Field Analysis' low",
"",
"Using the four console commands above will set the automation to perform Tracking contracts " +
" automate status - Check the current status of your automation and get a brief description of what it'll do",
" automate en - Enable the automation feature",
" automate dis - Disable the automation feature",
"",
"There are four properties that must be set for this automation to work properly. Here is how to set them:",
"",
" automate stamina 100 high",
" automate contract Tracking high",
" automate stamina 50 low",
" automate general 'Field Analysis' low",
"",
"Using the four console commands above will set the automation to perform Tracking contracts " +
"if your stamina is 100 or higher, and then switch to Field Analysis if your stamina drops below " +
"50. Note that when setting the action, the name of the action is CASE-SENSITIVE. It must " +
"exactly match whatever the name is in the UI.",
],
clear: [
"clear",
"",
"Clears the console",
],
cls: [
"cls",
"",
"Clears the console",
],
help: [
"help [command]",
"",
"Running 'help' with no arguments displays the general help text, which lists all console commands " +
],
clear: ["clear", "", "Clears the console"],
cls: ["cls", "", "Clears the console"],
help: [
"help [command]",
"",
"Running 'help' with no arguments displays the general help text, which lists all console commands " +
"and a brief description of what they do. A command can be specified to get more specific help text " +
"about that particular command. For example:",
"",
" help automate",
"",
"will display specific information about using the automate console command",
],
log: [
"log [en/dis] [type]",
"",
"Enable or disable logging. By default, the results of completing actions such as contracts/operations are logged " +
"",
" help automate",
"",
"will display specific information about using the automate console command",
],
log: [
"log [en/dis] [type]",
"",
"Enable or disable logging. By default, the results of completing actions such as contracts/operations are logged " +
"in the console. There are also random events that are logged in the console as well. The five categories of " +
"things that get logged are:",
"",
"[general, contracts, ops, blackops, events]",
"",
"The logging for these categories can be enabled or disabled like so:",
"",
" log dis contracts - Disables logging that occurs when contracts are completed",
" log en contracts - Enables logging that occurs when contracts are completed",
" log dis events - Disables logging for Bladeburner random events",
"",
"Logging can be universally enabled/disabled using the 'all' keyword:",
"",
" log dis all",
" log en all",
],
skill: [
"skill [action] [name]",
"",
"Level or display information about your skills.",
"",
"To display information about all of your skills and your multipliers, use:",
"",
" skill list",
"",
"To display information about a specific skill, specify the name of the skill afterwards. " +
"",
"[general, contracts, ops, blackops, events]",
"",
"The logging for these categories can be enabled or disabled like so:",
"",
" log dis contracts - Disables logging that occurs when contracts are completed",
" log en contracts - Enables logging that occurs when contracts are completed",
" log dis events - Disables logging for Bladeburner random events",
"",
"Logging can be universally enabled/disabled using the 'all' keyword:",
"",
" log dis all",
" log en all",
],
skill: [
"skill [action] [name]",
"",
"Level or display information about your skills.",
"",
"To display information about all of your skills and your multipliers, use:",
"",
" skill list",
"",
"To display information about a specific skill, specify the name of the skill afterwards. " +
"Note that the name of the skill is case-sensitive. Enter it exactly as seen in the UI. If " +
"the name of the skill has whitespace, enclose the name of the skill in double quotation marks:",
"",
" skill list Reaper<br>" +
" skill list 'Digital Observer'",
"",
"This console command can also be used to level up skills:",
"",
" skill level [skill name]",
],
start: [
"start [type] [name]",
"",
"Start an action. An action is specified by its type and its name. The " +
"",
" skill list Reaper<br>" + " skill list 'Digital Observer'",
"",
"This console command can also be used to level up skills:",
"",
" skill level [skill name]",
],
start: [
"start [type] [name]",
"",
"Start an action. An action is specified by its type and its name. The " +
"name is case-sensitive. It must appear exactly as it does in the UI. If " +
"the name of the action has whitespace, enclose it in double quotation marks. " +
"Valid action types include:",
"",
"[general, contract, op, blackop]",
"",
"Examples:",
"",
" start contract Tracking",
" start op 'Undercover Operation'",
],
stop:[
"stop",
"",
"Stop your current action and go idle.",
],
}
"",
"[general, contract, op, blackop]",
"",
"Examples:",
"",
" start contract Tracking",
" start op 'Undercover Operation'",
],
stop: ["stop", "", "Stop your current action and go idle."],
};

@ -1,14 +1,30 @@
import * as React from "react";
export const stealthIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 166 132" style={{fill:'#adff2f'}}>
export const stealthIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16px"
height="16px"
viewBox="0 0 166 132"
style={{ fill: "#adff2f" }}
>
<g>
<path d="M132.658-0.18l-24.321,24.321c-7.915-2.71-16.342-4.392-25.087-4.392c-45.84,0-83,46-83,46 s14.1,17.44,35.635,30.844L12.32,120.158l12.021,12.021L144.68,11.841L132.658-0.18z M52.033,80.445 c-2.104-4.458-3.283-9.438-3.283-14.695c0-19.054,15.446-34.5,34.5-34.5c5.258,0,10.237,1.179,14.695,3.284L52.033,80.445z" />
<path d="M134.865,37.656l-18.482,18.482c0.884,3.052,1.367,6.275,1.367,9.612c0,19.055-15.446,34.5-34.5,34.5 c-3.337,0-6.56-0.483-9.611-1.367l-10.124,10.124c6.326,1.725,12.934,2.743,19.735,2.743c45.84,0,83-46,83-46 S153.987,50.575,134.865,37.656z" />
<path d="M132.658-0.18l-24.321,24.321c-7.915-2.71-16.342-4.392-25.087-4.392c-45.84,0-83,46-83,46 s14.1,17.44,35.635,30.844L12.32,120.158l12.021,12.021L144.68,11.841L132.658-0.18z M52.033,80.445 c-2.104-4.458-3.283-9.438-3.283-14.695c0-19.054,15.446-34.5,34.5-34.5c5.258,0,10.237,1.179,14.695,3.284L52.033,80.445z" />
<path d="M134.865,37.656l-18.482,18.482c0.884,3.052,1.367,6.275,1.367,9.612c0,19.055-15.446,34.5-34.5,34.5 c-3.337,0-6.56-0.483-9.611-1.367l-10.124,10.124c6.326,1.725,12.934,2.743,19.735,2.743c45.84,0,83-46,83-46 S153.987,50.575,134.865,37.656z" />
</g>
</svg>
export const killIcon = <svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="-22 0 511 511.99561" style={{fill:'#adff2f'}}>
</svg>
);
export const killIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16px"
height="16px"
viewBox="-22 0 511 511.99561"
style={{ fill: "#adff2f" }}
>
<path d="m.496094 466.242188 39.902344-39.902344 45.753906 45.753906-39.898438 39.902344zm0 0" />
<path d="m468.421875 89.832031-1.675781-89.832031-300.265625 300.265625 45.753906 45.753906zm0 0" />
<path d="m95.210938 316.785156 16.84375 16.847656h.003906l83.65625 83.65625 22.753906-22.753906-100.503906-100.503906zm0 0" />
<path d="m101.445312 365.300781-39.902343 39.902344 45.753906 45.753906 39.902344-39.902343-39.90625-39.902344zm0 0" />
</svg>
</svg>
);

@ -1,31 +1,31 @@
export const SkillNames: {
BladesIntuition: string;
Cloak: string;
Marksman: string;
WeaponProficiency: string;
ShortCircuit: string;
DigitalObserver: string;
Tracer: string;
Overclock: string;
Reaper: string;
EvasiveSystem: string;
Datamancer: string;
CybersEdge: string;
HandsOfMidas: string;
Hyperdrive: string;
BladesIntuition: string;
Cloak: string;
Marksman: string;
WeaponProficiency: string;
ShortCircuit: string;
DigitalObserver: string;
Tracer: string;
Overclock: string;
Reaper: string;
EvasiveSystem: string;
Datamancer: string;
CybersEdge: string;
HandsOfMidas: string;
Hyperdrive: string;
} = {
BladesIntuition: "Blade's Intuition",
Cloak: "Cloak",
Marksman: "Marksman",
WeaponProficiency: "Weapon Proficiency",
ShortCircuit: "Short-Circuit",
DigitalObserver: "Digital Observer",
Tracer: "Tracer",
Overclock: "Overclock",
Reaper: "Reaper",
EvasiveSystem: "Evasive System",
Datamancer: "Datamancer",
CybersEdge: "Cyber's Edge",
HandsOfMidas: "Hands of Midas",
Hyperdrive: "Hyperdrive",
}
BladesIntuition: "Blade's Intuition",
Cloak: "Cloak",
Marksman: "Marksman",
WeaponProficiency: "Weapon Proficiency",
ShortCircuit: "Short-Circuit",
DigitalObserver: "Digital Observer",
Tracer: "Tracer",
Overclock: "Overclock",
Reaper: "Reaper",
EvasiveSystem: "Evasive System",
Datamancer: "Datamancer",
CybersEdge: "Cyber's Edge",
HandsOfMidas: "Hands of Midas",
Hyperdrive: "Hyperdrive",
};

@ -9,41 +9,65 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function AllPages(props: IProps): React.ReactElement {
const [page, setPage] = useState('General');
const setRerender = useState(false)[1];
const [page, setPage] = useState("General");
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => setRerender(old => !old), 1000);
return () => clearInterval(id);
}, []);
useEffect(() => {
const id = setInterval(() => setRerender((old) => !old), 1000);
return () => clearInterval(id);
}, []);
function Header(props: {name: string}): React.ReactElement {
return (<a
onClick={()=>setPage(props.name)}
className={page !== props.name ?
"bladeburner-nav-button" :
"bladeburner-nav-button-inactive"}>
{props.name}
</a>);
}
return (<>
<Header name={'General'} />
<Header name={'Contracts'} />
<Header name={'Operations'} />
<Header name={'BlackOps'} />
<Header name={'Skills'} />
<div style={{display:"block", margin:"4px", padding:"4px"}}>
{page === 'General' && <GeneralActionPage bladeburner={props.bladeburner} player={props.player} />}
{page === 'Contracts' && <ContractPage bladeburner={props.bladeburner} player={props.player} />}
{page === 'Operations' && <OperationPage bladeburner={props.bladeburner} player={props.player} />}
{page === 'BlackOps' && <BlackOpPage bladeburner={props.bladeburner} player={props.player} />}
{page === 'Skills' && <SkillPage bladeburner={props.bladeburner} />}
</div>
<span className="text">{stealthIcon} = This action requires stealth, {killIcon} = This action involves retirement</span>
</>);
}
function Header(props: { name: string }): React.ReactElement {
return (
<a
onClick={() => setPage(props.name)}
className={
page !== props.name
? "bladeburner-nav-button"
: "bladeburner-nav-button-inactive"
}
>
{props.name}
</a>
);
}
return (
<>
<Header name={"General"} />
<Header name={"Contracts"} />
<Header name={"Operations"} />
<Header name={"BlackOps"} />
<Header name={"Skills"} />
<div style={{ display: "block", margin: "4px", padding: "4px" }}>
{page === "General" && (
<GeneralActionPage
bladeburner={props.bladeburner}
player={props.player}
/>
)}
{page === "Contracts" && (
<ContractPage bladeburner={props.bladeburner} player={props.player} />
)}
{page === "Operations" && (
<OperationPage
bladeburner={props.bladeburner}
player={props.player}
/>
)}
{page === "BlackOps" && (
<BlackOpPage bladeburner={props.bladeburner} player={props.player} />
)}
{page === "Skills" && <SkillPage bladeburner={props.bladeburner} />}
</div>
<span className="text">
{stealthIcon} = This action requires stealth, {killIcon} = This action
involves retirement
</span>
</>
);
}

@ -1,7 +1,7 @@
import React, { useState } from "react";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
@ -14,76 +14,108 @@ import { SuccessChance } from "./SuccessChance";
import { CopyableText } from "../../ui/React/CopyableText";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: any;
bladeburner: IBladeburner;
player: IPlayer;
action: any;
}
export function BlackOpElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isCompleted = (props.bladeburner.blackops[props.action.name] != null);
if(isCompleted) {
return (
<h2 style={{display: 'block'}}>{props.action.name} (COMPLETED)</h2>);
}
const setRerender = useState(false)[1];
const isCompleted = props.bladeburner.blackops[props.action.name] != null;
if (isCompleted) {
return (
<h2 style={{ display: "block" }}>{props.action.name} (COMPLETED)</h2>
);
}
const isActive = props.bladeburner.action.type === ActionTypes["BlackOperation"] && props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
const actionTime = props.action.getActionTime(props.bladeburner);
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow, props.bladeburner.actionTimeToComplete);
const isActive =
props.bladeburner.action.type === ActionTypes["BlackOperation"] &&
props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(
props.bladeburner,
);
const actionTime = props.action.getActionTime(props.bladeburner);
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
);
function onStart(): void {
props.bladeburner.action.type = ActionTypes.BlackOperation;
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function onStart(): void {
props.bladeburner.action.type = ActionTypes.BlackOperation;
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function onTeam(): void {
const popupId = "bladeburner-operation-set-team-size-popup";
createPopup(popupId, TeamSizePopup, {
bladeburner: props.bladeburner,
action: props.action,
popupId: popupId,
});
}
function onTeam(): void {
const popupId = "bladeburner-operation-set-team-size-popup";
createPopup(popupId, TeamSizePopup, {
bladeburner: props.bladeburner,
action: props.action,
popupId: popupId,
});
}
return (<>
<h2 style={{display: 'inline-block'}}>
{isActive ?
<><CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
<CopyableText value={props.action.name} />
}
</h2>
{isActive ?
<p style={{display: 'block'}}>{createProgressBarText({progress: computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
<>
<a
className={hasReqdRank ? "a-link-button" : "a-link-button-inactive"}
style={{margin:"3px", padding:"3px"}}
onClick={onStart}
>Start</a>
<a
onClick={onTeam}
style={{margin:"3px", padding:"3px"}}
className="a-link-button">
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
</a>
</>}
<br />
<br />
<p style={{display:"inline-block"}} dangerouslySetInnerHTML={{__html: props.action.desc}} />
<br />
<br />
<p style={{display:"block", color:hasReqdRank ? "white" : "red"}}>
Required Rank: {formatNumber(props.action.reqdRank, 0)}
return (
<>
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
<CopyableText value={props.action.name} />
)}
</h2>
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
className={hasReqdRank ? "a-link-button" : "a-link-button-inactive"}
style={{ margin: "3px", padding: "3px" }}
onClick={onStart}
>
Start
</a>
<a
onClick={onTeam}
style={{ margin: "3px", padding: "3px" }}
className="a-link-button"
>
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
</a>
</>
)}
<br />
<br />
<p
style={{ display: "inline-block" }}
dangerouslySetInnerHTML={{ __html: props.action.desc }}
/>
<br />
<br />
<p style={{ display: "block", color: hasReqdRank ? "white" : "red" }}>
Required Rank: {formatNumber(props.action.reqdRank, 0)}
</p>
<br />
<pre style={{ display: "inline-block" }}>
Estimated Success Chance:{" "}
<SuccessChance chance={estimatedSuccessChance} />{" "}
{props.action.isStealth ? stealthIcon : <></>}
{props.action.isKill ? killIcon : <></>}
<br />
<pre style={{display:"inline-block"}}>
Estimated Success Chance: <SuccessChance chance={estimatedSuccessChance} /> {props.action.isStealth?stealthIcon:<></>}{props.action.isKill?killIcon:<></>}
<br />
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}
</pre>
</>);
}
Time Required: {convertTimeMsToTimeElapsedString(actionTime * 1000)}
</pre>
</>
);
}

@ -6,31 +6,43 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function BlackOpList(props: IProps): React.ReactElement {
let blackops: BlackOperation[] = [];
for (const blackopName in BlackOperations) {
if (BlackOperations.hasOwnProperty(blackopName)) {
blackops.push(BlackOperations[blackopName]);
}
let blackops: BlackOperation[] = [];
for (const blackopName in BlackOperations) {
if (BlackOperations.hasOwnProperty(blackopName)) {
blackops.push(BlackOperations[blackopName]);
}
blackops.sort(function(a, b) {
return (a.reqdRank - b.reqdRank);
});
}
blackops.sort(function (a, b) {
return a.reqdRank - b.reqdRank;
});
blackops = blackops.filter((blackop: BlackOperation, i: number) => !(props.bladeburner.blackops[blackops[i].name] == null &&
i !== 0 &&
props.bladeburner.blackops[blackops[i-1].name] == null));
blackops = blackops.filter(
(blackop: BlackOperation, i: number) =>
!(
props.bladeburner.blackops[blackops[i].name] == null &&
i !== 0 &&
props.bladeburner.blackops[blackops[i - 1].name] == null
),
);
blackops = blackops.reverse();
blackops = blackops.reverse();
return (<>
{blackops.map((blackop: BlackOperation) => <li key={blackop.name} className="bladeburner-action">
<BlackOpElem bladeburner={props.bladeburner} action={blackop} player={props.player} />
</li>,
)}
</>);
}
return (
<>
{blackops.map((blackop: BlackOperation) => (
<li key={blackop.name} className="bladeburner-action">
<BlackOpElem
bladeburner={props.bladeburner}
action={blackop}
player={props.player}
/>
</li>
))}
</>
);
}

@ -5,25 +5,29 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
import { CopyableText } from "../../ui/React/CopyableText";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function BlackOpPage(props: IProps): React.ReactElement {
return (<>
<p style={{display: 'block', margin: '4px', padding: '4px'}}>
Black Operations (Black Ops) are special, one-time covert operations.
Each Black Op must be unlocked successively by completing
the one before it.
<br />
<br />
<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete
all of the Black Ops.</b>
<br />
<br />
Like normal operations, you may use a team for Black Ops. Failing
a black op will incur heavy HP and rank losses.
</p>
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
</>);
}
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
Black Operations (Black Ops) are special, one-time covert operations.
Each Black Op must be unlocked successively by completing the one before
it.
<br />
<br />
<b>
Your ultimate goal to climb through the ranks of Bladeburners is to
complete all of the Black Ops.
</b>
<br />
<br />
Like normal operations, you may use a team for Black Ops. Failing a
black op will incur heavy HP and rank losses.
</p>
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
</>
);
}

@ -4,112 +4,141 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface ILineProps {
content: any;
content: any;
}
function Line(props: ILineProps): React.ReactElement {
return (<tr>
<td className="bladeburner-console-line" style={{color: 'var(--my-font-color)', whiteSpace: 'pre-wrap'}}>{props.content}</td>
</tr>)
return (
<tr>
<td
className="bladeburner-console-line"
style={{ color: "var(--my-font-color)", whiteSpace: "pre-wrap" }}
>
{props.content}
</td>
</tr>
);
}
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function Console(props: IProps): React.ReactElement {
const lastRef = useRef<HTMLDivElement>(null);
const setRerender = useState(false)[1];
const lastRef = useRef<HTMLDivElement>(null);
const setRerender = useState(false)[1];
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(
props.bladeburner.consoleHistory.length,
);
// TODO: Figure out how to actually make the scrolling work correctly.
function scrollToBottom(): void {
if(!lastRef.current) return;
lastRef.current.scrollTop = lastRef.current.scrollHeight;
// TODO: Figure out how to actually make the scrolling work correctly.
function scrollToBottom(): void {
if (!lastRef.current) return;
lastRef.current.scrollTop = lastRef.current.scrollHeight;
}
function rerender(): void {
setRerender((old) => !old);
}
useEffect(() => {
const id = setInterval(rerender, 1000);
const id2 = setInterval(scrollToBottom, 100);
return () => {
clearInterval(id);
clearInterval(id2);
};
}, []);
function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
if (event.keyCode === 13) {
event.preventDefault();
const command = event.currentTarget.value;
event.currentTarget.value = "";
if (command.length > 0) {
props.bladeburner.postToConsole("> " + command);
props.bladeburner.executeConsoleCommands(props.player, command);
setConsoleHistoryIndex(props.bladeburner.consoleHistory.length);
rerender();
}
}
function rerender(): void {
setRerender(old => !old);
const consoleHistory = props.bladeburner.consoleHistory;
if (event.keyCode === 38) {
// up
let i = consoleHistoryIndex;
const len = consoleHistory.length;
if (len === 0) {
return;
}
if (i < 0 || i > len) {
setConsoleHistoryIndex(len);
}
if (i !== 0) {
i = i - 1;
}
setConsoleHistoryIndex(i);
const prevCommand = consoleHistory[i];
event.currentTarget.value = prevCommand;
}
useEffect(() => {
const id = setInterval(rerender, 1000);
const id2 = setInterval(scrollToBottom, 100);
return () => {
clearInterval(id);
clearInterval(id2);
};
}, []);
if (event.keyCode === 40) {
const i = consoleHistoryIndex;
const len = consoleHistory.length;
function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
if (event.keyCode === 13) {
event.preventDefault();
const command = event.currentTarget.value;
event.currentTarget.value = "";
if (command.length > 0) {
props.bladeburner.postToConsole("> " + command);
props.bladeburner.executeConsoleCommands(props.player, command);
setConsoleHistoryIndex(props.bladeburner.consoleHistory.length);
rerender();
}
}
if (len == 0) {
return;
}
if (i < 0 || i > len) {
setConsoleHistoryIndex(len);
}
const consoleHistory = props.bladeburner.consoleHistory;
if (event.keyCode === 38) { // up
let i = consoleHistoryIndex;
const len = consoleHistory.length;
if (len === 0) {return;}
if (i < 0 || i > len) {
setConsoleHistoryIndex(len);
}
if (i !== 0) {
i = i-1;
}
setConsoleHistoryIndex(i);
const prevCommand = consoleHistory[i];
event.currentTarget.value = prevCommand;
}
if (event.keyCode === 40) {
const i = consoleHistoryIndex;
const len = consoleHistory.length;
if (len == 0) {return;}
if (i < 0 || i > len) {
setConsoleHistoryIndex(len);
}
// Latest command, put nothing
if (i == len || i == len-1) {
setConsoleHistoryIndex(len);
event.currentTarget.value = "";
} else {
setConsoleHistoryIndex(consoleHistoryIndex+1);
const prevCommand = consoleHistory[consoleHistoryIndex+1];
event.currentTarget.value = prevCommand;
}
}
// Latest command, put nothing
if (i == len || i == len - 1) {
setConsoleHistoryIndex(len);
event.currentTarget.value = "";
} else {
setConsoleHistoryIndex(consoleHistoryIndex + 1);
const prevCommand = consoleHistory[consoleHistoryIndex + 1];
event.currentTarget.value = prevCommand;
}
}
}
return (<div ref={lastRef} className="bladeburner-console-div">
<table className="bladeburner-console-table">
<tbody>
{/*
return (
<div ref={lastRef} className="bladeburner-console-div">
<table className="bladeburner-console-table">
<tbody>
{/*
TODO: optimize this.
using `i` as a key here isn't great because it'll re-render everything
everytime the console reaches max length.
*/}
{props.bladeburner.consoleLogs.map((log: any, i: number) => <Line key={i} content={log} />)}
<tr key="input" id="bladeburner-console-input-row" className="bladeburner-console-input-row">
<td className="bladeburner-console-input-cell">
<pre>{"> "}</pre><input autoFocus className="bladeburner-console-input" tabIndex={1} type="text" onKeyDown={handleKeyDown} />
</td>
</tr>
</tbody>
</table>
</div>);
}
{props.bladeburner.consoleLogs.map((log: any, i: number) => (
<Line key={i} content={log} />
))}
<tr
key="input"
id="bladeburner-console-input-row"
className="bladeburner-console-input-row"
>
<td className="bladeburner-console-input-cell">
<pre>{"> "}</pre>
<input
autoFocus
className="bladeburner-console-input"
tabIndex={1}
type="text"
onKeyDown={handleKeyDown}
/>
</td>
</tr>
</tbody>
</table>
</div>
);
}

@ -2,8 +2,8 @@ import React, { useState } from "react";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants";
@ -13,107 +13,161 @@ import { SuccessChance } from "./SuccessChance";
import { CopyableText } from "../../ui/React/CopyableText";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: any;
bladeburner: IBladeburner;
player: IPlayer;
action: any;
}
export function ContractElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isActive = props.bladeburner.action.type === ActionTypes["Contract"] && props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
const successChance = props.action.getSuccessChance(props.bladeburner);
const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow, props.bladeburner.actionTimeToComplete);
const maxLevel = (props.action.level >= props.action.maxLevel);
const actionTime = props.action.getActionTime(props.bladeburner);
const autolevelCheckboxId = `bladeburner-${props.action.name}-autolevel-checkbox`;
const setRerender = useState(false)[1];
const isActive =
props.bladeburner.action.type === ActionTypes["Contract"] &&
props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(
props.bladeburner,
);
const successChance = props.action.getSuccessChance(props.bladeburner);
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
);
const maxLevel = props.action.level >= props.action.maxLevel;
const actionTime = props.action.getActionTime(props.bladeburner);
const autolevelCheckboxId = `bladeburner-${props.action.name}-autolevel-checkbox`;
function onStart(): void {
props.bladeburner.action.type = ActionTypes.Contract;
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function onStart(): void {
props.bladeburner.action.type = ActionTypes.Contract;
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function increaseLevel(): void {
++props.action.level;
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function increaseLevel(): void {
++props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function decreaseLevel(): void {
--props.action.level;
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function decreaseLevel(): void {
--props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function onAutolevel(event: React.ChangeEvent<HTMLInputElement>): void {
props.action.autoLevel = event.target.checked;
setRerender(old => !old);
}
function onAutolevel(event: React.ChangeEvent<HTMLInputElement>): void {
props.action.autoLevel = event.target.checked;
setRerender((old) => !old);
}
return (<>
<h2 style={{display: 'inline-block'}}>
{isActive ?
<><CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
<CopyableText value={props.action.name} />
}
</h2>
{isActive ?
<p style={{display: 'block'}}>{createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
return (
<>
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
<CopyableText value={props.action.name} />
)}
</h2>
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
onClick={onStart}
className="a-link-button"
style={{margin:"3px", padding:"3px"}}>
Start
</a>
</>}
<a
onClick={onStart}
className="a-link-button"
style={{ margin: "3px", padding: "3px" }}
>
Start
</a>
</>
)}
<br />
<br />
<pre className="tooltip" style={{ display: "inline-block" }}>
<span className="tooltiptext">
{props.action.getSuccessesNeededForNextLevel(
BladeburnerConstants.ContractSuccessesPerLevel,
)}{" "}
successes needed for next level
</span>
Level: {props.action.level} / {props.action.maxLevel}
</pre>
<a
onClick={increaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
maxLevel ? "a-link-button-inactive" : "a-link-button"
}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
</a>
<a
onClick={decreaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"
}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
</a>
<br />
<br />
<pre style={{ display: "inline-block" }}>
<span dangerouslySetInnerHTML={{ __html: props.action.desc }} />
<br />
<br />
<pre className="tooltip" style={{display:"inline-block"}}>
<span className="tooltiptext">
{props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.ContractSuccessesPerLevel)} successes needed for next level
</span>
Level: {props.action.level} / {props.action.maxLevel}
</pre>
<a
onClick={increaseLevel}
style={{padding:"2px", margin:"2px"}}
className={`tooltip ${maxLevel ? "a-link-button-inactive" : "a-link-button"}`}>
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
</a>
<a
onClick={decreaseLevel}
style={{padding:"2px", margin:"2px"}}
className={`tooltip ${props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"}`}>
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
</a>
Estimated success chance:{" "}
<SuccessChance chance={estimatedSuccessChance} />{" "}
{props.action.isStealth ? stealthIcon : <></>}
{props.action.isKill ? killIcon : <></>}
<br />
Time Required: {convertTimeMsToTimeElapsedString(actionTime * 1000)}
<br />
<pre style={{display: 'inline-block'}}>
<span dangerouslySetInnerHTML={{__html: props.action.desc}} />
<br /><br />
Estimated success chance: <SuccessChance chance={estimatedSuccessChance} /> {props.action.isStealth?stealthIcon:<></>}{props.action.isKill?killIcon:<></>}<br />
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}<br />
Contracts remaining: {Math.floor(props.action.count)}<br />
Successes: {props.action.successes}<br />
Failures: {props.action.failures}
</pre>
Contracts remaining: {Math.floor(props.action.count)}
<br />
<label
className="tooltip"
style={{color: 'white'}}
htmlFor={autolevelCheckboxId}>
Autolevel:
<span className="tooltiptext">Automatically increase operation level when possible</span>
</label>
<input
type="checkbox"
id={autolevelCheckboxId}
checked={props.action.autoLevel}
onChange={onAutolevel}/>
</>);
Successes: {props.action.successes}
<br />
Failures: {props.action.failures}
</pre>
<br />
<label
className="tooltip"
style={{ color: "white" }}
htmlFor={autolevelCheckboxId}
>
Autolevel:
<span className="tooltiptext">
Automatically increase operation level when possible
</span>
</label>
<input
type="checkbox"
id={autolevelCheckboxId}
checked={props.action.autoLevel}
onChange={onAutolevel}
/>
</>
);
}

@ -4,17 +4,24 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function ContractList(props: IProps): React.ReactElement {
const names = Object.keys(props.bladeburner.contracts);
const contracts = props.bladeburner.contracts;
return (<>
{names.map((name: string) => <li key={name} className="bladeburner-action">
<ContractElem bladeburner={props.bladeburner} action={contracts[name]} player={props.player} />
</li>,
)}
</>);
}
const names = Object.keys(props.bladeburner.contracts);
const contracts = props.bladeburner.contracts;
return (
<>
{names.map((name: string) => (
<li key={name} className="bladeburner-action">
<ContractElem
bladeburner={props.bladeburner}
action={contracts[name]}
player={props.player}
/>
</li>
))}
</>
);
}

@ -4,20 +4,24 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function ContractPage(props: IProps): React.ReactElement {
return (<>
<p style={{display: 'block', margin: '4px', padding: '4px'}}>
Complete contracts in order to increase your Bladeburner rank and earn money.
Failing a contract will cause you to lose HP, which can lead to hospitalization.
<br />
<br />
You can unlock higher-level contracts by successfully completing them.
Higher-level contracts are more difficult, but grant more rank, experience, and money.
</p>
<ContractList bladeburner={props.bladeburner} player={props.player} />
</>);
}
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
Complete contracts in order to increase your Bladeburner rank and earn
money. Failing a contract will cause you to lose HP, which can lead to
hospitalization.
<br />
<br />
You can unlock higher-level contracts by successfully completing them.
Higher-level contracts are more difficult, but grant more rank,
experience, and money.
</p>
<ContractList bladeburner={props.bladeburner} player={props.player} />
</>
);
}

@ -2,68 +2,106 @@ import React, { useState } from "react";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { CopyableText } from "../../ui/React/CopyableText";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: any;
bladeburner: IBladeburner;
player: IPlayer;
action: any;
}
export function GeneralActionElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isActive = props.action.name === props.bladeburner.action.name;
const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow, props.bladeburner.actionTimeToComplete);
const actionTime = (function(): number{
switch(props.action.name) {
case "Training":
case "Field Analysis":
return 30;
case "Diplomacy":
case "Hyperbolic Regeneration Chamber":
return 60;
case "Recruitment":
return props.bladeburner.getRecruitmentTime(props.player);
}
return -1; // dead code
})();
const successChance = props.action.name === "Recruitment" ? Math.max(0, Math.min(props.bladeburner.getRecruitmentSuccessChance(props.player), 1)) : -1;
function onStart(): void {
props.bladeburner.action.type = ActionTypes[(props.action.name as string)];
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
const setRerender = useState(false)[1];
const isActive = props.action.name === props.bladeburner.action.name;
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
);
const actionTime = (function (): number {
switch (props.action.name) {
case "Training":
case "Field Analysis":
return 30;
case "Diplomacy":
case "Hyperbolic Regeneration Chamber":
return 60;
case "Recruitment":
return props.bladeburner.getRecruitmentTime(props.player);
}
return -1; // dead code
})();
const successChance =
props.action.name === "Recruitment"
? Math.max(
0,
Math.min(
props.bladeburner.getRecruitmentSuccessChance(props.player),
1,
),
)
: -1;
return (<>
<h2 style={{display: 'inline-block'}}>
{isActive ?
<><CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
<CopyableText value={props.action.name} />
}
</h2>
{isActive ?
<p style={{display: 'block'}}>{createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
function onStart(): void {
props.bladeburner.action.type = ActionTypes[props.action.name as string];
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
return (
<>
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
<CopyableText value={props.action.name} />
)}
</h2>
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
onClick={onStart}
className="a-link-button"
style={{margin:"3px", padding:"3px"}}>
Start
</a>
</>}
<br />
<br />
<pre style={{display: 'inline-block'}} dangerouslySetInnerHTML={{__html: props.action.desc}}></pre><br /><br />
<pre style={{display: 'inline-block'}}>
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}
{successChance !== -1 && <><br />Estimated success chance: {formatNumber(successChance*100, 1)}%</>}
</pre>
</>);
}
<a
onClick={onStart}
className="a-link-button"
style={{ margin: "3px", padding: "3px" }}
>
Start
</a>
</>
)}
<br />
<br />
<pre
style={{ display: "inline-block" }}
dangerouslySetInnerHTML={{ __html: props.action.desc }}
></pre>
<br />
<br />
<pre style={{ display: "inline-block" }}>
Time Required: {convertTimeMsToTimeElapsedString(actionTime * 1000)}
{successChance !== -1 && (
<>
<br />
Estimated success chance: {formatNumber(successChance * 100, 1)}%
</>
)}
</pre>
</>
);
}

@ -6,21 +6,28 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function GeneralActionList(props: IProps): React.ReactElement {
const actions: Action[] = [];
for (const name in GeneralActions) {
if (GeneralActions.hasOwnProperty(name)) {
actions.push(GeneralActions[name]);
}
const actions: Action[] = [];
for (const name in GeneralActions) {
if (GeneralActions.hasOwnProperty(name)) {
actions.push(GeneralActions[name]);
}
return (<>
{actions.map((action: Action) => <li key={action.name} className="bladeburner-action">
<GeneralActionElem bladeburner={props.bladeburner} action={action} player={props.player} />
</li>,
)}
</>);
}
}
return (
<>
{actions.map((action: Action) => (
<li key={action.name} className="bladeburner-action">
<GeneralActionElem
bladeburner={props.bladeburner}
action={action}
player={props.player}
/>
</li>
))}
</>
);
}

@ -4,16 +4,21 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function GeneralActionPage(props: IProps): React.ReactElement {
return (<>
<p style={{display: 'block', margin: '4px', padding: '4px'}}>
These are generic actions that will assist you in your Bladeburner
duties. They will not affect your Bladeburner rank in any way.
</p>
<GeneralActionList bladeburner={props.bladeburner} player={props.player} />
</>);
}
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
These are generic actions that will assist you in your Bladeburner
duties. They will not affect your Bladeburner rank in any way.
</p>
<GeneralActionList
bladeburner={props.bladeburner}
player={props.player}
/>
</>
);
}

@ -2,8 +2,8 @@ import React, { useState } from "react";
import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import {
formatNumber,
convertTimeMsToTimeElapsedString,
formatNumber,
convertTimeMsToTimeElapsedString,
} from "../../../utils/StringHelperFunctions";
import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants";
@ -15,121 +15,176 @@ import { SuccessChance } from "./SuccessChance";
import { CopyableText } from "../../ui/React/CopyableText";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: any;
bladeburner: IBladeburner;
player: IPlayer;
action: any;
}
export function OperationElem(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const isActive = props.bladeburner.action.type === ActionTypes["Operation"] && props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(props.bladeburner);
const computedActionTimeCurrent = Math.min(props.bladeburner.actionTimeCurrent+props.bladeburner.actionTimeOverflow,props.bladeburner.actionTimeToComplete);
const maxLevel = (props.action.level >= props.action.maxLevel);
const actionTime = props.action.getActionTime(props.bladeburner);
const autolevelCheckboxId = `bladeburner-${props.action.name}-autolevel-checkbox`;
const setRerender = useState(false)[1];
const isActive =
props.bladeburner.action.type === ActionTypes["Operation"] &&
props.action.name === props.bladeburner.action.name;
const estimatedSuccessChance = props.action.getEstSuccessChance(
props.bladeburner,
);
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
);
const maxLevel = props.action.level >= props.action.maxLevel;
const actionTime = props.action.getActionTime(props.bladeburner);
const autolevelCheckboxId = `bladeburner-${props.action.name}-autolevel-checkbox`;
function onStart(): void {
props.bladeburner.action.type = ActionTypes.Operation;
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function onStart(): void {
props.bladeburner.action.type = ActionTypes.Operation;
props.bladeburner.action.name = props.action.name;
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function onTeam(): void {
const popupId = "bladeburner-operation-set-team-size-popup";
createPopup(popupId, TeamSizePopup, {
bladeburner: props.bladeburner,
action: props.action,
popupId: popupId,
});
}
function onTeam(): void {
const popupId = "bladeburner-operation-set-team-size-popup";
createPopup(popupId, TeamSizePopup, {
bladeburner: props.bladeburner,
action: props.action,
popupId: popupId,
});
}
function increaseLevel(): void {
++props.action.level;
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function increaseLevel(): void {
++props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function decreaseLevel(): void {
--props.action.level;
if (isActive) props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender(old => !old);
}
function decreaseLevel(): void {
--props.action.level;
if (isActive)
props.bladeburner.startAction(props.player, props.bladeburner.action);
setRerender((old) => !old);
}
function onAutolevel(event: React.ChangeEvent<HTMLInputElement>): void {
props.action.autoLevel = event.target.checked;
setRerender(old => !old);
}
function onAutolevel(event: React.ChangeEvent<HTMLInputElement>): void {
props.action.autoLevel = event.target.checked;
setRerender((old) => !old);
}
return (<>
<h2 style={{display: 'inline-block'}}>
{isActive ?
<><CopyableText value={props.action.name} /> (IN PROGRESS - {formatNumber(computedActionTimeCurrent, 0)} / {formatNumber(props.bladeburner.actionTimeToComplete, 0)})</> :
<CopyableText value={props.action.name} />
}
</h2>
{isActive ?
<p style={{display: 'block'}}>{createProgressBarText({progress:computedActionTimeCurrent / props.bladeburner.actionTimeToComplete})}</p> :
return (
<>
<h2 style={{ display: "inline-block" }}>
{isActive ? (
<>
<CopyableText value={props.action.name} /> (IN PROGRESS -{" "}
{formatNumber(computedActionTimeCurrent, 0)} /{" "}
{formatNumber(props.bladeburner.actionTimeToComplete, 0)})
</>
) : (
<CopyableText value={props.action.name} />
)}
</h2>
{isActive ? (
<p style={{ display: "block" }}>
{createProgressBarText({
progress:
computedActionTimeCurrent /
props.bladeburner.actionTimeToComplete,
})}
</p>
) : (
<>
<a
onClick={onStart}
className="a-link-button"
style={{margin:"3px", padding:"3px"}}>
Start
</a>
<a
onClick={onTeam}
style={{margin:"3px", padding:"3px"}}
className="a-link-button">
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
</a>
</>}
<a
onClick={onStart}
className="a-link-button"
style={{ margin: "3px", padding: "3px" }}
>
Start
</a>
<a
onClick={onTeam}
style={{ margin: "3px", padding: "3px" }}
className="a-link-button"
>
Set Team Size (Curr Size: {formatNumber(props.action.teamCount, 0)})
</a>
</>
)}
<br />
<br />
<pre className="tooltip" style={{ display: "inline-block" }}>
<span className="tooltiptext">
{props.action.getSuccessesNeededForNextLevel(
BladeburnerConstants.OperationSuccessesPerLevel,
)}{" "}
successes needed for next level
</span>
Level: {props.action.level} / {props.action.maxLevel}
</pre>
<a
onClick={increaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
maxLevel ? "a-link-button-inactive" : "a-link-button"
}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
</a>
<a
onClick={decreaseLevel}
style={{ padding: "2px", margin: "2px" }}
className={`tooltip ${
props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"
}`}
>
{isActive && (
<span className="tooltiptext">
WARNING: changing the level will restart the Operation
</span>
)}
</a>
<br />
<br />
<pre style={{ display: "inline-block" }}>
<span dangerouslySetInnerHTML={{ __html: props.action.desc }} />
<br />
<br />
<pre className="tooltip" style={{display:"inline-block"}}>
<span className="tooltiptext">
{props.action.getSuccessesNeededForNextLevel(BladeburnerConstants.OperationSuccessesPerLevel)} successes needed for next level
</span>
Level: {props.action.level} / {props.action.maxLevel}
</pre>
<a
onClick={increaseLevel}
style={{padding:"2px", margin:"2px"}}
className={`tooltip ${maxLevel ? "a-link-button-inactive" : "a-link-button"}`}>
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
</a>
<a
onClick={decreaseLevel}
style={{padding:"2px", margin:"2px"}}
className={`tooltip ${props.action.level <= 1 ? "a-link-button-inactive" : "a-link-button"}`}>
{isActive && (<span className="tooltiptext">WARNING: changing the level will restart the Operation</span>)}
</a>
Estimated success chance:{" "}
<SuccessChance chance={estimatedSuccessChance} />{" "}
{props.action.isStealth ? stealthIcon : <></>}
{props.action.isKill ? killIcon : <></>}
<br />
Time Required: {convertTimeMsToTimeElapsedString(actionTime * 1000)}
<br />
<pre style={{display:"inline-block"}}>
<span dangerouslySetInnerHTML={{__html: props.action.desc}} />
<br /><br />
Estimated success chance: <SuccessChance chance={estimatedSuccessChance} /> {props.action.isStealth?stealthIcon:<></>}{props.action.isKill?killIcon:<></>}<br />
Time Required: {convertTimeMsToTimeElapsedString(actionTime*1000)}<br />
Operations remaining: {Math.floor(props.action.count)}<br />
Successes: {props.action.successes}<br />
Failures: {props.action.failures}
</pre>
Operations remaining: {Math.floor(props.action.count)}
<br />
<label
className="tooltip"
style={{color: 'white'}}
htmlFor={autolevelCheckboxId}>
Autolevel:
<span className="tooltiptext">Automatically increase operation level when possible</span>
</label>
<input
type="checkbox"
id={autolevelCheckboxId}
checked={props.action.autoLevel}
onChange={onAutolevel}/>
</>);
Successes: {props.action.successes}
<br />
Failures: {props.action.failures}
</pre>
<br />
<label
className="tooltip"
style={{ color: "white" }}
htmlFor={autolevelCheckboxId}
>
Autolevel:
<span className="tooltiptext">
Automatically increase operation level when possible
</span>
</label>
<input
type="checkbox"
id={autolevelCheckboxId}
checked={props.action.autoLevel}
onChange={onAutolevel}
/>
</>
);
}

@ -4,17 +4,24 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function OperationList(props: IProps): React.ReactElement {
const names = Object.keys(props.bladeburner.operations);
const operations = props.bladeburner.operations;
return (<>
{names.map((name: string) => <li key={name} className="bladeburner-action">
<OperationElem bladeburner={props.bladeburner} action={operations[name]} player={props.player} />
</li>,
)}
</>);
}
const names = Object.keys(props.bladeburner.operations);
const operations = props.bladeburner.operations;
return (
<>
{names.map((name: string) => (
<li key={name} className="bladeburner-action">
<OperationElem
bladeburner={props.bladeburner}
action={operations[name]}
player={props.player}
/>
</li>
))}
</>
);
}

@ -4,31 +4,33 @@ import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
bladeburner: IBladeburner;
player: IPlayer;
}
export function OperationPage(props: IProps): React.ReactElement {
return (<>
<p style={{display: 'block', margin: '4px', padding: '4px'}}>
Carry out operations for the Bladeburner division.
Failing an operation will reduce your Bladeburner rank. It will also
cause you to lose HP, which can lead to hospitalization. In general,
operations are harder and more punishing than contracts,
but are also more rewarding.
<br />
<br />
Operations can affect the chaos level and Synthoid population of your
current city. The exact effects vary between different Operations.
<br />
<br />
For operations, you can use a team. You must first recruit team members.
Having a larger team will improves your chances of success.
<br />
<br />
You can unlock higher-level operations by successfully completing them.
Higher-level operations are more difficult, but grant more rank and experience.
</p>
<OperationList bladeburner={props.bladeburner} player={props.player} />
</>);
}
return (
<>
<p style={{ display: "block", margin: "4px", padding: "4px" }}>
Carry out operations for the Bladeburner division. Failing an operation
will reduce your Bladeburner rank. It will also cause you to lose HP,
which can lead to hospitalization. In general, operations are harder and
more punishing than contracts, but are also more rewarding.
<br />
<br />
Operations can affect the chaos level and Synthoid population of your
current city. The exact effects vary between different Operations.
<br />
<br />
For operations, you can use a team. You must first recruit team members.
Having a larger team will improves your chances of success.
<br />
<br />
You can unlock higher-level operations by successfully completing them.
Higher-level operations are more difficult, but grant more rank and
experience.
</p>
<OperationList bladeburner={props.bladeburner} player={props.player} />
</>
);
}

@ -8,21 +8,43 @@ import { IEngine } from "../../IEngine";
import { IBladeburner } from "../IBladeburner";
interface IProps {
bladeburner: IBladeburner;
engine: IEngine;
player: IPlayer;
bladeburner: IBladeburner;
engine: IEngine;
player: IPlayer;
}
export function Root(props: IProps): React.ReactElement {
return (<div id="bladeburner-container">
<div style={{height:"60%", display:"block", position:"relative"}}>
<div style={{height: '100%', width:"30%", display:"inline-block", border:"1px solid white"}}>
<Stats bladeburner={props.bladeburner} player={props.player} engine={props.engine} />
</div>
<Console bladeburner={props.bladeburner} player={props.player} />
return (
<div id="bladeburner-container">
<div style={{ height: "60%", display: "block", position: "relative" }}>
<div
style={{
height: "100%",
width: "30%",
display: "inline-block",
border: "1px solid white",
}}
>
<Stats
bladeburner={props.bladeburner}
player={props.player}
engine={props.engine}
/>
</div>
<div style={{width:"70%", display:"block", border:"1px solid white", marginTop:"6px", padding: "6px", position:"relative"}}>
<AllPages bladeburner={props.bladeburner} player={props.player} />
</div>
</div>);
}
<Console bladeburner={props.bladeburner} player={props.player} />
</div>
<div
style={{
width: "70%",
display: "block",
border: "1px solid white",
marginTop: "6px",
padding: "6px",
position: "relative",
}}
>
<AllPages bladeburner={props.bladeburner} player={props.player} />
</div>
</div>
);
}

@ -4,45 +4,62 @@ import { formatNumber } from "../../../utils/StringHelperFunctions";
import { IBladeburner } from "../IBladeburner";
interface IProps {
skill: any;
bladeburner: IBladeburner;
onUpgrade: () => void;
skill: any;
bladeburner: IBladeburner;
onUpgrade: () => void;
}
export function SkillElem(props: IProps): React.ReactElement {
const skillName = props.skill.name;
let currentLevel = 0;
if (props.bladeburner.skills[skillName] && !isNaN(props.bladeburner.skills[skillName])) {
currentLevel = props.bladeburner.skills[skillName];
}
const pointCost = props.skill.calculateCost(currentLevel);
const skillName = props.skill.name;
let currentLevel = 0;
if (
props.bladeburner.skills[skillName] &&
!isNaN(props.bladeburner.skills[skillName])
) {
currentLevel = props.bladeburner.skills[skillName];
}
const pointCost = props.skill.calculateCost(currentLevel);
const canLevel = props.bladeburner.skillPoints >= pointCost;
const maxLvl = props.skill.maxLvl ? currentLevel >= props.skill.maxLvl : false;
const canLevel = props.bladeburner.skillPoints >= pointCost;
const maxLvl = props.skill.maxLvl
? currentLevel >= props.skill.maxLvl
: false;
function onClick(): void {
if (props.bladeburner.skillPoints < pointCost) return;
props.bladeburner.skillPoints -= pointCost;
props.bladeburner.upgradeSkill(props.skill);
props.onUpgrade();
}
function onClick(): void {
if (props.bladeburner.skillPoints < pointCost) return;
props.bladeburner.skillPoints -= pointCost;
props.bladeburner.upgradeSkill(props.skill);
props.onUpgrade();
}
return (<>
<h2 style={{display: 'inline-block'}}>
<CopyableText value={props.skill.name} />
</h2>
<a
onClick={onClick}
style={{display: "inline-block", margin: "3px", padding: "3px"}}
className={canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive"}>
Level
</a>
<br />
<br />
<p style={{display: 'block'}}>Level: {currentLevel}</p>
{maxLvl ?
<p style={{color:"red", display:"block"}}>MAX LEVEL</p> :
<p style={{display:"block"}}>Skill Points required: {formatNumber(pointCost, 0)}</p>}
<p style={{display:"inline-block"}} dangerouslySetInnerHTML={{__html: props.skill.desc}} />
</>);
}
return (
<>
<h2 style={{ display: "inline-block" }}>
<CopyableText value={props.skill.name} />
</h2>
<a
onClick={onClick}
style={{ display: "inline-block", margin: "3px", padding: "3px" }}
className={
canLevel && !maxLvl ? "a-link-button" : "a-link-button-inactive"
}
>
Level
</a>
<br />
<br />
<p style={{ display: "block" }}>Level: {currentLevel}</p>
{maxLvl ? (
<p style={{ color: "red", display: "block" }}>MAX LEVEL</p>
) : (
<p style={{ display: "block" }}>
Skill Points required: {formatNumber(pointCost, 0)}
</p>
)}
<p
style={{ display: "inline-block" }}
dangerouslySetInnerHTML={{ __html: props.skill.desc }}
/>
</>
);
}

@ -4,15 +4,22 @@ import { Skills } from "../Skills";
import { IBladeburner } from "../IBladeburner";
interface IProps {
bladeburner: IBladeburner;
onUpgrade: () => void;
bladeburner: IBladeburner;
onUpgrade: () => void;
}
export function SkillList(props: IProps): React.ReactElement {
return (<>
{Object.keys(Skills).map((skill: string) => <li key={skill} className="bladeburner-action">
<SkillElem bladeburner={props.bladeburner} skill={Skills[skill]} onUpgrade={props.onUpgrade} />
</li>,
)}
</>);
}
return (
<>
{Object.keys(Skills).map((skill: string) => (
<li key={skill} className="bladeburner-action">
<SkillElem
bladeburner={props.bladeburner}
skill={Skills[skill]}
onUpgrade={props.onUpgrade}
/>
</li>
))}
</>
);
}

@ -5,51 +5,110 @@ import { formatNumber } from "../../../utils/StringHelperFunctions";
import { IBladeburner } from "../IBladeburner";
interface IProps {
bladeburner: IBladeburner;
bladeburner: IBladeburner;
}
export function SkillPage(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const mults = props.bladeburner.skillMultipliers;
const setRerender = useState(false)[1];
const mults = props.bladeburner.skillMultipliers;
function valid(mult: any): boolean {
return mult && mult !== 1
}
function valid(mult: any): boolean {
return mult && mult !== 1;
}
return (<>
<p>
<strong>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</strong>
</p>
<p>
You will gain one skill point every {BladeburnerConstants.RanksPerSkillPoint} ranks.
<br />
<br />
Note that when upgrading a skill, the benefit for that skill is additive.
However, the effects of different skills with each other is multiplicative.
<br />
</p>
return (
<>
<p>
<strong>
Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}
</strong>
</p>
<p>
You will gain one skill point every{" "}
{BladeburnerConstants.RanksPerSkillPoint} ranks.
<br />
{valid(mults["successChanceAll"]) && <p>Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}</p>}
{valid(mults["successChanceStealth"]) && <p>Stealth Success Chance: x{formatNumber(mults["successChanceStealth"], 3)}</p>}
{valid(mults["successChanceKill"]) && <p>Retirement Success Chance: x{formatNumber(mults["successChanceKill"], 3)}</p>}
{valid(mults["successChanceContract"]) && <p>Contract Success Chance: x{formatNumber(mults["successChanceContract"], 3)}</p>}
{valid(mults["successChanceOperation"]) && <p>Operation Success Chance: x{formatNumber(mults["successChanceOperation"], 3)}</p>}
{valid(mults["successChanceEstimate"]) && <p>Synthoid Data Estimate: x{formatNumber(mults["successChanceEstimate"], 3)}</p>}
{valid(mults["actionTime"]) && <p>Action Time: x{formatNumber(mults["actionTime"], 3)}</p>}
{valid(mults["effHack"]) && <p>Hacking Skill: x{formatNumber(mults["effHack"], 3)}</p>}
{valid(mults["effStr"]) && <p>Strength: x{formatNumber(mults["effStr"], 3)}</p>}
{valid(mults["effDef"]) && <p>Defense: x{formatNumber(mults["effDef"], 3)}</p>}
{valid(mults["effDex"]) && <p>Dexterity: x{formatNumber(mults["effDex"], 3)}</p>}
{valid(mults["effAgi"]) && <p>Agility: x{formatNumber(mults["effAgi"], 3)}</p>}
{valid(mults["effCha"]) && <p>Charisma: x{formatNumber(mults["effCha"], 3)}</p>}
{valid(mults["effInt"]) && <p>Intelligence: x{formatNumber(mults["effInt"], 3)}</p>}
{valid(mults["stamina"]) && <p>Stamina: x{formatNumber(mults["stamina"], 3)}</p>}
{valid(mults["money"]) && <p>Contract Money: x{formatNumber(mults["money"], 3)}</p>}
{valid(mults["expGain"]) && <p>Exp Gain: x{formatNumber(mults["expGain"], 3)}</p>}
<br />
<SkillList bladeburner={props.bladeburner} onUpgrade={() => setRerender(old => !old)} />
</>);
Note that when upgrading a skill, the benefit for that skill is
additive. However, the effects of different skills with each other is
multiplicative.
<br />
</p>
<br />
{valid(mults["successChanceAll"]) && (
<p>
Total Success Chance: x{formatNumber(mults["successChanceAll"], 3)}
</p>
)}
{valid(mults["successChanceStealth"]) && (
<p>
Stealth Success Chance: x
{formatNumber(mults["successChanceStealth"], 3)}
</p>
)}
{valid(mults["successChanceKill"]) && (
<p>
Retirement Success Chance: x
{formatNumber(mults["successChanceKill"], 3)}
</p>
)}
{valid(mults["successChanceContract"]) && (
<p>
Contract Success Chance: x
{formatNumber(mults["successChanceContract"], 3)}
</p>
)}
{valid(mults["successChanceOperation"]) && (
<p>
Operation Success Chance: x
{formatNumber(mults["successChanceOperation"], 3)}
</p>
)}
{valid(mults["successChanceEstimate"]) && (
<p>
Synthoid Data Estimate: x
{formatNumber(mults["successChanceEstimate"], 3)}
</p>
)}
{valid(mults["actionTime"]) && (
<p>Action Time: x{formatNumber(mults["actionTime"], 3)}</p>
)}
{valid(mults["effHack"]) && (
<p>Hacking Skill: x{formatNumber(mults["effHack"], 3)}</p>
)}
{valid(mults["effStr"]) && (
<p>Strength: x{formatNumber(mults["effStr"], 3)}</p>
)}
{valid(mults["effDef"]) && (
<p>Defense: x{formatNumber(mults["effDef"], 3)}</p>
)}
{valid(mults["effDex"]) && (
<p>Dexterity: x{formatNumber(mults["effDex"], 3)}</p>
)}
{valid(mults["effAgi"]) && (
<p>Agility: x{formatNumber(mults["effAgi"], 3)}</p>
)}
{valid(mults["effCha"]) && (
<p>Charisma: x{formatNumber(mults["effCha"], 3)}</p>
)}
{valid(mults["effInt"]) && (
<p>Intelligence: x{formatNumber(mults["effInt"], 3)}</p>
)}
{valid(mults["stamina"]) && (
<p>Stamina: x{formatNumber(mults["stamina"], 3)}</p>
)}
{valid(mults["money"]) && (
<p>Contract Money: x{formatNumber(mults["money"], 3)}</p>
)}
{valid(mults["expGain"]) && (
<p>Exp Gain: x{formatNumber(mults["expGain"], 3)}</p>
)}
<br />
<SkillList
bladeburner={props.bladeburner}
onUpgrade={() => setRerender((old) => !old)}
/>
</>
);
}
/*
@ -67,4 +126,4 @@ for (var i = 0; i < multKeys.length; ++i) {
}
}
}
*/
*/

Some files were not shown because too many files have changed in this diff Show More