mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-30 01:47:33 +01:00
commit
112f00f3d7
45
Quotes.txt
Normal file
45
Quotes.txt
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
Collection of Quotes
|
||||||
|
|
||||||
|
The past is relevant only as data
|
||||||
|
|
||||||
|
Pull on the new flesh like borrowed gloves and burn your fingers once again.
|
||||||
|
|
||||||
|
A weapon is a tool. A tool for killing and destroying. And there will be times
|
||||||
|
when you must kill and destroy. Then you will choose and equip yourself with the tools
|
||||||
|
that you need. But remember the weakness of weapons. They are an extension --
|
||||||
|
You are the killer and destroyer. You are whole, with or without them.
|
||||||
|
|
||||||
|
For all that we have done, as a civilization, as individuals, the universe is
|
||||||
|
not stable, and nor is any single thing within it. Stars consume themselves,
|
||||||
|
the universe itself rushes apart, and we ourselves are composed of matter in
|
||||||
|
constant flux. Colonies of cells in temporary alliance, replicating and
|
||||||
|
decaying and housed within, an incandescent cloud of electrical impulse and
|
||||||
|
precariously stacked carbon code memory. This is reality, this is self knowledge,
|
||||||
|
and the perception of it will, of course, make you dizzy.
|
||||||
|
|
||||||
|
You are still young and stupid. Human life has no value. Haven't you learned
|
||||||
|
that yet, Takeshi, with all you've seen? It has no value, intrinsic to itself.
|
||||||
|
Machines cost money to build. Raw materials cost money to extract. But people?"
|
||||||
|
She made a tiny spitting sound. "You can always get some more people. they
|
||||||
|
reproduce like cancer cells, whether you want them or not. They are abundant,
|
||||||
|
Takeshi. Why should they be valuable? Do you know that it costs us less to
|
||||||
|
recruit and use up a real snuff whore than it does to set up and run the virtual
|
||||||
|
equivalent format. Real human flesh is cheaper than a machine. It's the axiomatic
|
||||||
|
truth of our times.
|
||||||
|
|
||||||
|
Peace is an illusion, no matter how tranquil the world seems, peace doesn't last long.
|
||||||
|
Peace is a struggle against our very nature. A skin we sketch over the bone, muscle,
|
||||||
|
and sinew of our own innate savagery.
|
||||||
|
|
||||||
|
The human eye is a wonderful device. With a little effort, it can fail to see even
|
||||||
|
the most glaring injustice.
|
||||||
|
|
||||||
|
Humanity has spread to the stars. We set out like ancient seafarers to explore
|
||||||
|
the limitless ocean of space. But no matter how far we venture into the unknown,
|
||||||
|
the worst monsters are those we bring with us.
|
||||||
|
|
||||||
|
What we believe shapes who we are. Belief can bring us salvation or destruction.
|
||||||
|
But when you believe a lie for too long, the truth doesn't set you free. It tears
|
||||||
|
you apart.
|
||||||
|
|
||||||
|
We aren't meant to live forever. It corrupts even the best of us.
|
@ -31,13 +31,12 @@
|
|||||||
border: 1px solid #fff;
|
border: 1px solid #fff;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bladeburner-nav-button {
|
.bladeburner-nav-button {
|
||||||
@extend %bladeburner-nav-button;
|
@extend %bladeburner-nav-button;
|
||||||
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #3d4044;
|
background-color: #3d4044;
|
||||||
}
|
}
|
||||||
|
49
css/codemirror-overrides.scss
Normal file
49
css/codemirror-overrides.scss
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
@import "theme";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customized styling for the Code Mirror editor
|
||||||
|
*/
|
||||||
|
|
||||||
|
#codemirror-form-wrapper {
|
||||||
|
height: 80%;
|
||||||
|
margin: 10px 0px 0px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-selection-highlight-scrollbar {
|
||||||
|
background-color: #8F908A;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show Invisibles
|
||||||
|
*/
|
||||||
|
.cm-whitespace::before {
|
||||||
|
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;
|
||||||
|
}
|
@ -18,116 +18,6 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Script Editor */
|
|
||||||
#script-editor-container {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
#javascript-editor {
|
|
||||||
margin: 10px;
|
|
||||||
height: 80%;
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 6px;
|
|
||||||
padding-left: 6px;
|
|
||||||
padding-top: 6px;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
border: 2px solid var(--my-highlight-color);
|
|
||||||
z-index: 1;
|
|
||||||
font-family: $fontFamily;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ace_line,
|
|
||||||
.ace_line * {
|
|
||||||
background-color: transparent;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ace_text-input {
|
|
||||||
font-size: $defaultFontSize;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This temp element is used for auto adjusting filename field */
|
|
||||||
.tmp-element {
|
|
||||||
visibility: hidden;
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
#script-editor-container {
|
|
||||||
position: fixed;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#script-editor-buttons-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
padding-right: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#script-editor-wrapper {
|
|
||||||
height: 100%;
|
|
||||||
width: 70%;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
#script-editor-filename-wrapper {
|
|
||||||
background-color: #555;
|
|
||||||
margin-left: 6px;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#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);
|
|
||||||
|
|
||||||
background-color: #555;
|
|
||||||
display: inline-block;
|
|
||||||
float: center;
|
|
||||||
resize: none;
|
|
||||||
color: #fff;
|
|
||||||
margin: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
border: 2px solid var(--my-highlight-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#script-editor-status {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#script-editor-options-panel fieldset {
|
|
||||||
margin-top: 8px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
padding: 2px;
|
|
||||||
font-size: $defaultFontSize * 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Active scripts */
|
/* Active scripts */
|
||||||
.active-scripts-list {
|
.active-scripts-list {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
@ -537,70 +427,3 @@
|
|||||||
display: inline;
|
display: inline;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stock market */
|
|
||||||
#stock-market-container {
|
|
||||||
position: fixed;
|
|
||||||
padding: 6px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: $defaultFontSize * 0.8125;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
font-size: $defaultFontSize * 0.875;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change font size of Stock TIcker headers */
|
|
||||||
#stock-market-list li {
|
|
||||||
button {
|
|
||||||
font-size: $defaultFontSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#stock-market-container p {
|
|
||||||
padding: 10px;
|
|
||||||
margin: 10px;
|
|
||||||
width: 70%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#stock-market-container a {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#stock-market-watchlist-filter {
|
|
||||||
width: 50%;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stock-market-input {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 4px;
|
|
||||||
margin: 2px;
|
|
||||||
background-color: #000;
|
|
||||||
border: 1px solid #fff;
|
|
||||||
color: var(--my-font-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.stock-market-position-text {
|
|
||||||
color: #fff;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stock-market-order-list {
|
|
||||||
overflow-y: auto;
|
|
||||||
max-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stock-market-order-cancel-btn {
|
|
||||||
background-color: #000;
|
|
||||||
border: 1px solid #fff;
|
|
||||||
color: var(--my-font-color);
|
|
||||||
margin: 2px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 40%;
|
max-height: 50%;
|
||||||
top: 40%;
|
top: 40%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -10% 0 0 -25%;
|
margin: -10% 0 0 -25%;
|
||||||
|
22
css/redpill.scss
Normal file
22
css/redpill.scss
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
@import "theme";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for the Red Pill screen (the BitNode selection UI)
|
||||||
|
*/
|
||||||
|
#red-pill-container {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bitnode {
|
||||||
|
color: #00f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bitnode-destroyed {
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bitnode:hover,
|
||||||
|
.bitnode-destroyed:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
28
css/resleeving.scss
Normal file
28
css/resleeving.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Styling for the Re-Sleeving Page
|
||||||
|
*/
|
||||||
|
@import "theme";
|
||||||
|
|
||||||
|
.resleeve-container {
|
||||||
|
border: 1px solid white;
|
||||||
|
margin: 4px;
|
||||||
|
width: 75%;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: $defaultFontSize * 0.8125;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.resleeve-panel {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resleeve-aug-selector {
|
||||||
|
font-size: $defaultFontSize * 0.8125;
|
||||||
|
|
||||||
|
option {
|
||||||
|
font-size: $defaultFontSize * 0.8125;
|
||||||
|
}
|
||||||
|
}
|
123
css/scripteditor.scss
Normal file
123
css/scripteditor.scss
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
@import "mixins";
|
||||||
|
@import "theme";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for Script Editor (both Ace and CodeMirror)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#script-editor-container {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ace-editor {
|
||||||
|
margin: 10px;
|
||||||
|
height: 80%;
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 6px;
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
border: 2px solid var(--my-highlight-color);
|
||||||
|
z-index: 1;
|
||||||
|
font-family: $fontFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This temp element is used for auto adjusting filename field */
|
||||||
|
.tmp-element {
|
||||||
|
visibility: hidden;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
#script-editor-container {
|
||||||
|
position: fixed;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#script-editor-buttons-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#script-editor-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
width: 70%;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#script-editor-filename-wrapper {
|
||||||
|
background-color: #555;
|
||||||
|
margin-left: 6px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
background-color: #555;
|
||||||
|
display: inline-block;
|
||||||
|
float: center;
|
||||||
|
resize: none;
|
||||||
|
color: #fff;
|
||||||
|
margin: 4px;
|
||||||
|
padding: 2px;
|
||||||
|
border: 2px solid var(--my-highlight-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#script-editor-status {
|
||||||
|
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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#script-editor-options-panel fieldset {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 2px;
|
||||||
|
font-size: $defaultFontSize * 0.75;
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific overrides for Ace Editor */
|
||||||
|
.ace_line,
|
||||||
|
.ace_line * {
|
||||||
|
background-color: transparent;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ace_text-input {
|
||||||
|
font-size: $defaultFontSize;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specified overrides for Code mirror Editor are defined in codemirror-override.scss */
|
29
css/sleeves.scss
Normal file
29
css/sleeves.scss
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Styling for the Sleeves Management page
|
||||||
|
*/
|
||||||
|
@import "theme";
|
||||||
|
|
||||||
|
.sleeve-container {
|
||||||
|
border: 1px solid white;
|
||||||
|
margin: 4px;
|
||||||
|
width: 75%;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: $defaultFontSize * 0.875;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sleeves-page-info {
|
||||||
|
display: "block";
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sleeve-panel {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 2px;
|
||||||
|
|
||||||
|
select {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
66
css/stockmarket.scss
Normal file
66
css/stockmarket.scss
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
@import "theme";
|
||||||
|
|
||||||
|
#stock-market-container {
|
||||||
|
position: fixed;
|
||||||
|
padding: 6px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: $defaultFontSize * 0.8125;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
font-size: $defaultFontSize * 0.875;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#stock-market-list li {
|
||||||
|
button {
|
||||||
|
font-size: $defaultFontSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#stock-market-container p {
|
||||||
|
padding: 6px;
|
||||||
|
margin: 6px;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stock-market-container a {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stock-market-watchlist-filter {
|
||||||
|
width: 50%;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-market-input {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px;
|
||||||
|
margin: 2px;
|
||||||
|
background-color: #000;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
color: var(--my-font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-market-position-text {
|
||||||
|
color: #fff;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-market-order-list {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-market-order-cancel-btn {
|
||||||
|
background-color: #000;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
color: var(--my-font-color);
|
||||||
|
margin: 2px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
@ -35,11 +35,6 @@ li {
|
|||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
|
||||||
margin: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#entire-game-container {
|
#entire-game-container {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
@ -67,5 +67,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#terminal-input-text-box {
|
#terminal-input-text-box {
|
||||||
|
margin-left: 2px;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
@ -46,18 +46,6 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#red-pill-container,
|
|
||||||
#cinematic-text-container {
|
#cinematic-text-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bitnode {
|
|
||||||
color: #00f;
|
|
||||||
}
|
|
||||||
.bitnode-destroyed {
|
|
||||||
color: #f00;
|
|
||||||
}
|
|
||||||
.bitnode:hover,
|
|
||||||
.bitnode-destroyed:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
2
dist/engine.bundle.js
vendored
2
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
205
dist/engine.css
vendored
205
dist/engine.css
vendored
@ -1,3 +1,46 @@
|
|||||||
|
/* COLORS */
|
||||||
|
/* Attributes */
|
||||||
|
/**
|
||||||
|
* Customized styling for the Code Mirror editor
|
||||||
|
*/
|
||||||
|
#codemirror-form-wrapper {
|
||||||
|
height: 80%;
|
||||||
|
margin: 10px 0px 0px 6px; }
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border: 2px solid var(--my-highlight-color);
|
||||||
|
z-index: 1;
|
||||||
|
font-family: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas", "Courier New", Courier, monospace, "Times New Roman";
|
||||||
|
font-size: 16px; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlight matches
|
||||||
|
*/
|
||||||
|
.cm-matchhighlight {
|
||||||
|
background-color: #8F908A; }
|
||||||
|
|
||||||
|
.CodeMirror-selection-highlight-scrollbar {
|
||||||
|
background-color: #8F908A; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show Invisibles
|
||||||
|
*/
|
||||||
|
.cm-whitespace::before {
|
||||||
|
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; }
|
||||||
|
|
||||||
/* COLORS */
|
/* COLORS */
|
||||||
/* Attributes */
|
/* Attributes */
|
||||||
/* COLORS */
|
/* COLORS */
|
||||||
@ -40,10 +83,6 @@ ul {
|
|||||||
li {
|
li {
|
||||||
list-style-type: none; }
|
list-style-type: none; }
|
||||||
|
|
||||||
span {
|
|
||||||
margin: 4px;
|
|
||||||
padding: 4px; }
|
|
||||||
|
|
||||||
#entire-game-container {
|
#entire-game-container {
|
||||||
background-color: transparent; }
|
background-color: transparent; }
|
||||||
|
|
||||||
@ -771,29 +810,18 @@ button {
|
|||||||
white-space: pre; }
|
white-space: pre; }
|
||||||
|
|
||||||
#terminal-input-text-box {
|
#terminal-input-text-box {
|
||||||
|
margin-left: 2px;
|
||||||
flex: 1 1 auto; }
|
flex: 1 1 auto; }
|
||||||
|
|
||||||
/* COLORS */
|
/* COLORS */
|
||||||
/* Attributes */
|
/* Attributes */
|
||||||
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
/**
|
||||||
terminal which has its own page) */
|
* Styling for Script Editor (both Ace and CodeMirror)
|
||||||
.generic-menupage-container {
|
*/
|
||||||
height: 100%;
|
|
||||||
padding-left: 10px;
|
|
||||||
margin-left: 10%;
|
|
||||||
width: 99%;
|
|
||||||
overflow-y: scroll; }
|
|
||||||
|
|
||||||
/* Character Info */
|
|
||||||
#character-container {
|
|
||||||
padding-top: 10px;
|
|
||||||
position: fixed; }
|
|
||||||
|
|
||||||
/* Script Editor */
|
|
||||||
#script-editor-container {
|
#script-editor-container {
|
||||||
background-color: transparent; }
|
background-color: transparent; }
|
||||||
|
|
||||||
#javascript-editor {
|
#ace-editor {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -805,16 +833,6 @@ button {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
font-family: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas", "Courier New", Courier, monospace, "Times New Roman"; }
|
font-family: "Lucida Console", "Lucida Sans Unicode", "Fira Mono", "Consolas", "Courier New", Courier, monospace, "Times New Roman"; }
|
||||||
|
|
||||||
.ace_line,
|
|
||||||
.ace_line * {
|
|
||||||
background-color: transparent;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0; }
|
|
||||||
|
|
||||||
.ace_text-input {
|
|
||||||
font-size: 16px;
|
|
||||||
background-color: transparent; }
|
|
||||||
|
|
||||||
/* This temp element is used for auto adjusting filename field */
|
/* This temp element is used for auto adjusting filename field */
|
||||||
.tmp-element {
|
.tmp-element {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@ -877,13 +895,45 @@ button {
|
|||||||
padding: 2px;
|
padding: 2px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
color: #fff; }
|
color: #fff;
|
||||||
|
max-height: 50%; }
|
||||||
|
|
||||||
#script-editor-options-panel fieldset {
|
#script-editor-options-panel fieldset {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
font-size: 12px; }
|
font-size: 12px; }
|
||||||
|
#script-editor-options-panel fieldset input {
|
||||||
|
margin: 2px; }
|
||||||
|
|
||||||
|
/* Specific overrides for Ace Editor */
|
||||||
|
.ace_line,
|
||||||
|
.ace_line * {
|
||||||
|
background-color: transparent;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0; }
|
||||||
|
|
||||||
|
.ace_text-input {
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: transparent; }
|
||||||
|
|
||||||
|
/* Specified overrides for Code mirror Editor are defined in codemirror-override.scss */
|
||||||
|
|
||||||
|
/* COLORS */
|
||||||
|
/* Attributes */
|
||||||
|
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
||||||
|
terminal which has its own page) */
|
||||||
|
.generic-menupage-container {
|
||||||
|
height: 100%;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-left: 10%;
|
||||||
|
width: 99%;
|
||||||
|
overflow-y: scroll; }
|
||||||
|
|
||||||
|
/* Character Info */
|
||||||
|
#character-container {
|
||||||
|
padding-top: 10px;
|
||||||
|
position: fixed; }
|
||||||
|
|
||||||
/* Active scripts */
|
/* Active scripts */
|
||||||
.active-scripts-list {
|
.active-scripts-list {
|
||||||
@ -1222,7 +1272,26 @@ button {
|
|||||||
display: inline;
|
display: inline;
|
||||||
width: 25%; }
|
width: 25%; }
|
||||||
|
|
||||||
/* Stock market */
|
/* COLORS */
|
||||||
|
/* Attributes */
|
||||||
|
/**
|
||||||
|
* Styling for the Red Pill screen (the BitNode selection UI)
|
||||||
|
*/
|
||||||
|
#red-pill-container {
|
||||||
|
position: fixed; }
|
||||||
|
|
||||||
|
.bitnode {
|
||||||
|
color: #00f; }
|
||||||
|
|
||||||
|
.bitnode-destroyed {
|
||||||
|
color: #f00; }
|
||||||
|
|
||||||
|
.bitnode:hover,
|
||||||
|
.bitnode-destroyed:hover {
|
||||||
|
color: #fff; }
|
||||||
|
|
||||||
|
/* COLORS */
|
||||||
|
/* Attributes */
|
||||||
#stock-market-container {
|
#stock-market-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding: 6px; }
|
padding: 6px; }
|
||||||
@ -1235,13 +1304,12 @@ button {
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
display: block; }
|
display: block; }
|
||||||
|
|
||||||
/* Change font size of Stock TIcker headers */
|
|
||||||
#stock-market-list li button {
|
#stock-market-list li button {
|
||||||
font-size: 16px; }
|
font-size: 16px; }
|
||||||
|
|
||||||
#stock-market-container p {
|
#stock-market-container p {
|
||||||
padding: 10px;
|
padding: 6px;
|
||||||
margin: 10px;
|
margin: 6px;
|
||||||
width: 70%; }
|
width: 70%; }
|
||||||
|
|
||||||
#stock-market-container a {
|
#stock-market-container a {
|
||||||
@ -1318,20 +1386,9 @@ button {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer; }
|
cursor: pointer; }
|
||||||
|
|
||||||
#red-pill-container,
|
|
||||||
#cinematic-text-container {
|
#cinematic-text-container {
|
||||||
position: fixed; }
|
position: fixed; }
|
||||||
|
|
||||||
.bitnode {
|
|
||||||
color: #00f; }
|
|
||||||
|
|
||||||
.bitnode-destroyed {
|
|
||||||
color: #f00; }
|
|
||||||
|
|
||||||
.bitnode:hover,
|
|
||||||
.bitnode-destroyed:hover {
|
|
||||||
color: #fff; }
|
|
||||||
|
|
||||||
/* COLORS */
|
/* COLORS */
|
||||||
/* Attributes */
|
/* Attributes */
|
||||||
/* Pop-up boxes */
|
/* Pop-up boxes */
|
||||||
@ -1393,7 +1450,7 @@ button {
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 40%;
|
max-height: 50%;
|
||||||
top: 40%;
|
top: 40%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -10% 0 0 -25%;
|
margin: -10% 0 0 -25%;
|
||||||
@ -2047,12 +2104,11 @@ button {
|
|||||||
.bladeburner-nav-button, .bladeburner-nav-button-inactive {
|
.bladeburner-nav-button, .bladeburner-nav-button-inactive {
|
||||||
border: 1px solid #fff;
|
border: 1px solid #fff;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
padding: 2px; }
|
padding: 2px;
|
||||||
|
|
||||||
.bladeburner-nav-button {
|
|
||||||
color: #fff; }
|
color: #fff; }
|
||||||
.bladeburner-nav-button:hover {
|
|
||||||
background-color: #3d4044; }
|
.bladeburner-nav-button:hover {
|
||||||
|
background-color: #3d4044; }
|
||||||
|
|
||||||
.bladeburner-nav-button-inactive {
|
.bladeburner-nav-button-inactive {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@ -2136,6 +2192,51 @@ button {
|
|||||||
margin: 1px;
|
margin: 1px;
|
||||||
padding: 1px; }
|
padding: 1px; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for the Sleeves Management page
|
||||||
|
*/
|
||||||
|
/* COLORS */
|
||||||
|
/* Attributes */
|
||||||
|
.sleeve-container {
|
||||||
|
border: 1px solid white;
|
||||||
|
margin: 4px;
|
||||||
|
width: 75%; }
|
||||||
|
.sleeve-container p {
|
||||||
|
font-size: 14px; }
|
||||||
|
|
||||||
|
.sleeves-page-info {
|
||||||
|
display: "block";
|
||||||
|
width: 75%; }
|
||||||
|
|
||||||
|
.sleeve-panel {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 2px; }
|
||||||
|
.sleeve-panel select {
|
||||||
|
display: block; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for the Re-Sleeving Page
|
||||||
|
*/
|
||||||
|
/* COLORS */
|
||||||
|
/* Attributes */
|
||||||
|
.resleeve-container {
|
||||||
|
border: 1px solid white;
|
||||||
|
margin: 4px;
|
||||||
|
width: 75%; }
|
||||||
|
.resleeve-container p {
|
||||||
|
font-size: 13px; }
|
||||||
|
|
||||||
|
.resleeve-panel {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 2px; }
|
||||||
|
|
||||||
|
.resleeve-aug-selector {
|
||||||
|
font-size: 13px; }
|
||||||
|
.resleeve-aug-selector option {
|
||||||
|
font-size: 13px; }
|
||||||
|
|
||||||
/* required LIB STYLES */
|
/* required LIB STYLES */
|
||||||
/* .Treant se automatski dodaje na svaki chart conatiner */
|
/* .Treant se automatski dodaje na svaki chart conatiner */
|
||||||
.Treant {
|
.Treant {
|
||||||
|
219
dist/vendor.bundle.js
vendored
219
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
5527
dist/vendor.css
vendored
5527
dist/vendor.css
vendored
File diff suppressed because one or more lines are too long
14
doc/source/advancedgameplay.rst
Normal file
14
doc/source/advancedgameplay.rst
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Advanced Gameplay
|
||||||
|
=================
|
||||||
|
This section documents Bitburner gameplay elements that are **not** immediately
|
||||||
|
available and/or accessible to the player. These gameplay mechanics
|
||||||
|
must be unlocked.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 5
|
||||||
|
:caption: Elements:
|
||||||
|
|
||||||
|
BitNodes <advancedgameplay/bitnodes>
|
||||||
|
Source-Files <advancedgameplay/sourcefiles>
|
||||||
|
Intelligence <advancedgameplay/intelligence>
|
||||||
|
Sleeves <advancedgameplay/sleeves>
|
63
doc/source/advancedgameplay/bitnodes.rst
Normal file
63
doc/source/advancedgameplay/bitnodes.rst
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
.. _gameplay_bitnodes:
|
||||||
|
|
||||||
|
.. warning:: This page contains spoilers regarding the game's story/plot-line.
|
||||||
|
|
||||||
|
BitNodes
|
||||||
|
========
|
||||||
|
A BitNode is an important part of the game's storyline. In the game, you discover
|
||||||
|
what BitNodes are by following the trail of clues left by the mysterious jump3r
|
||||||
|
(essentially a minimal questline).
|
||||||
|
|
||||||
|
What is a BitNode
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
A BitNode is the complex simulated reality in which you reside. By following the messages
|
||||||
|
from jump3r, you discover that humanity was enslaved by an advanced alien race, called
|
||||||
|
the Enders, using virtual simulations that trapped the minds of humans.
|
||||||
|
|
||||||
|
However, the Enders didn't just create a single virtual reality to enslave humans, but many
|
||||||
|
different simulations. In other words, there are many different BitNodes that exist.
|
||||||
|
These BitNode are very different from each other.
|
||||||
|
|
||||||
|
jump3r tells you that the only hope for humanity is to destroy all of these BitNodes.
|
||||||
|
Therefore, the end goal for the player is to enter and then destroy each BitNode at least once.
|
||||||
|
|
||||||
|
Destroying a BitNode resets most of the player's progress but grants the player a
|
||||||
|
powerful second-tier persistent upgrade called a :ref:`Source-File <gameplay_sourcefiles>`.
|
||||||
|
Different BitNodes grant different Source-Files.
|
||||||
|
|
||||||
|
Each BitNode has unique characteristics that are related to varying backstories. For example,
|
||||||
|
in one BitNode the world is in the middle of a financial catastrophe with a collapsing
|
||||||
|
market. In this BitNode, most forms of income such as working at a company or Hacknet
|
||||||
|
Nodes are significantly less profitable. Servers have less money on them and lowered
|
||||||
|
growth rates, but it is easier to lower their security level using the weaken() Netscript function.
|
||||||
|
|
||||||
|
Furthermore, some BitNodes introduce new content and mechanics. For example there is one
|
||||||
|
BitNode that grants access to the :ref:`Netscript Singularity Functions <netscript_singularityfunctions>`.
|
||||||
|
There is another BitNode in which you can manage a gang to earn money and reputation.
|
||||||
|
|
||||||
|
How to destroy a BitNode
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Initially, the only way to destroy a BitNode is to join the Daedalus :ref:`Daedalus <gameplay_factions>`.
|
||||||
|
From Daedalus, the player can obtain an Augmentation called 'The Red Pill', which doesn't cost any money
|
||||||
|
but does require a good amount of faction reputation.
|
||||||
|
|
||||||
|
After installing 'The Red Pill', the player must search for and then manually hack a
|
||||||
|
server called 'w0r1d_d43m0n'. This server requires a hacking level of 3000 in order
|
||||||
|
to successfully hack it. This will destroy the player's current BitNode.
|
||||||
|
|
||||||
|
There is a second method of destroying a BitNode, but it must be unlocked by first
|
||||||
|
destroying BitNode-6 or BitNode-7 (Bladeburners).
|
||||||
|
|
||||||
|
.. todo:: Link to Bladeburner documentation page here
|
||||||
|
|
||||||
|
When the player destroys a BitNode, most of his/her progress will be reset. This includes things
|
||||||
|
such as Augmentations and RAM upgrades on the home computer. The only things that will persist
|
||||||
|
through destroying BitNodes is:
|
||||||
|
|
||||||
|
* Source-Files
|
||||||
|
* Scripts on the home computer
|
||||||
|
|
||||||
|
BitNode Details
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
TODO
|
21
doc/source/advancedgameplay/intelligence.rst
Normal file
21
doc/source/advancedgameplay/intelligence.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.. _gameplay_intelligence:
|
||||||
|
|
||||||
|
Intelligence
|
||||||
|
============
|
||||||
|
Intelligence is a :ref:`stat <gameplay_stats>` that is unlocked by having
|
||||||
|
:ref:`Source-File 5 <gameplay_sourcefiles>` (i.e. Destroying BitNode-5).
|
||||||
|
|
||||||
|
Intelligence is unique because it is permanent and persistent. It never gets reset
|
||||||
|
back to 1. However, gaining Intelligence experience is extremely slow. The methods
|
||||||
|
of gaining Intelligence exp is also hidden. You won't know when you gain
|
||||||
|
experience and how much. It is a stat that gradually builds up as you continue
|
||||||
|
to play the game.
|
||||||
|
|
||||||
|
Intelligence will boost your production for many actions in the game, including:
|
||||||
|
|
||||||
|
* Hacking
|
||||||
|
* Infiltration
|
||||||
|
* Hacking Missions
|
||||||
|
* Crime success rate
|
||||||
|
* Bladeburner
|
||||||
|
* Reputation gain for companies & factions
|
67
doc/source/advancedgameplay/sleeves.rst
Normal file
67
doc/source/advancedgameplay/sleeves.rst
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
.. _gameplay_sleeves:
|
||||||
|
|
||||||
|
Sleeves
|
||||||
|
=======
|
||||||
|
When VitaLife unveiled their Persona Core technology that allowed people to digitize
|
||||||
|
and transfer their consciousness into other vessels, human bodies became nothing more
|
||||||
|
than 'sleeves' for the human consciousness. This technology thus became known as
|
||||||
|
"Sleeve technology".
|
||||||
|
|
||||||
|
Sleeve technology unlocks two different gameplay features:
|
||||||
|
|
||||||
|
* Duplicate Sleeves
|
||||||
|
* Re-sleeving
|
||||||
|
|
||||||
|
Sleeve technology is unlocked in :ref:`BitNode-10 <gameplay_bitnodes>`.
|
||||||
|
|
||||||
|
Duplicate Sleeves
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciuosness
|
||||||
|
has been copied. In other words, these Synthoids contain a perfect duplicate of your mind.
|
||||||
|
|
||||||
|
Duplicate Sleeves are essentially clones which you can use to perform work-type actions,
|
||||||
|
such as working for a company/faction or committing a crime. When sleeves perform these tasks,
|
||||||
|
they will earn money, experience, and reputation.
|
||||||
|
|
||||||
|
Sleeves are their own individuals, which means they each have their own experience and stats.
|
||||||
|
|
||||||
|
When a sleeve earns experience, it earns experience for itself, the player's
|
||||||
|
original consciousness, as well as all of the player's other sleeves.
|
||||||
|
|
||||||
|
Synchronization
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
Synchronization is a measure of how aligned your consciousness is with that of your
|
||||||
|
Duplicate Sleeves. It is a numeral value between 1 and 100, and it affects how much experience
|
||||||
|
is earned when the sleeve is performing a task.
|
||||||
|
|
||||||
|
Let N be the sleeve's synchronization. When the sleeve earns experience by performing
|
||||||
|
a task, both the sleeve and the player's original host consciousness of N% of the
|
||||||
|
amount of experience normally earned by the task. All of the player's other sleeves
|
||||||
|
earn ((N/100)^2 * 100)% of the experience.
|
||||||
|
|
||||||
|
Synchronization can be increased by assigning sleeves to the 'Synchronize' task.
|
||||||
|
|
||||||
|
Sleeve Shock
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
Sleeve shock is a measure of how much trauma the sleeve has due to being placed in a new
|
||||||
|
body. It is a numeral value between 0 and 99, where 99 indicates full shock and 0 indicates
|
||||||
|
no shock. Shock affects the amount of experience earned by the sleeve.
|
||||||
|
|
||||||
|
Sleeve shock slowly decreases over time. You can further increase the rate at which
|
||||||
|
it decreases by assigning sleeves to the 'Shock Recovery' task.
|
||||||
|
|
||||||
|
Re-sleeving
|
||||||
|
^^^^^^^^^^^
|
||||||
|
Re-sleeving is the process of digitizing and transferring your consciousness into a
|
||||||
|
new human body, or "sleeve". When you re-sleeve into a new body, your stat experience
|
||||||
|
and Augmentations get replaced with those of the new body.
|
||||||
|
|
||||||
|
In order to re-sleeve, you must purchase new bodies. This can be done at VitaLife in
|
||||||
|
New Tokyo. Once you purchase a body to re-sleeve into, the effects will take
|
||||||
|
place immediately.
|
||||||
|
|
||||||
|
Note that resleeving **REMOVES** all of your currently-installed Augmentations,
|
||||||
|
and replaces them with the ones provided by the purchased sleeve. However,
|
||||||
|
Augmentations that are purchased but not installed will **not** be removed. If you have purchased
|
||||||
|
an Augmentation and then re-sleeve into a body which already has that Augmentation,
|
||||||
|
it will be removed since you cannot have duplicate Augmentations.
|
86
doc/source/advancedgameplay/sourcefiles.rst
Normal file
86
doc/source/advancedgameplay/sourcefiles.rst
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
.. _gameplay_sourcefiles:
|
||||||
|
|
||||||
|
.. warning:: This page contains spoilers regarding the game's story/plot-line.
|
||||||
|
|
||||||
|
Source-Files
|
||||||
|
============
|
||||||
|
Source-Files are a type of persistent upgrade that are more powerful than Augmentations.
|
||||||
|
Source-Files are received by destroying a BitNode. There are many different BitNodes
|
||||||
|
in the game and each BitNode will grant a different Source-File when it is destroyed.
|
||||||
|
|
||||||
|
A Source-File can be upgraded by destroying its corresponding BitNode a second or
|
||||||
|
third time (AKA playing through that BitNode again). It can be upgraded to a maximum
|
||||||
|
of level 3.
|
||||||
|
|
||||||
|
List of all Source-Files
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-1: Source Genesis | * Lets the player start with 32 GB of RAM on home computer |
|
||||||
|
| | * Increases all of the player's multipliers by 16%/24%/28% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-2: Rise of the Underworld | * Increases the player's crime success rate, crime money, and |
|
||||||
|
| | charisma multipliers by 24%/36%/42% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-3: Corporatocracy | * Lets the player create Corporations in other BitNodes (although some |
|
||||||
|
| | BitNodes will disable this mechanic) |
|
||||||
|
| | * Increases the player's charisma and company salary multipliers by 8%/12%/14% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-4: The Singularity | * Lets the player access and use Netscript Singularity Functions in other BitNodes. |
|
||||||
|
| | * Each level of this Source-File opens up more of the Singularity Functions to use |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-5: Artificial Intelligence | * Unlocks :ref:`gameplay_intelligence` |
|
||||||
|
| | * Unlocks getBitNodeMultipliers() Netscript function |
|
||||||
|
| | * Increases all of the player's hacking-related multipliers by 8%/12%/14% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-6: Bladeburners | * Unlocks the Bladeburner feature in other BitNodes |
|
||||||
|
| | * Increases all of the player's level and experience gain rate multipliers for |
|
||||||
|
| | combat stats by 8%/12%/14% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-7: Bladeburners 2079 | * Allows the player to access the :ref:`netscript_bladeburnerapi` in other BitNodes |
|
||||||
|
| | * Increases all of the player's Bladeburner multipliers by 8%/12%/14% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-8: Ghost of Wall Street | * Increases the player's hacking growth multiplier by 12%/18%/21% |
|
||||||
|
| | * Level 1 grants permanent access to :ref:`WSE <gameplay_stock_market>` and |
|
||||||
|
| | :ref:`TIX API <netscript_tixapi>` |
|
||||||
|
| | * Level 2 grants permanent access to shorting stocks |
|
||||||
|
| | * Level 3 grants permanent access to use limit/stop orders |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-9: Coming Soon | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-10: Digital Carbon | * Each level of this grants a Duplicate Sleeve |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-11: The Big Crash | * Company favor increases both the player's salary and reputation gain at that |
|
||||||
|
| | company by 1% per favor (rather than just the reputation gain) |
|
||||||
|
| | * Increases the player's company salary and reputation gain multipliers by |
|
||||||
|
| | 24%/36%/42% |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| BitNode-12: The Recursion | * There is no maximum level for this Source-File |
|
||||||
|
| | * Each level of this Source-File increases all of the player's multipliers by 1%. |
|
||||||
|
| | * This affect is multiplicative with itself. This means that level N of this |
|
||||||
|
| | Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers |
|
||||||
|
| | that decrease) |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Companies
|
Companies
|
||||||
=========
|
=========
|
||||||
When exploring the :ref:`world <World>`, you can visit various companies. At
|
When exploring the :ref:`world <gameplay_world>`, you can visit various companies. At
|
||||||
these companies, you can apply for jobs.
|
these companies, you can apply for jobs.
|
||||||
|
|
||||||
Working a job lets you earn money, experience, and reputation with that company.
|
Working a job lets you earn money, experience, and reputation with that company.
|
||||||
|
@ -4,7 +4,7 @@ Crimes
|
|||||||
======
|
======
|
||||||
Commiting crimes is an active gameplay mechanic that allows the player to train
|
Commiting crimes is an active gameplay mechanic that allows the player to train
|
||||||
their stats and potentially earn money. The player can attempt to commit crimes
|
their stats and potentially earn money. The player can attempt to commit crimes
|
||||||
by visiting 'The Slums' through the 'City' tab (:ref:`Keyboard shortcut <_shortcuts>` Alt + w).
|
by visiting 'The Slums' through the 'City' tab (:ref:`Keyboard shortcut <shortcuts>` Alt + w).
|
||||||
'The Slums' is available in every city.
|
'The Slums' is available in every city.
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ List of Factions and their Requirements
|
|||||||
| | Clarke | * Have 200k reputation with | |
|
| | Clarke | * Have 200k reputation with | |
|
||||||
| | Incorporated | the Corporation | |
|
| | Incorporated | the Corporation | |
|
||||||
+ +----------------+-----------------------------------------+-------------------------------+
|
+ +----------------+-----------------------------------------+-------------------------------+
|
||||||
| | Fulcrum Secret | * Have 200k reputation with | |
|
| | Fulcrum Secret | * Have 250k reputation with | |
|
||||||
| | Technologies | the Corporation | |
|
| | Technologies | the Corporation | |
|
||||||
| | | * Hack fulcrumassets manually | |
|
| | | * Hack fulcrumassets manually | |
|
||||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||||
|
@ -3,6 +3,30 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
v0.43.0 - 2/4/2019
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added BitNode-10: Digital Carbon
|
||||||
|
|
||||||
|
* Stock Market Changes:
|
||||||
|
* Each stock now has a maximum number of shares you can purchase (both Long and Short positions combined)
|
||||||
|
* Added getStockMaxShares() Netscript function to the TIX API
|
||||||
|
* The cost of 4S Market Data TIX API Access increased from $20b to $25b
|
||||||
|
|
||||||
|
* Job Changes:
|
||||||
|
* You can now hold multiple jobs at once. This means you no longer lose reputation when leaving a company
|
||||||
|
* Because of this change, the getCharacterInformation() Netscript function returns a slightly different value
|
||||||
|
|
||||||
|
* Script Editor Changes:
|
||||||
|
* Added new script editor: CodeMirror. You can choose between the old editor (Ace) or CodeMirror
|
||||||
|
* Navigation keyboard shortcuts no longer work if the script editor is focused
|
||||||
|
|
||||||
|
* Trying to programmatically run a script (run(), exec()) with a 'threads' argument of 0 will now cause the function to return false without running the script
|
||||||
|
* Home Computer RAM is now capped at 2 ^ 30 GB (1073741824 GB)
|
||||||
|
* The maximum amount, maximum RAM, and cost of purchasing servers can now vary between different BitNodes (new BitNode multipliers)
|
||||||
|
* Pop-up dialog boxes are a little bit bigger
|
||||||
|
* Bug Fix: When importing scripts, "./" will now be properly ignored (e.g. import { foo } from "./lib.script" )
|
||||||
|
|
||||||
v0.42.0 - 1/8/2019
|
v0.42.0 - 1/8/2019
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.0'
|
version = '0.43'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '1.0'
|
release = '0.43.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
@ -92,7 +92,11 @@ todo_include_todos = True
|
|||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#
|
#
|
||||||
html_theme = 'agogo'
|
#html_theme = 'agogo'
|
||||||
|
html_theme = "sphinx_rtd_theme"
|
||||||
|
html_theme_options = {
|
||||||
|
"navigation_depth": 5,
|
||||||
|
}
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
@ -178,7 +182,10 @@ texinfo_documents = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
print("Initializing (setup())");
|
||||||
|
app.add_stylesheet('maxwidthoverride.css')
|
||||||
|
@ -21,7 +21,9 @@ secrets that you've been searching for.
|
|||||||
|
|
||||||
Netscript <netscript>
|
Netscript <netscript>
|
||||||
Basic Gameplay <basicgameplay>
|
Basic Gameplay <basicgameplay>
|
||||||
|
Advanced Gameplay <advancedgameplay>
|
||||||
Keyboard Shortcuts <shortcuts>
|
Keyboard Shortcuts <shortcuts>
|
||||||
|
Script Editors <scripteditors>
|
||||||
Game Frozen or Stuck? <gamefrozen>
|
Game Frozen or Stuck? <gamefrozen>
|
||||||
Changelog <changelog>
|
Changelog <changelog>
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _netscript_bladeburnerapi:
|
||||||
|
|
||||||
Netscript Bladeburner API
|
Netscript Bladeburner API
|
||||||
=========================
|
=========================
|
||||||
Netscript provides the following API for interacting with the game's Bladeburner mechanic.
|
Netscript provides the following API for interacting with the game's Bladeburner mechanic.
|
||||||
|
@ -380,8 +380,10 @@ run
|
|||||||
Run a script as a separate process. This function can only be used to run scripts located on the current server (the server
|
Run a script as a separate process. This function can only be used to run scripts located on the current server (the server
|
||||||
running the script that calls this function).
|
running the script that calls this function).
|
||||||
|
|
||||||
Returns true if the script is successfully started, and false otherwise. Requires a significant amount of RAM to run this
|
Returns true if the script is successfully started, and false otherwise.
|
||||||
command.
|
|
||||||
|
Running this function with a *numThreads* argument of 0 will return false without running the script.
|
||||||
|
However, running this function with a negative *numThreads* argument will cause a runtime error.
|
||||||
|
|
||||||
The simplest way to use the *run* command is to call it with just the script name. The following example will run
|
The simplest way to use the *run* command is to call it with just the script name. The following example will run
|
||||||
'foo.script' single-threaded with no arguments::
|
'foo.script' single-threaded with no arguments::
|
||||||
@ -415,6 +417,9 @@ exec
|
|||||||
|
|
||||||
Returns true if the script is successfully started, and false otherwise.
|
Returns true if the script is successfully started, and false otherwise.
|
||||||
|
|
||||||
|
Running this function with a *numThreads* argument of 0 will return false without running the script.
|
||||||
|
However, running this function with a negative *numThreads* argument will cause a runtime error.
|
||||||
|
|
||||||
The simplest way to use the *exec* command is to call it with just the script name and the target server.
|
The simplest way to use the *exec* command is to call it with just the script name and the target server.
|
||||||
The following example will try to run *generic-hack.script* on the *foodnstuff* server::
|
The following example will try to run *generic-hack.script* on the *foodnstuff* server::
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
.. _netscript_tixapi:
|
||||||
|
|
||||||
Netscript Trade Information eXchange (TIX) API
|
Netscript Trade Information eXchange (TIX) API
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
The Trade Information eXchange (TIX) is the communications protocol supported by the World Stock Exchange (WSE).
|
The Trade Information eXchange (TIX) is the communications protocol supported by the World Stock Exchange (WSE).
|
||||||
The WSE provides an API that allows you to automatically communicate with the
|
The WSE provides an API that allows you to automatically communicate with the
|
||||||
`Stock Market <http://bitburner.wikia.com/wiki/Stock_Market>`_. This API lets you write code using Netscript
|
:ref:`Stock Market <gameplay_stock_market>`.
|
||||||
|
This API lets you write code using Netscript
|
||||||
to build automated trading systems and create your own algorithmic trading strategies. Access to this
|
to build automated trading systems and create your own algorithmic trading strategies. Access to this
|
||||||
TIX API can be purchased by visiting the World Stock Exchange in-game.
|
TIX API can be purchased by visiting the World Stock Exchange in-game.
|
||||||
|
|
||||||
@ -62,6 +65,19 @@ getStockPosition
|
|||||||
sharesShort = pos[2];
|
sharesShort = pos[2];
|
||||||
avgPxShort = pos[3];
|
avgPxShort = pos[3];
|
||||||
|
|
||||||
|
getStockMaxShares
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
|
||||||
|
.. js:function:: getStockMaxShares(sym)
|
||||||
|
|
||||||
|
:param string sym: Stock symbol
|
||||||
|
:RAM cost: 2 GB
|
||||||
|
|
||||||
|
Returns the maximum number of shares that the stock has. This is the maximum
|
||||||
|
amount of the stock that can be purchased in both the Long and Short
|
||||||
|
positions combined
|
||||||
|
|
||||||
buyStock
|
buyStock
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _netscript_singularityfunctions:
|
||||||
|
|
||||||
Netscript Singularity Functions
|
Netscript Singularity Functions
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
@ -164,9 +166,9 @@ getCharacterInformation
|
|||||||
{
|
{
|
||||||
bitnode: Current BitNode number
|
bitnode: Current BitNode number
|
||||||
city: Name of city you are currently in
|
city: Name of city you are currently in
|
||||||
company: Name of company
|
|
||||||
factions: Array of factions you are currently a member of
|
factions: Array of factions you are currently a member of
|
||||||
jobTitle: Name of job
|
jobs: Array of all companies at which you have jobs
|
||||||
|
jobTitle: Array of job positions for all companies you are employed at. Same order as 'jobs'
|
||||||
tor: Boolean indicating whether or not you have a tor router
|
tor: Boolean indicating whether or not you have a tor router
|
||||||
|
|
||||||
// The following is an object with many of the player's multipliers from Augmentations/Source Files
|
// The following is an object with many of the player's multipliers from Augmentations/Source Files
|
||||||
|
140
doc/source/scripteditors.rst
Normal file
140
doc/source/scripteditors.rst
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
.. _scripteditors:
|
||||||
|
|
||||||
|
Script Editors
|
||||||
|
==============
|
||||||
|
Third-party libraries are used to implement the game's Script Editor(s). There are
|
||||||
|
currently two options for the Script Editor:
|
||||||
|
|
||||||
|
* `Ace <https://ace.c9.io/>`_
|
||||||
|
* `CodeMirror <https://codemirror.net/>`_
|
||||||
|
|
||||||
|
You can select which of the two editors you want to use on the Script Editor page
|
||||||
|
('Create Script' on the main menu).
|
||||||
|
|
||||||
|
Ace was the game's original Script Editor, while CodeMirror was added later in
|
||||||
|
v0.43.0. The two editors share many of the same features, so there is not a significant
|
||||||
|
difference between the two. Currently, CodeMirror is slightly more modern,
|
||||||
|
more customizable, and has a few quality-of-life improvements compared to Ace.
|
||||||
|
|
||||||
|
Universal Key Bindings
|
||||||
|
----------------------
|
||||||
|
These keyboard shortcuts are available in both the Ace and CodeMirror editors, regardless
|
||||||
|
of what key binding option you are using:
|
||||||
|
|
||||||
|
============= ===========================================================================
|
||||||
|
Shortcut Action
|
||||||
|
============= ===========================================================================
|
||||||
|
Ctrl + b Save script and return to :ref:`terminal`
|
||||||
|
Ctrl + space Show Autocomplete Hints
|
||||||
|
============= ===========================================================================
|
||||||
|
|
||||||
|
.. _scripteditor_linter:
|
||||||
|
|
||||||
|
Linter
|
||||||
|
------
|
||||||
|
Both script editors contain a linter, which is a tool that analyzes your
|
||||||
|
code and flags anything it thinks might be an error. You can see
|
||||||
|
warnings and errors from the linter on the left-hand side of the script editor. There
|
||||||
|
will be an icon on whatever lines the linter thinks might be problematic. Hovering
|
||||||
|
over the icon will display information on what the issue is.
|
||||||
|
|
||||||
|
Note that **just because the linter shows an error/warning, this does NOT automatically mean that**
|
||||||
|
**your script is broken and will fail to run.** This is especially true if you are using
|
||||||
|
:ref:`netscriptjs`. The linter used by the script editors isn't necessarily perfect or
|
||||||
|
up-to-date. Furthermore, the linter does not affect anything when you actually run scripts.
|
||||||
|
|
||||||
|
Ace
|
||||||
|
---
|
||||||
|
The following documents what the different settings/options do for the Ace editor,
|
||||||
|
as well as the different key binding settings. Note that the
|
||||||
|
information for the key bindings may not be completely comprehensive. You'll
|
||||||
|
have to dig into the editor source code if you want to learn more.
|
||||||
|
|
||||||
|
Settings
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
===================== ===========================================================================================================
|
||||||
|
Setting Effect
|
||||||
|
===================== ===========================================================================================================
|
||||||
|
Theme Switch between different color schemes
|
||||||
|
Key Binding Switch between different key binding options. This changes what keyboard shortcuts are available
|
||||||
|
Highlight Active Line When enabled, the line on which the cursor currently resides will be highlighted.
|
||||||
|
Show Invisibles When enabled, you will be able to view hidden whitespace characters such as spaces, tabs, and newlines.
|
||||||
|
Use Soft Tab When enabled, tabs will be replaced with spaces
|
||||||
|
Max Error Count Specifies the (approximate) number of lines that will be linted
|
||||||
|
===================== ===========================================================================================================
|
||||||
|
|
||||||
|
Ace Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
For Ace, the "Ace" Key Binding setting uses the default configuration. A list of these
|
||||||
|
`can be found here <https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts>`_.
|
||||||
|
|
||||||
|
Vim Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
For Ace, the "Vim" Key Binding setting configures the editor to use
|
||||||
|
`Vim <https://en.wikipedia.org/wiki/Vim_(text_editor)>`_ key mappings. Note that while this tries
|
||||||
|
to emulate Vim features as faithfully as possible, it is not a complete Vim implementation.
|
||||||
|
|
||||||
|
Since I'm not familiar with Vim, I'll leave
|
||||||
|
`Ace's Vim Mode implementation here <https://github.com/ajaxorg/ace/blob/96088d0fc292daf0706b2d029cc03c3799be5974/lib/ace/keyboard/vim.js#L860>`_,
|
||||||
|
which I believe shows most of the implemented features.
|
||||||
|
|
||||||
|
Note that the following Vim Ex commands will properly save the script and/or quit the editor in game:
|
||||||
|
|
||||||
|
======= ==============================================
|
||||||
|
Command Effect
|
||||||
|
======= ==============================================
|
||||||
|
:w Save the script and return to :ref:`terminal`
|
||||||
|
:q Return to :ref:`terminal` **WITHOUT** saving
|
||||||
|
:x Save the script and return to :ref:`terminal`
|
||||||
|
:wq Save the script and return to :ref:`terminal`
|
||||||
|
======= ==============================================
|
||||||
|
|
||||||
|
Emacs Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
For Ace, the "Emacs" Key Binding setting configures the editor to use
|
||||||
|
`Emacs <https://en.wikipedia.org/wiki/Emacs>`_ key mappings. Note that while this tries
|
||||||
|
to emulate the Emacs key mappings as faithfully as possible, it won't necessarily be a
|
||||||
|
complete implementation.
|
||||||
|
|
||||||
|
Since I'm not familiar with Emacs, I'll leave
|
||||||
|
`Ace's Emacs Mode implementation here <https://github.com/ajaxorg/ace/blob/96088d0fc292daf0706b2d029cc03c3799be5974/lib/ace/keyboard/emacs.js#L343>`_,
|
||||||
|
which I believe shows most of the implemented features.
|
||||||
|
|
||||||
|
CodeMirror
|
||||||
|
----------
|
||||||
|
The following documents what the different settings/options do for the CodeMirror editor,
|
||||||
|
as well as the shortcuts for the different key binding settings. Note that the
|
||||||
|
information for the key bindings may not be completely comprehensive. You'll
|
||||||
|
have to dig into the editor source code if you want to learn everything.
|
||||||
|
|
||||||
|
Settings
|
||||||
|
~~~~~~~~
|
||||||
|
========================== ===========================================================================================================
|
||||||
|
Setting Effect
|
||||||
|
========================== ===========================================================================================================
|
||||||
|
Theme Switch between different color schemes
|
||||||
|
Key Binding Switch between different key binding options. This changes what keyboard shortcuts are available
|
||||||
|
Highlight Active Line When enabled, the line on which the cursor currently resides will be highlighted.
|
||||||
|
Show Invisibles When enabled, you will be able to view hidden whitespace characters such as spaces, tabs, and newlines.
|
||||||
|
Use Soft Tab When enabled, tabs will be replaced with spaces
|
||||||
|
Auto-Close Brackets/Quotes When enabled, any opening brackets or quotes that are typed will be closed
|
||||||
|
Enable Linting Enable/Disable the :ref:`scripteditor_linter`
|
||||||
|
Continue Comments When enabled, pressing 'Enter' inside a comment block will continue the comment on the next line
|
||||||
|
========================== ===========================================================================================================
|
||||||
|
|
||||||
|
Default Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
.. todo:: Fill out
|
||||||
|
|
||||||
|
Sublime Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
.. todo:: Fill out
|
||||||
|
|
||||||
|
Vim Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
.. todo:: Fill out
|
||||||
|
|
||||||
|
Emacs Key Bindings
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
.. todo:: Fill out
|
@ -18,7 +18,7 @@ These shortcuts are almost always available. Exceptions include:
|
|||||||
========== ===========================================================================
|
========== ===========================================================================
|
||||||
Shortcut Action
|
Shortcut Action
|
||||||
========== ===========================================================================
|
========== ===========================================================================
|
||||||
Alt + t Switch to :doc:`terminal`
|
Alt + t Switch to :ref:`terminal`
|
||||||
Alt + c Switch to 'Stats' page
|
Alt + c Switch to 'Stats' page
|
||||||
Alt + e Switch to Script Editor. Will open up the last-edited file or a new file
|
Alt + e Switch to Script Editor. Will open up the last-edited file or a new file
|
||||||
Alt + s Switch to 'Active Scripts' page
|
Alt + s Switch to 'Active Scripts' page
|
||||||
@ -35,24 +35,11 @@ Alt + o Switch to 'Options' page
|
|||||||
|
|
||||||
Script Editor
|
Script Editor
|
||||||
-------------
|
-------------
|
||||||
These shortcuts are available only in the Script Editor
|
See the :ref:`Script Editor <scripteditors>` documentation for more details.
|
||||||
|
|
||||||
============= ===========================================================================
|
|
||||||
Shortcut Action
|
|
||||||
============= ===========================================================================
|
|
||||||
Ctrl + b Save script and return to :doc:`terminal`
|
|
||||||
Ctrl + space Function autocompletion
|
|
||||||
============= ===========================================================================
|
|
||||||
|
|
||||||
In the Script Editor you can configure your key binding mode to three preset options:
|
|
||||||
|
|
||||||
* `Ace <https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts>`_
|
|
||||||
* Vim
|
|
||||||
* Emacs
|
|
||||||
|
|
||||||
Terminal Shortcuts
|
Terminal Shortcuts
|
||||||
------------------
|
------------------
|
||||||
These shortcuts are available only in the :doc:`terminal`
|
These shortcuts are available only in the :ref:`terminal`
|
||||||
|
|
||||||
============= ===========================================================================
|
============= ===========================================================================
|
||||||
Shortcut Action
|
Shortcut Action
|
||||||
@ -66,7 +53,7 @@ Tab Autocomplete command
|
|||||||
Terminal Bash Shortcuts
|
Terminal Bash Shortcuts
|
||||||
-----------------------
|
-----------------------
|
||||||
These shortcuts were implemented to better emulate a bash shell. They must be enabled
|
These shortcuts were implemented to better emulate a bash shell. They must be enabled
|
||||||
in your :doc:`terminal`'s *.fconf* file. This can be done be entering the Terminal command::
|
in your :ref:`terminal`'s *.fconf* file. This can be done be entering the Terminal command::
|
||||||
|
|
||||||
nano .fconf
|
nano .fconf
|
||||||
|
|
||||||
@ -92,10 +79,13 @@ Alt + f Move cursor to next word
|
|||||||
Ctrl + h/d Delete previous character ('Backspace')
|
Ctrl + h/d Delete previous character ('Backspace')
|
||||||
============= ===========================================================================
|
============= ===========================================================================
|
||||||
|
|
||||||
Misc Shortcuts
|
Popup/Dialog Box Shortcuts
|
||||||
--------------
|
--------------------------
|
||||||
|
The following shortcuts work if there are any popup or dialog boxes on the screen.
|
||||||
|
|
||||||
============= ===========================================================================
|
============= ===========================================================================
|
||||||
Shortcut Action
|
Shortcut Action
|
||||||
============= ===========================================================================
|
============= ===========================================================================
|
||||||
Esc Close a script's log window
|
Esc Close the current popup, cancelling any prompts on a dialog box
|
||||||
|
Enter Clicks the "Yes/Confirm" option for every dialog box
|
||||||
============= ===========================================================================
|
============= ===========================================================================
|
||||||
|
3
doc/source/ystatic/maxwidthoverride.css
Normal file
3
doc/source/ystatic/maxwidthoverride.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.wy-nav-content {
|
||||||
|
max-width: none;
|
||||||
|
}
|
BIN
favicon.ico
BIN
favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
49
index.html
49
index.html
@ -65,6 +65,9 @@
|
|||||||
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel">
|
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel">
|
||||||
<button id="hacknet-nodes-menu-link"> Hacknet Nodes </button>
|
<button id="hacknet-nodes-menu-link"> Hacknet Nodes </button>
|
||||||
</li>
|
</li>
|
||||||
|
<li id="sleeves-tab" class="mainmenu-accordion-panel">
|
||||||
|
<button id="sleeves-menu-link"> Sleeves </button>
|
||||||
|
</li>
|
||||||
|
|
||||||
<!-- World dropdown -->
|
<!-- World dropdown -->
|
||||||
<li id="world-menu-header-li">
|
<li id="world-menu-header-li">
|
||||||
@ -115,7 +118,11 @@
|
|||||||
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/>
|
<input id="script-editor-filename" type="text" maxlength="30" tabindex="1"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="javascript-editor"></div>
|
<div id="ace-editor"></div>
|
||||||
|
<form id="codemirror-form-wrapper"><textarea id="codemirror-editor"></textarea></form>
|
||||||
|
<div id="codemirror-vim-command-display-wrapper">
|
||||||
|
Key Buffer: <span id="codemirror-vim-command-display"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="script-editor-buttons-wrapper"></div> <!-- Buttons below script editor -->
|
<div id="script-editor-buttons-wrapper"></div> <!-- Buttons below script editor -->
|
||||||
</div> <!-- End wrapper -->
|
</div> <!-- End wrapper -->
|
||||||
@ -123,26 +130,21 @@
|
|||||||
<div id="script-editor-options-panel">
|
<div id="script-editor-options-panel">
|
||||||
<h1 style="color:white;"> Script Editor Options </h1>
|
<h1 style="color:white;"> Script Editor Options </h1>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="script-editor-option-theme">Theme</label>
|
<label for="script-editor-option-editor">Editor</label>
|
||||||
<select id="script-editor-option-theme">
|
<select id="script-editor-option-editor">
|
||||||
<option value="Chaos">Chaos</option>
|
<option value="Ace">Ace</option>
|
||||||
<option value="Chrome">Chrome</option>
|
<option value="CodeMirror">CodeMirror</option>
|
||||||
<option value="Monokai">Monokai</option>
|
|
||||||
<option value="Solarized_Dark">Solarized Dark</option>
|
|
||||||
<option value="Solarized_Light">Solarized Light</option>
|
|
||||||
<option value="Terminal">Terminal</option>
|
|
||||||
<option value="Twilight">Twilight</option>
|
|
||||||
<option value="XCode">XCode</option>
|
|
||||||
</select>
|
</select>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<label for="script-editor-option-theme">Theme</label>
|
||||||
|
<select id="script-editor-option-theme"></select>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="script-editor-option-keybinding">Key Binding</label>
|
<label for="script-editor-option-keybinding">Key Binding</label>
|
||||||
<select id="script-editor-option-keybinding">
|
<select id="script-editor-option-keybinding"></select>
|
||||||
<option value="ace">Ace</option>
|
|
||||||
<option value="vim">Vim</option>
|
|
||||||
<option value="emacs">Emacs</option>
|
|
||||||
</select>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@ -160,11 +162,11 @@
|
|||||||
<input type="checkbox" name="script-editor-option-usesofttab" id="script-editor-option-usesofttab" checked>
|
<input type="checkbox" name="script-editor-option-usesofttab" id="script-editor-option-usesofttab" checked>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset id="script-editor-option-flex1-fieldset"></fieldset>
|
||||||
<label for="script-editor-option-maxerr" class="tooltip">Max Error Count</label>
|
<fieldset id="script-editor-option-flex2-fieldset"></fieldset>
|
||||||
<input type="range" max="1000" min="50" value="200" step="1" name="script-editor-option-maxerr" id="script-editor-option-maxerr"/>
|
<fieldset id="script-editor-option-flex3-fieldset"></fieldset>
|
||||||
<em id="script-editor-option-maxerror-value-label" style="font-style: normal;"></em>
|
<fieldset id="script-editor-option-flex4-fieldset"></fieldset>
|
||||||
</fieldset>
|
|
||||||
</div> <!-- End script editor options panel -->
|
</div> <!-- End script editor options panel -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -594,8 +596,11 @@
|
|||||||
<!-- City Hall -->
|
<!-- City Hall -->
|
||||||
<a id="location-cityhall-create-corporation" class="a-link-button">Create a Corporation</a>
|
<a id="location-cityhall-create-corporation" class="a-link-button">Create a Corporation</a>
|
||||||
|
|
||||||
<!-- Bladeburner@NSA -->
|
<!-- Bladeburner @ NSA -->
|
||||||
<a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a>
|
<a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a>
|
||||||
|
|
||||||
|
<!-- Re-sleeving @ VitaLife -->
|
||||||
|
<a id="location-vitalife-resleeve" class="a-link-button">Re-Sleeve</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="infiltration-container" class="generic-menupage-container">
|
<div id="infiltration-container" class="generic-menupage-container">
|
||||||
|
1138
package-lock.json
generated
1138
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,7 @@
|
|||||||
"autosize": "^4.0.2",
|
"autosize": "^4.0.2",
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"brace": "^0.11.1",
|
"brace": "^0.11.1",
|
||||||
|
"codemirror": "^5.43.0",
|
||||||
"decimal.js": "7.2.3",
|
"decimal.js": "7.2.3",
|
||||||
"enhanced-resolve": "^4.0.0",
|
"enhanced-resolve": "^4.0.0",
|
||||||
"escodegen": "^1.11.0",
|
"escodegen": "^1.11.0",
|
||||||
@ -22,6 +23,7 @@
|
|||||||
"file-saver": "^1.3.8",
|
"file-saver": "^1.3.8",
|
||||||
"interpret": "^1.0.0",
|
"interpret": "^1.0.0",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
|
"jshint": "^2.9.7",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"jsplumb": "^2.6.8",
|
"jsplumb": "^2.6.8",
|
||||||
"jszip": "^3.1.5",
|
"jszip": "^3.1.5",
|
||||||
@ -58,10 +60,9 @@
|
|||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.10",
|
||||||
"mini-css-extract-plugin": "^0.4.1",
|
"mini-css-extract-plugin": "^0.4.1",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mocha": "^3.2.0",
|
"mocha": "^5.2.0",
|
||||||
"mocha-lcov-reporter": "^1.0.0",
|
"mocha-lcov-reporter": "^1.0.0",
|
||||||
"node-sass": "^4.9.2",
|
"node-sass": "^4.10.0",
|
||||||
"nsp": "^3.2.1",
|
|
||||||
"raw-loader": "~0.5.0",
|
"raw-loader": "~0.5.0",
|
||||||
"sass-loader": "^7.0.3",
|
"sass-loader": "^7.0.3",
|
||||||
"script-loader": "~0.7.0",
|
"script-loader": "~0.7.0",
|
||||||
|
156
src/Augmentation/Augmentation.ts
Normal file
156
src/Augmentation/Augmentation.ts
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// Class definition for a single Augmentation object
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
|
import { Faction } from "../Faction/Faction";
|
||||||
|
import { Factions } from "../Faction/Factions";
|
||||||
|
|
||||||
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||||
|
|
||||||
|
interface IConstructorParams {
|
||||||
|
info: string;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Augmentation {
|
||||||
|
// Initiatizes a Augmentation object from a JSON save state.
|
||||||
|
static fromJSON(value: any): Augmentation {
|
||||||
|
return Generic_fromJSON(Augmentation, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// How much money this costs to buy
|
||||||
|
baseCost: number = 0;
|
||||||
|
|
||||||
|
// How much faction reputation is required to unlock this
|
||||||
|
baseRepRequirement: number = 0;
|
||||||
|
|
||||||
|
// Description of what this Aug is and what it does
|
||||||
|
info: string = "";
|
||||||
|
|
||||||
|
// Augmentation level - for repeatable Augs like NeuroFlux Governor
|
||||||
|
level: number = 0;
|
||||||
|
|
||||||
|
// Name of Augmentation
|
||||||
|
name: string = "";
|
||||||
|
|
||||||
|
// Whether the player owns this Augmentation
|
||||||
|
owned: boolean = false;
|
||||||
|
|
||||||
|
// 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> = {}
|
||||||
|
|
||||||
|
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 * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||||
|
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
facObj!.augmentations.push(this.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the current object to a JSON save state.
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("Augmentation", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Augmentation = Augmentation;
|
File diff suppressed because it is too large
Load Diff
4
src/Augmentation/Augmentations.ts
Normal file
4
src/Augmentation/Augmentations.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Augmentation } from "./Augmentation";
|
||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
export let Augmentations: IMap<Augmentation> = {};
|
13
src/Augmentation/PlayerOwnedAugmentation.ts
Normal file
13
src/Augmentation/PlayerOwnedAugmentation.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export class PlayerOwnedAugmentation {
|
||||||
|
level: number = 1;
|
||||||
|
name: string = "";
|
||||||
|
|
||||||
|
constructor(name: string = "") {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPlayerOwnedAugmentation {
|
||||||
|
level: number;
|
||||||
|
name: string;
|
||||||
|
}
|
114
src/Augmentation/data/AugmentationNames.ts
Normal file
114
src/Augmentation/data/AugmentationNames.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import { IMap } from "../../types";
|
||||||
|
|
||||||
|
export let 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",
|
||||||
|
ADRPheromone1: "ADR-V1 Pheromone Gene",
|
||||||
|
ADRPheromone2: "ADR-V2 Pheromone Gene",
|
||||||
|
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",
|
||||||
|
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)",
|
||||||
|
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,
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import {BitNodeMultipliers} from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
||||||
import {Player} from "./Player";
|
import { Player } from "../Player";
|
||||||
|
|
||||||
function BitNode(n, name, desc="", info="") {
|
function BitNode(n, name, desc="", info="") {
|
||||||
this.number = n;
|
this.number = n;
|
||||||
@ -56,7 +56,6 @@ function initBitNodes() {
|
|||||||
"The price and reputation cost of all Augmentations is tripled<br>" +
|
"The price and reputation cost of all Augmentations is tripled<br>" +
|
||||||
"The starting and maximum amount of money on servers is reduced by 75%<br>" +
|
"The starting and maximum amount of money on servers is reduced by 75%<br>" +
|
||||||
"Server growth rate is reduced by 80%<br>" +
|
"Server growth rate is reduced by 80%<br>" +
|
||||||
"You will start out with $150b so that you can start your corporation<br>" +
|
|
||||||
"You now only need 75 favour with a faction in order to donate to it, rather than 150<br><br>" +
|
"You now only need 75 favour with a faction in order to donate to it, rather than 150<br><br>" +
|
||||||
"Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will " +
|
"Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will " +
|
||||||
"upgrade its level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although " +
|
"upgrade its level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although " +
|
||||||
@ -157,7 +156,22 @@ function initBitNodes() {
|
|||||||
"This Source-File also increases your hacking growth multipliers by: " +
|
"This Source-File also increases your hacking growth multipliers by: " +
|
||||||
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
||||||
BitNodes["BitNode9"] = new BitNode(9, "Do Androids Dream?", "COMING SOON");
|
BitNodes["BitNode9"] = new BitNode(9, "Do Androids Dream?", "COMING SOON");
|
||||||
BitNodes["BitNode10"] = new BitNode(10, "MegaCorp", "COMING SOON"); //Not sure yet
|
BitNodes["BitNode10"] = new BitNode(10, "Digital Carbon", "Your body is not who you are",
|
||||||
|
"In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people " +
|
||||||
|
"to digitize their consciousness. Their consciousness could then be transferred into Synthoids " +
|
||||||
|
"or other bodies by trasmitting the digitized data. Human bodies became nothing more than 'sleeves' for the " +
|
||||||
|
"human consciousness. Mankind had finally achieved immortality - at least for those that could afford it.<br><br>" +
|
||||||
|
"This BitNode unlocks Sleeve technology. Sleeve technology allows you to:<br><br>" +
|
||||||
|
"1. Re-sleeve: Purchase and transfer your consciousness into a new body<br>" +
|
||||||
|
"2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously<br><br>" +
|
||||||
|
"In this BitNode:<br><br>" +
|
||||||
|
"Your stats are significantly decreased.<br>" +
|
||||||
|
"All methods of gaining money are half as profitable (except Stock Market)<br>" +
|
||||||
|
"Purchased servers are more expensive, have less max RAM, and a lower maximum limit<br>" +
|
||||||
|
"Augmentations are 5x as expensive and require twice as much reputation<br><br>" +
|
||||||
|
"Destroying this BitNode will give you Source-File 10, or if you already have this Source-File it will " +
|
||||||
|
"upgrade its level up to a maximum of 3. This Source-File unlocks Sleeve technology in other BitNodes. " +
|
||||||
|
"Each level of this Source-File also grants you a Duplicate Sleeve");
|
||||||
BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
|
BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
|
||||||
"The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " +
|
"The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " +
|
||||||
"of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " +
|
"of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " +
|
||||||
@ -306,6 +320,27 @@ function initBitNodeMultipliers() {
|
|||||||
BitNodeMultipliers.CorporationValuation = 0;
|
BitNodeMultipliers.CorporationValuation = 0;
|
||||||
BitNodeMultipliers.CodingContractMoney = 0;
|
BitNodeMultipliers.CodingContractMoney = 0;
|
||||||
break;
|
break;
|
||||||
|
case 10: // Digital Carbon
|
||||||
|
BitNodeMultipliers.HackingLevelMultiplier = 0.2;
|
||||||
|
BitNodeMultipliers.StrengthLevelMultiplier = 0.4;
|
||||||
|
BitNodeMultipliers.DefenseLevelMultiplier = 0.4;
|
||||||
|
BitNodeMultipliers.DexterityLevelMultiplier = 0.4;
|
||||||
|
BitNodeMultipliers.AgilityLevelMultiplier = 0.4;
|
||||||
|
BitNodeMultipliers.CharismaLevelMultiplier = 0.4;
|
||||||
|
BitNodeMultipliers.CompanyWorkMoney = 0.5;
|
||||||
|
BitNodeMultipliers.CrimeMoney = 0.5;
|
||||||
|
BitNodeMultipliers.HacknetNodeMoney = 0.5;
|
||||||
|
BitNodeMultipliers.ManualHackMoney = 0.5;
|
||||||
|
BitNodeMultipliers.ScriptHackMoney = 0.5;
|
||||||
|
BitNodeMultipliers.CodingContractMoney = 0.5;
|
||||||
|
BitNodeMultipliers.InfiltrationMoney = 0.5;
|
||||||
|
BitNodeMultipliers.CorporationValuation = 0.5;
|
||||||
|
BitNodeMultipliers.AugmentationMoneyCost = 5;
|
||||||
|
BitNodeMultipliers.AugmentationRepCost = 2;
|
||||||
|
BitNodeMultipliers.PurchasedServerCost = 5;
|
||||||
|
BitNodeMultipliers.PurchasedServerLimit = 0.6;
|
||||||
|
BitNodeMultipliers.PurchasedServerMaxRam = 0.5;
|
||||||
|
break;
|
||||||
case 11: //The Big Crash
|
case 11: //The Big Crash
|
||||||
BitNodeMultipliers.ServerMaxMoney = 0.1;
|
BitNodeMultipliers.ServerMaxMoney = 0.1;
|
||||||
BitNodeMultipliers.ServerStartingMoney = 0.1;
|
BitNodeMultipliers.ServerStartingMoney = 0.1;
|
@ -4,6 +4,11 @@
|
|||||||
* player toward the intended strategy. Unless they really want to play the long, slow game of waiting...
|
* player toward the intended strategy. Unless they really want to play the long, slow game of waiting...
|
||||||
*/
|
*/
|
||||||
interface IBitNodeMultipliers {
|
interface IBitNodeMultipliers {
|
||||||
|
/**
|
||||||
|
* Influences how quickly the player's agility level (not exp) scales
|
||||||
|
*/
|
||||||
|
AgilityLevelMultiplier: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Influences the base cost to purchase an augmentation.
|
* Influences the base cost to purchase an augmentation.
|
||||||
*/
|
*/
|
||||||
@ -24,6 +29,11 @@ interface IBitNodeMultipliers {
|
|||||||
*/
|
*/
|
||||||
BladeburnerSkillCost: number;
|
BladeburnerSkillCost: 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.
|
* Influences the experience gained for each ability when a player completes a class.
|
||||||
*/
|
*/
|
||||||
@ -59,6 +69,16 @@ interface IBitNodeMultipliers {
|
|||||||
*/
|
*/
|
||||||
CrimeMoney: number;
|
CrimeMoney: 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 much rep the player gains in each faction simply by being a member.
|
* Influences how much rep the player gains in each faction simply by being a member.
|
||||||
*/
|
*/
|
||||||
@ -105,6 +125,20 @@ interface IBitNodeMultipliers {
|
|||||||
*/
|
*/
|
||||||
ManualHackMoney: number;
|
ManualHackMoney: 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 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.
|
* Influences the minimum favor the player must have with a faction before they can donate to gain rep.
|
||||||
*/
|
*/
|
||||||
@ -139,6 +173,11 @@ interface IBitNodeMultipliers {
|
|||||||
* Influences the weaken amount per invocation against a server.
|
* Influences the weaken amount per invocation against a server.
|
||||||
*/
|
*/
|
||||||
ServerWeakenRate: number;
|
ServerWeakenRate: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Influences how quickly the player's strength level (not exp) scales
|
||||||
|
*/
|
||||||
|
StrengthLevelMultiplier: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,6 +186,11 @@ interface IBitNodeMultipliers {
|
|||||||
// tslint:disable-next-line:variable-name
|
// tslint:disable-next-line:variable-name
|
||||||
export const BitNodeMultipliers: IBitNodeMultipliers = {
|
export const BitNodeMultipliers: IBitNodeMultipliers = {
|
||||||
HackingLevelMultiplier: 1,
|
HackingLevelMultiplier: 1,
|
||||||
|
StrengthLevelMultiplier: 1,
|
||||||
|
DefenseLevelMultiplier: 1,
|
||||||
|
DexterityLevelMultiplier: 1,
|
||||||
|
AgilityLevelMultiplier: 1,
|
||||||
|
CharismaLevelMultiplier: 1,
|
||||||
|
|
||||||
ServerGrowthRate: 1,
|
ServerGrowthRate: 1,
|
||||||
ServerMaxMoney: 1,
|
ServerMaxMoney: 1,
|
||||||
@ -154,6 +198,10 @@ export const BitNodeMultipliers: IBitNodeMultipliers = {
|
|||||||
ServerStartingSecurity: 1,
|
ServerStartingSecurity: 1,
|
||||||
ServerWeakenRate: 1,
|
ServerWeakenRate: 1,
|
||||||
|
|
||||||
|
PurchasedServerCost: 1,
|
||||||
|
PurchasedServerLimit: 1,
|
||||||
|
PurchasedServerMaxRam: 1,
|
||||||
|
|
||||||
CompanyWorkMoney: 1,
|
CompanyWorkMoney: 1,
|
||||||
CrimeMoney: 1,
|
CrimeMoney: 1,
|
||||||
HacknetNodeMoney: 1,
|
HacknetNodeMoney: 1,
|
1
src/BitNode/README.md
Normal file
1
src/BitNode/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Contains implementation of BitNodes and BitNode-specific mechanics
|
@ -1,5 +1,6 @@
|
|||||||
import { Augmentations , AugmentationNames } from "./Augmentations";
|
import { Augmentations } from "./Augmentation/Augmentations";
|
||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import { Engine } from "./engine";
|
import { Engine } from "./engine";
|
||||||
import { Faction } from "./Faction/Faction";
|
import { Faction } from "./Faction/Faction";
|
||||||
|
@ -84,7 +84,7 @@ function sanitizeRewardType(rewardType) {
|
|||||||
if (type === CodingContractRewardType.FactionReputationAll && factionsThatAllowHacking.length === 0) {
|
if (type === CodingContractRewardType.FactionReputationAll && factionsThatAllowHacking.length === 0) {
|
||||||
type = CodingContractRewardType.CompanyReputation;
|
type = CodingContractRewardType.CompanyReputation;
|
||||||
}
|
}
|
||||||
if (type === CodingContractRewardType.CompanyReputation && Player.companyName === "") {
|
if (type === CodingContractRewardType.CompanyReputation && Object.keys(Player.jobs).length === 0) {
|
||||||
type = CodingContractRewardType.Money;
|
type = CodingContractRewardType.Money;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,8 +115,9 @@ function getRandomReward() {
|
|||||||
reward.name = randFaction;
|
reward.name = randFaction;
|
||||||
break;
|
break;
|
||||||
case CodingContractRewardType.CompanyReputation:
|
case CodingContractRewardType.CompanyReputation:
|
||||||
if (Player.companyName !== "") {
|
const allJobs = Object.keys(Player.jobs);
|
||||||
reward.name = Player.companyName;
|
if (allJobs.length > 0) {
|
||||||
|
reward.name = allJobs[getRandomInt(0, allJobs.length - 1)];
|
||||||
} else {
|
} else {
|
||||||
reward.type = CodingContractRewardType.Money;
|
reward.type = CodingContractRewardType.Money;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
|
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
|
||||||
BaseCostFor1GBOfRamHacknetNode: 30000,
|
BaseCostFor1GBOfRamHacknetNode: 30000,
|
||||||
|
|
||||||
TravelCost: 200000,
|
TravelCost: 200e3,
|
||||||
|
|
||||||
BaseCostForHacknetNode: 1000,
|
BaseCostForHacknetNode: 1000,
|
||||||
BaseCostForHacknetNodeCore: 500000,
|
BaseCostForHacknetNodeCore: 500000,
|
||||||
@ -104,10 +104,11 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
NumNetscriptPorts: 20,
|
NumNetscriptPorts: 20,
|
||||||
|
|
||||||
//Server constants
|
//Server constants
|
||||||
ServerBaseGrowthRate: 1.03, //Unadjusted Growth rate
|
HomeComputerMaxRam: 1073741824, // 2 ^ 30
|
||||||
ServerMaxGrowthRate: 1.0035, //Maximum possible growth rate (max rate accounting for server security)
|
ServerBaseGrowthRate: 1.03, // Unadjusted Growth rate
|
||||||
ServerFortifyAmount: 0.002, //Amount by which server's security increases when its hacked/grown
|
ServerMaxGrowthRate: 1.0035, // Maximum possible growth rate (max rate accounting for server security)
|
||||||
ServerWeakenAmount: 0.05, //Amount by which server's security decreases when weakened
|
ServerFortifyAmount: 0.002, // Amount by which server's security increases when its hacked/grown
|
||||||
|
ServerWeakenAmount: 0.05, // Amount by which server's security decreases when weakened
|
||||||
|
|
||||||
PurchasedServerLimit: 25,
|
PurchasedServerLimit: 25,
|
||||||
PurchasedServerMaxRam: 1048576, //2^20
|
PurchasedServerMaxRam: 1048576, //2^20
|
||||||
@ -129,7 +130,7 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
WSEAccountCost: 200e6,
|
WSEAccountCost: 200e6,
|
||||||
TIXAPICost: 5e9,
|
TIXAPICost: 5e9,
|
||||||
MarketData4SCost: 1e9,
|
MarketData4SCost: 1e9,
|
||||||
MarketDataTixApi4SCost: 20e9,
|
MarketDataTixApi4SCost: 25e9,
|
||||||
StockMarketCommission: 100e3,
|
StockMarketCommission: 100e3,
|
||||||
|
|
||||||
//Hospital/Health
|
//Hospital/Health
|
||||||
@ -275,6 +276,9 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
CodingContractBaseCompanyRepGain: 4000,
|
CodingContractBaseCompanyRepGain: 4000,
|
||||||
CodingContractBaseMoneyGain: 50e6,
|
CodingContractBaseMoneyGain: 50e6,
|
||||||
|
|
||||||
|
// BitNode/Source-File related stuff
|
||||||
|
TotalNumBitNodes: 24,
|
||||||
|
|
||||||
/* Tutorial related things */
|
/* Tutorial related things */
|
||||||
TutorialNetworkingText: "Servers are a central part of the game. You start with a single personal server (your home computer) " +
|
TutorialNetworkingText: "Servers are a central part of the game. You start with a single personal server (your home computer) " +
|
||||||
"and you can purchase additional servers as you progress through the game. Connecting to other servers " +
|
"and you can purchase additional servers as you progress through the game. Connecting to other servers " +
|
||||||
@ -506,40 +510,27 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
|
|
||||||
LatestUpdate:
|
LatestUpdate:
|
||||||
`
|
`
|
||||||
v0.42.0
|
v0.43.0
|
||||||
* Corporation Changes:
|
* Added BitNode-10: Digital Carbon
|
||||||
** Corporation can now be self-funded with $150b or using seed money in exchange for 500m newly-issued shares
|
|
||||||
** In BitNode-3, you no longer start with $150b
|
|
||||||
** Changed initial market prices for many materials
|
|
||||||
** Changed the way a material's demand, competition, and market price change over time
|
|
||||||
** The sale price of materials can no longer be marked-up as high
|
|
||||||
** Added a Research Tree mechanic. Spend Scientific Research on permanent upgrades for each industry
|
|
||||||
** You can now redistribute earnings to shareholders (including yourself) as dividends
|
|
||||||
** Cost of "Smart Supply" upgraded reduced from $50b to $25b
|
|
||||||
** Now has offline progress, which works similarly to the Gang/Bladeburner mechanics
|
|
||||||
** Slightly reduced the amount of money offered to you by investment firms
|
|
||||||
** Employee salaries now slowly increase over time
|
|
||||||
** Slightly reduced the effect "Real Estate" has on the Production Multiplier for the Agriculture industry
|
|
||||||
** Changed the way your Corporation's value is calculated (this is what determines stock price)
|
|
||||||
** After taking your corporation public, it is now possible to issue new shares to raise capital
|
|
||||||
** Issuing new shares can only be done once every 12 hours
|
|
||||||
** Buying back shares must now be done at a premium
|
|
||||||
** Selling shares can now only be done once per hour
|
|
||||||
** Selling large amounts of shares now immediately impacts stock price (during the transaction)
|
|
||||||
** Reduced the initial cost of the DreamSense upgrade from $8b to $4b, but increased its price multiplier
|
|
||||||
** Reduced the price multiplier for ABC SalesBots upgrade
|
|
||||||
|
|
||||||
* Added getOrders() Netscript function to the TIX API
|
* Stock Market Changes:
|
||||||
* Added getAugmentationPrereq() Singularity function (by havocmayhem)
|
** Each stock now has a maximum number of shares you can purchase (both Long and Short positions combined)
|
||||||
* Added hackAnalyzePercent() and hackAnalyzeThreads() Netscript functions
|
** Added getStockMaxShares() Netscript function to the TIX API
|
||||||
* Stock Market, Travel, and Corporation main menu links are now properly styled
|
** The cost of 4S Market Data TIX API Access increased from $20b to $25b
|
||||||
* Many pop-up/dialog boxes now support the 'Enter' and 'Esc' hotkeys. If you find a pop-up/dialog box that doesnt support this, let me know specifically which one ('Enter' for the default option, 'Esc' for cancelling and closing the pop-up box)
|
|
||||||
* Added "brace_style = preserve_inline" configuration to Script Editor Beautifier
|
* Job Changes:
|
||||||
* ServerProfiler.exe can now be purchased from the Dark Web
|
** You can now hold multiple jobs at once. This means you no longer lose reputation when leaving a company
|
||||||
* Added an option to copy save data to clipboard
|
** Because of this change, the getCharacterInformation() Netscript function returns a slightly different value
|
||||||
* Added total multiplier information on the "Augmentations" page
|
|
||||||
* Bug Fix: gymWorkout() Singularity function should now work properly with Millenium Fitness Gym
|
* Script Editor Changes:
|
||||||
* Began migrating gameplay information to the ReadTheDocs documentation
|
** Added new script editor: CodeMirror. You can choose between the old editor (Ace) or CodeMirror
|
||||||
`
|
** Navigation keyboard shortcuts no longer work if the script editor is focused
|
||||||
|
|
||||||
|
* Trying to programmatically run a script (run(), exec()) with a 'threads' argument of 0 will now cause the function to return false without running the script
|
||||||
|
* Home Computer RAM is now capped at 2 ^ 30 GB (1073741824 GB)
|
||||||
|
* The maximum amount, maximum RAM, and cost of purchasing servers can now vary between different BitNodes (new BitNode multipliers)
|
||||||
|
* Pop-up dialog boxes are a little bit bigger
|
||||||
|
* Bug Fix: When importing scripts, "./" will now be properly ignored (e.g. import { foo } from "./lib.script" )
|
||||||
|
`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import { MaterialSizes } from "./MaterialSizes";
|
|||||||
import { Product } from "./Product";
|
import { Product } from "./Product";
|
||||||
import { ResearchMap } from "./ResearchMap";
|
import { ResearchMap } from "./ResearchMap";
|
||||||
|
|
||||||
import { BitNodeMultipliers } from "../BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
import { Factions } from "../Faction/Factions";
|
import { Factions } from "../Faction/Factions";
|
||||||
import { showLiterature } from "../Literature";
|
import { showLiterature } from "../Literature";
|
||||||
|
147
src/Crime/Crime.ts
Normal file
147
src/Crime/Crime.ts
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
export interface IConstructorParams {
|
||||||
|
hacking_success_weight?: number;
|
||||||
|
strength_success_weight?: number;
|
||||||
|
defense_success_weight?: number;
|
||||||
|
dexterity_success_weight?: number;
|
||||||
|
agility_success_weight?: number;
|
||||||
|
charisma_success_weight?: number;
|
||||||
|
hacking_exp?: number;
|
||||||
|
strength_exp?: number;
|
||||||
|
defense_exp?: number;
|
||||||
|
dexterity_exp?: number;
|
||||||
|
agility_exp?: number;
|
||||||
|
charisma_exp?: number;
|
||||||
|
intelligence_exp?: number;
|
||||||
|
|
||||||
|
kills?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IPlayer {
|
||||||
|
startCrime(crimeType: string,
|
||||||
|
hackExp: number,
|
||||||
|
strExp: number,
|
||||||
|
defExp: number,
|
||||||
|
dexExp: number,
|
||||||
|
agiExp: number,
|
||||||
|
chaExp: number,
|
||||||
|
money: number,
|
||||||
|
time: number,
|
||||||
|
singParams: any): void;
|
||||||
|
|
||||||
|
hacking_skill: number;
|
||||||
|
strength: number;
|
||||||
|
defense: number;
|
||||||
|
dexterity: number;
|
||||||
|
agility: number;
|
||||||
|
charisma: number;
|
||||||
|
intelligence: number;
|
||||||
|
|
||||||
|
crime_success_mult: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Crime {
|
||||||
|
// Number representing the difficulty of the crime. Used for success chance calculations
|
||||||
|
difficulty: number = 0;
|
||||||
|
|
||||||
|
// Amount of karma lost for SUCCESSFULLY committing this crime
|
||||||
|
karma: number = 0;
|
||||||
|
|
||||||
|
// How many people die as a result of this crime
|
||||||
|
kills: number = 0;
|
||||||
|
|
||||||
|
// How much money is given by the
|
||||||
|
money: number = 0;
|
||||||
|
|
||||||
|
// Name of crime
|
||||||
|
name: string = "";
|
||||||
|
|
||||||
|
// Milliseconds it takes to attempt the crime
|
||||||
|
time: number = 0;
|
||||||
|
|
||||||
|
// Corresponding type in CONSTANTS. Contains a description for the crime activity
|
||||||
|
type: string = "";
|
||||||
|
|
||||||
|
// Weighting factors that determine how stats affect the success rate of this crime
|
||||||
|
hacking_success_weight: number = 0;
|
||||||
|
strength_success_weight: number = 0;
|
||||||
|
defense_success_weight: number = 0;
|
||||||
|
dexterity_success_weight: number = 0;
|
||||||
|
agility_success_weight: number = 0;
|
||||||
|
charisma_success_weight: number = 0;
|
||||||
|
|
||||||
|
// How much stat experience is granted by this crime
|
||||||
|
hacking_exp: number = 0;
|
||||||
|
strength_exp: number = 0;
|
||||||
|
defense_exp: number = 0;
|
||||||
|
dexterity_exp: number = 0;
|
||||||
|
agility_exp: number = 0;
|
||||||
|
charisma_exp: number = 0;
|
||||||
|
intelligence_exp: number = 0;
|
||||||
|
|
||||||
|
constructor(name: string = "",
|
||||||
|
type: string = "",
|
||||||
|
time: number = 0,
|
||||||
|
money: number = 0,
|
||||||
|
difficulty: number = 0,
|
||||||
|
karma: number = 0,
|
||||||
|
params: IConstructorParams={}) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.time = time;
|
||||||
|
this.money = money;
|
||||||
|
this.difficulty = difficulty;
|
||||||
|
this.karma = karma;
|
||||||
|
|
||||||
|
this.hacking_success_weight = params.hacking_success_weight ? params.hacking_success_weight : 0;
|
||||||
|
this.strength_success_weight = params.strength_success_weight ? params.strength_success_weight : 0;
|
||||||
|
this.defense_success_weight = params.defense_success_weight ? params.defense_success_weight : 0;
|
||||||
|
this.dexterity_success_weight = params.dexterity_success_weight ? params.dexterity_success_weight : 0;
|
||||||
|
this.agility_success_weight = params.agility_success_weight ? params.agility_success_weight : 0;
|
||||||
|
this.charisma_success_weight = params.charisma_success_weight ? params.charisma_success_weight : 0;
|
||||||
|
|
||||||
|
this.hacking_exp = params.hacking_exp ? params.hacking_exp : 0;
|
||||||
|
this.strength_exp = params.strength_exp ? params.strength_exp : 0;
|
||||||
|
this.defense_exp = params.defense_exp ? params.defense_exp : 0;
|
||||||
|
this.dexterity_exp = params.dexterity_exp ? params.dexterity_exp : 0;
|
||||||
|
this.agility_exp = params.agility_exp ? params.agility_exp : 0;
|
||||||
|
this.charisma_exp = params.charisma_exp ? params.charisma_exp : 0;
|
||||||
|
this.intelligence_exp = params.intelligence_exp ? params.intelligence_exp : 0;
|
||||||
|
|
||||||
|
this.kills = params.kills ? params.kills : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
commit(p: IPlayer, div: number=1, singParams: any=null): number {
|
||||||
|
if (div <= 0) { div = 1; }
|
||||||
|
p.startCrime(
|
||||||
|
this.type,
|
||||||
|
this.hacking_exp/div,
|
||||||
|
this.strength_exp/div,
|
||||||
|
this.defense_exp/div,
|
||||||
|
this.dexterity_exp/div,
|
||||||
|
this.agility_exp/div,
|
||||||
|
this.charisma_exp/div,
|
||||||
|
this.money/div,
|
||||||
|
this.time,
|
||||||
|
singParams
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
successRate(p: IPlayer): number {
|
||||||
|
let chance: number = (this.hacking_success_weight * p.hacking_skill +
|
||||||
|
this.strength_success_weight * p.strength +
|
||||||
|
this.defense_success_weight * p.defense +
|
||||||
|
this.dexterity_success_weight * p.dexterity +
|
||||||
|
this.agility_success_weight * p.agility +
|
||||||
|
this.charisma_success_weight * p.charisma +
|
||||||
|
CONSTANTS.IntelligenceCrimeWeight * p.intelligence);
|
||||||
|
chance /= CONSTANTS.MaxSkillLevel;
|
||||||
|
chance /= this.difficulty;
|
||||||
|
chance *= p.crime_success_mult;
|
||||||
|
|
||||||
|
return Math.min(chance, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
63
src/Crime/CrimeHelpers.js
Normal file
63
src/Crime/CrimeHelpers.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { Crimes } from "./Crimes";
|
||||||
|
|
||||||
|
import { Player } from "../Player";
|
||||||
|
|
||||||
|
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||||
|
|
||||||
|
export function determineCrimeSuccess(type, moneyGained) {
|
||||||
|
var chance = 0;
|
||||||
|
var found = false;
|
||||||
|
for(const i in Crimes) {
|
||||||
|
const crime = Crimes[i];
|
||||||
|
if(crime.type == type) {
|
||||||
|
chance = crime.successRate(Player);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
console.log(crime);
|
||||||
|
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.random() <= chance) {
|
||||||
|
//Success
|
||||||
|
Player.gainMoney(moneyGained);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
//Failure
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findCrime(roughName) {
|
||||||
|
if (roughName.includes("shoplift")) {
|
||||||
|
return Crimes.Shoplift;
|
||||||
|
} else if (roughName.includes("rob") && roughName.includes("store")) {
|
||||||
|
return Crimes.RobStore;
|
||||||
|
} else if (roughName.includes("mug")) {
|
||||||
|
return Crimes.Mug;
|
||||||
|
} else if (roughName.includes("larceny")) {
|
||||||
|
return Crimes.Larceny;
|
||||||
|
} else if (roughName.includes("drugs")) {
|
||||||
|
return Crimes.DealDrugs;
|
||||||
|
} else if (roughName.includes("bond") && roughName.includes("forge")) {
|
||||||
|
return Crimes.BondForgery;
|
||||||
|
} else if (roughName.includes("traffick") && roughName.includes("arms")) {
|
||||||
|
return Crimes.TraffickArms;
|
||||||
|
} else if (roughName.includes("homicide")) {
|
||||||
|
return Crimes.Homicide;
|
||||||
|
} else if (roughName.includes("grand") && roughName.includes("auto")) {
|
||||||
|
return Crimes.GrandTheftAuto;
|
||||||
|
} else if (roughName.includes("kidnap")) {
|
||||||
|
return Crimes.Kidnap;
|
||||||
|
} else if (roughName.includes("assassinate")) {
|
||||||
|
return Crimes.Assassination;
|
||||||
|
} else if (roughName.includes("heist")) {
|
||||||
|
return Crimes.Heist;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
163
src/Crime/Crimes.ts
Normal file
163
src/Crime/Crimes.ts
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import { Crime } from "./Crime";
|
||||||
|
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
export const Crimes: IMap<Crime> = {
|
||||||
|
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1/20, 0.1, {
|
||||||
|
dexterity_success_weight: 1,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
|
||||||
|
dexterity_exp: 2,
|
||||||
|
agility_exp: 2,
|
||||||
|
}),
|
||||||
|
|
||||||
|
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1/5, 0.5, {
|
||||||
|
hacking_exp: 30,
|
||||||
|
dexterity_exp: 45,
|
||||||
|
agility_exp: 45,
|
||||||
|
|
||||||
|
hacking_success_weight: 0.5 ,
|
||||||
|
dexterity_success_weight: 2,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
|
||||||
|
intelligence_exp: 0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
}),
|
||||||
|
|
||||||
|
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1/5, 0.25, {
|
||||||
|
strength_exp: 3,
|
||||||
|
defense_exp: 3,
|
||||||
|
dexterity_exp: 3,
|
||||||
|
agility_exp: 3,
|
||||||
|
|
||||||
|
strength_success_weight: 1.5,
|
||||||
|
defense_success_weight: 0.5,
|
||||||
|
dexterity_success_weight: 1.5,
|
||||||
|
agility_success_weight: 0.5,
|
||||||
|
}),
|
||||||
|
|
||||||
|
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1/3, 1.5, {
|
||||||
|
hacking_exp: 45,
|
||||||
|
dexterity_exp: 60,
|
||||||
|
agility_exp: 60,
|
||||||
|
|
||||||
|
hacking_success_weight: 0.5,
|
||||||
|
dexterity_success_weight: 1,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
|
||||||
|
intelligence_exp: 0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
}),
|
||||||
|
|
||||||
|
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
|
||||||
|
dexterity_exp: 5,
|
||||||
|
agility_exp: 5,
|
||||||
|
charisma_exp: 10,
|
||||||
|
|
||||||
|
charisma_success_weight: 3,
|
||||||
|
dexterity_success_weight: 2,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
}),
|
||||||
|
|
||||||
|
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1/2, 0.1, {
|
||||||
|
hacking_exp: 100,
|
||||||
|
dexterity_exp: 150,
|
||||||
|
charisma_exp: 15,
|
||||||
|
|
||||||
|
hacking_success_weight: 0.05,
|
||||||
|
dexterity_success_weight: 1.25,
|
||||||
|
|
||||||
|
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
}),
|
||||||
|
|
||||||
|
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
|
||||||
|
strength_exp: 20,
|
||||||
|
defense_exp: 20,
|
||||||
|
dexterity_exp: 20,
|
||||||
|
agility_exp: 20,
|
||||||
|
charisma_exp: 40,
|
||||||
|
|
||||||
|
charisma_success_weight: 1,
|
||||||
|
strength_success_weight: 1,
|
||||||
|
defense_success_weight: 1,
|
||||||
|
dexterity_success_weight: 1,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
}),
|
||||||
|
|
||||||
|
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
|
||||||
|
strength_exp: 2,
|
||||||
|
defense_exp: 2,
|
||||||
|
dexterity_exp: 2,
|
||||||
|
agility_exp: 2,
|
||||||
|
|
||||||
|
strength_success_weight: 2,
|
||||||
|
defense_success_weight: 2,
|
||||||
|
dexterity_success_weight: 0.5,
|
||||||
|
agility_success_weight: 0.5,
|
||||||
|
|
||||||
|
kills: 1,
|
||||||
|
}),
|
||||||
|
|
||||||
|
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
|
||||||
|
strength_exp: 20,
|
||||||
|
defense_exp: 20,
|
||||||
|
dexterity_exp: 20,
|
||||||
|
agility_exp: 80,
|
||||||
|
charisma_exp: 40,
|
||||||
|
|
||||||
|
hacking_success_weight: 1,
|
||||||
|
strength_success_weight: 1,
|
||||||
|
dexterity_success_weight: 4,
|
||||||
|
agility_success_weight: 2,
|
||||||
|
charisma_success_weight: 2,
|
||||||
|
|
||||||
|
intelligence_exp: CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
}),
|
||||||
|
|
||||||
|
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
|
||||||
|
strength_exp: 80,
|
||||||
|
defense_exp: 80,
|
||||||
|
dexterity_exp: 80,
|
||||||
|
agility_exp: 80,
|
||||||
|
charisma_exp: 80,
|
||||||
|
|
||||||
|
charisma_success_weight: 1,
|
||||||
|
strength_success_weight: 1,
|
||||||
|
dexterity_success_weight: 1,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
|
||||||
|
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
}),
|
||||||
|
|
||||||
|
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
|
||||||
|
strength_exp: 300,
|
||||||
|
defense_exp: 300,
|
||||||
|
dexterity_exp: 300,
|
||||||
|
agility_exp: 300,
|
||||||
|
|
||||||
|
strength_success_weight: 1,
|
||||||
|
dexterity_success_weight: 2,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
|
||||||
|
intelligence_exp: 5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
|
||||||
|
kills: 1,
|
||||||
|
}),
|
||||||
|
|
||||||
|
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
|
||||||
|
hacking_exp: 450,
|
||||||
|
strength_exp: 450,
|
||||||
|
defense_exp: 450,
|
||||||
|
dexterity_exp: 450,
|
||||||
|
agility_exp: 450,
|
||||||
|
charisma_exp: 450,
|
||||||
|
|
||||||
|
hacking_success_weight: 1,
|
||||||
|
strength_success_weight: 1,
|
||||||
|
defense_success_weight: 1,
|
||||||
|
dexterity_success_weight: 1,
|
||||||
|
agility_success_weight: 1,
|
||||||
|
charisma_success_weight: 1,
|
||||||
|
|
||||||
|
intelligence_exp: 10 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
||||||
|
}),
|
||||||
|
};
|
275
src/Crimes.js
275
src/Crimes.js
@ -1,275 +0,0 @@
|
|||||||
import {CONSTANTS} from "./Constants";
|
|
||||||
import {Player} from "./Player";
|
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
|
||||||
|
|
||||||
|
|
||||||
function Crime(name, type, time, money, difficulty, karma, params) {
|
|
||||||
this.name = name;
|
|
||||||
this.type = type;
|
|
||||||
this.time = time;
|
|
||||||
this.money = money;
|
|
||||||
this.difficulty = difficulty;
|
|
||||||
this.karma = karma;
|
|
||||||
|
|
||||||
this.hacking_success_weight = params.hacking_success_weight ? params.hacking_success_weight : 0;
|
|
||||||
this.strength_success_weight = params.strength_success_weight ? params.strength_success_weight : 0;
|
|
||||||
this.defense_success_weight = params.defense_success_weight ? params.defense_success_weight : 0;
|
|
||||||
this.dexterity_success_weight = params.dexterity_success_weight ? params.dexterity_success_weight : 0;
|
|
||||||
this.agility_success_weight = params.agility_success_weight ? params.agility_success_weight : 0;
|
|
||||||
this.charisma_success_weight = params.charisma_success_weight ? params.charisma_success_weight : 0;
|
|
||||||
|
|
||||||
this.hacking_exp = params.hacking_exp ? params.hacking_exp : 0;
|
|
||||||
this.strength_exp = params.strength_exp ? params.strength_exp : 0;
|
|
||||||
this.defense_exp = params.defense_exp ? params.defense_exp : 0;
|
|
||||||
this.dexterity_exp = params.dexterity_exp ? params.dexterity_exp : 0;
|
|
||||||
this.agility_exp = params.agility_exp ? params.agility_exp : 0;
|
|
||||||
this.charisma_exp = params.charisma_exp ? params.charisma_exp : 0;
|
|
||||||
this.intelligence_exp = params.intelligence_exp ? params.intelligence_exp : 0;
|
|
||||||
|
|
||||||
this.kills = params.kills ? params.kills : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Crime.prototype.commit = function(div=1, singParams=null) {
|
|
||||||
if (div <= 0) {div = 1;}
|
|
||||||
Player.crimeType = this.type;
|
|
||||||
Player.startCrime(
|
|
||||||
this.hacking_exp/div,
|
|
||||||
this.strength_exp/div,
|
|
||||||
this.defense_exp/div,
|
|
||||||
this.dexterity_exp/div,
|
|
||||||
this.agility_exp/div,
|
|
||||||
this.charisma_exp/div,
|
|
||||||
this.money/div, this.time, singParams);
|
|
||||||
return this.time;
|
|
||||||
}
|
|
||||||
|
|
||||||
Crime.prototype.successRate = function() {
|
|
||||||
var chance = (this.hacking_success_weight * Player.hacking_skill +
|
|
||||||
this.strength_success_weight * Player.strength +
|
|
||||||
this.defense_success_weight * Player.defense +
|
|
||||||
this.dexterity_success_weight * Player.dexterity +
|
|
||||||
this.agility_success_weight * Player.agility +
|
|
||||||
this.charisma_success_weight * Player.charisma +
|
|
||||||
CONSTANTS.IntelligenceCrimeWeight * Player.intelligence);
|
|
||||||
chance /= CONSTANTS.MaxSkillLevel;
|
|
||||||
chance /= this.difficulty;
|
|
||||||
chance *= Player.crime_success_mult;
|
|
||||||
return Math.min(chance, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Crimes = {
|
|
||||||
Shoplift: new Crime("Shoplift", CONSTANTS.CrimeShoplift, 2e3, 15e3, 1/20, 0.1, {
|
|
||||||
dexterity_success_weight: 1,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
|
|
||||||
dexterity_exp: 2,
|
|
||||||
agility_exp: 2,
|
|
||||||
}),
|
|
||||||
|
|
||||||
RobStore: new Crime("Rob Store", CONSTANTS.CrimeRobStore, 60e3, 400e3, 1/5, 0.5, {
|
|
||||||
hacking_exp: 30,
|
|
||||||
dexterity_exp: 45,
|
|
||||||
agility_exp: 45,
|
|
||||||
|
|
||||||
hacking_success_weight: 0.5 ,
|
|
||||||
dexterity_success_weight: 2,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
|
|
||||||
intelligence_exp: 0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Mug: new Crime("Mug", CONSTANTS.CrimeMug, 4e3, 36e3, 1/5, 0.25, {
|
|
||||||
strength_exp: 3,
|
|
||||||
defense_exp: 3,
|
|
||||||
dexterity_exp: 3,
|
|
||||||
agility_exp: 3,
|
|
||||||
|
|
||||||
strength_success_weight: 1.5,
|
|
||||||
defense_success_weight: 0.5,
|
|
||||||
dexterity_success_weight: 1.5,
|
|
||||||
agility_success_weight: 0.5,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Larceny: new Crime("Larceny", CONSTANTS.CrimeLarceny, 90e3, 800e3, 1/3, 1.5, {
|
|
||||||
hacking_exp: 45,
|
|
||||||
dexterity_exp: 60,
|
|
||||||
agility_exp: 60,
|
|
||||||
|
|
||||||
hacking_success_weight: 0.5,
|
|
||||||
dexterity_success_weight: 1,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
|
|
||||||
intelligence_exp: 0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
}),
|
|
||||||
|
|
||||||
DealDrugs: new Crime("Deal Drugs", CONSTANTS.CrimeDrugs, 10e3, 120e3, 1, 0.5, {
|
|
||||||
dexterity_exp: 5,
|
|
||||||
agility_exp: 5,
|
|
||||||
charisma_exp: 10,
|
|
||||||
|
|
||||||
charisma_success_weight: 3,
|
|
||||||
dexterity_success_weight: 2,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
}),
|
|
||||||
|
|
||||||
BondForgery: new Crime("Bond Forgery", CONSTANTS.CrimeBondForgery, 300e3, 4.5e6, 1/2, 0.1, {
|
|
||||||
hacking_exp: 100,
|
|
||||||
dexterity_exp: 150,
|
|
||||||
charisma_exp: 15,
|
|
||||||
|
|
||||||
hacking_success_weight: 0.05,
|
|
||||||
dexterity_success_weight: 1.25,
|
|
||||||
|
|
||||||
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
}),
|
|
||||||
|
|
||||||
TraffickArms: new Crime("Traffick Arms", CONSTANTS.CrimeTraffickArms, 40e3, 600e3, 2, 1, {
|
|
||||||
strength_exp: 20,
|
|
||||||
defense_exp: 20,
|
|
||||||
dexterity_exp: 20,
|
|
||||||
agility_exp: 20,
|
|
||||||
charisma_exp: 40,
|
|
||||||
|
|
||||||
charisma_success_weight: 1,
|
|
||||||
strength_success_weight: 1,
|
|
||||||
defense_success_weight: 1,
|
|
||||||
dexterity_success_weight: 1,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Homicide: new Crime("Homicide", CONSTANTS.CrimeHomicide, 3e3, 45e3, 1, 3, {
|
|
||||||
strength_exp: 2,
|
|
||||||
defense_exp: 2,
|
|
||||||
dexterity_exp: 2,
|
|
||||||
agility_exp: 2,
|
|
||||||
|
|
||||||
strength_success_weight: 2,
|
|
||||||
defense_success_weight: 2,
|
|
||||||
dexterity_success_weight: 0.5,
|
|
||||||
agility_success_weight: 0.5,
|
|
||||||
|
|
||||||
kills: 1,
|
|
||||||
}),
|
|
||||||
|
|
||||||
GrandTheftAuto: new Crime("Grand Theft Auto", CONSTANTS.CrimeGrandTheftAuto, 80e3, 1.6e6, 8, 5, {
|
|
||||||
strength_exp: 20,
|
|
||||||
defense_exp: 20,
|
|
||||||
dexterity_exp: 20,
|
|
||||||
agility_exp: 80,
|
|
||||||
charisma_exp: 40,
|
|
||||||
|
|
||||||
hacking_success_weight: 1,
|
|
||||||
strength_success_weight: 1,
|
|
||||||
dexterity_success_weight: 4,
|
|
||||||
agility_success_weight: 2,
|
|
||||||
charisma_success_weight: 2,
|
|
||||||
|
|
||||||
intelligence_exp: CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Kidnap: new Crime("Kidnap", CONSTANTS.CrimeKidnap, 120e3, 3.6e6, 5, 6, {
|
|
||||||
strength_exp: 80,
|
|
||||||
defense_exp: 80,
|
|
||||||
dexterity_exp: 80,
|
|
||||||
agility_exp: 80,
|
|
||||||
charisma_exp: 80,
|
|
||||||
|
|
||||||
charisma_success_weight: 1,
|
|
||||||
strength_success_weight: 1,
|
|
||||||
dexterity_success_weight: 1,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
|
|
||||||
intelligence_exp: 2 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Assassination: new Crime("Assassination", CONSTANTS.CrimeAssassination, 300e3, 12e6, 8, 10, {
|
|
||||||
strength_exp: 300,
|
|
||||||
defense_exp: 300,
|
|
||||||
dexterity_exp: 300,
|
|
||||||
agility_exp: 300,
|
|
||||||
|
|
||||||
strength_success_weight: 1,
|
|
||||||
dexterity_success_weight: 2,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
|
|
||||||
intelligence_exp: 5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
|
|
||||||
kills: 1,
|
|
||||||
}),
|
|
||||||
|
|
||||||
Heist: new Crime("Heist", CONSTANTS.CrimeHeist, 600e3, 120e6, 18, 15, {
|
|
||||||
hacking_exp: 450,
|
|
||||||
strength_exp: 450,
|
|
||||||
defense_exp: 450,
|
|
||||||
dexterity_exp: 450,
|
|
||||||
agility_exp: 450,
|
|
||||||
charisma_exp: 450,
|
|
||||||
|
|
||||||
hacking_success_weight: 1,
|
|
||||||
strength_success_weight: 1,
|
|
||||||
defense_success_weight: 1,
|
|
||||||
dexterity_success_weight: 1,
|
|
||||||
agility_success_weight: 1,
|
|
||||||
charisma_success_weight: 1,
|
|
||||||
|
|
||||||
intelligence_exp: 10 * CONSTANTS.IntelligenceCrimeBaseExpGain,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
function determineCrimeSuccess(type, moneyGained) {
|
|
||||||
var chance = 0;
|
|
||||||
var found = false;
|
|
||||||
for(const i in Crimes) {
|
|
||||||
const crime = Crimes[i];
|
|
||||||
if(crime.type == type) {
|
|
||||||
chance = crime.successRate();
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found) {
|
|
||||||
console.log(crime);
|
|
||||||
dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.random() <= chance) {
|
|
||||||
//Success
|
|
||||||
Player.gainMoney(moneyGained);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
//Failure
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findCrime(roughName) {
|
|
||||||
if (roughName.includes("shoplift")) {
|
|
||||||
return Crimes.Shoplift;
|
|
||||||
} else if (roughName.includes("rob") && roughName.includes("store")) {
|
|
||||||
return Crimes.RobStore;
|
|
||||||
} else if (roughName.includes("mug")) {
|
|
||||||
return Crimes.Mug;
|
|
||||||
} else if (roughName.includes("larceny")) {
|
|
||||||
return Crimes.Larceny;
|
|
||||||
} else if (roughName.includes("drugs")) {
|
|
||||||
return Crimes.DealDrugs;
|
|
||||||
} else if (roughName.includes("bond") && roughName.includes("forge")) {
|
|
||||||
return Crimes.BondForgery;
|
|
||||||
} else if (roughName.includes("traffick") && roughName.includes("arms")) {
|
|
||||||
return Crimes.TraffickArms;
|
|
||||||
} else if (roughName.includes("homicide")) {
|
|
||||||
return Crimes.Homicide;
|
|
||||||
} else if (roughName.includes("grand") && roughName.includes("auto")) {
|
|
||||||
return Crimes.GrandTheftAuto;
|
|
||||||
} else if (roughName.includes("kidnap")) {
|
|
||||||
return Crimes.Kidnap;
|
|
||||||
} else if (roughName.includes("assassinate")) {
|
|
||||||
return Crimes.Assassination;
|
|
||||||
} else if (roughName.includes("heist")) {
|
|
||||||
return Crimes.Heist;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {determineCrimeSuccess,findCrime,Crimes};
|
|
@ -1,4 +1,4 @@
|
|||||||
import { AugmentationNames } from "./Augmentations";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
import { generateRandomContract } from "./CodingContractGenerator";
|
import { generateRandomContract } from "./CodingContractGenerator";
|
||||||
import { Programs } from "./Programs/Programs";
|
import { Programs } from "./Programs/Programs";
|
||||||
import { Factions } from "./Faction/Factions";
|
import { Factions } from "./Faction/Factions";
|
||||||
@ -6,13 +6,17 @@ import { Player } from "./Player";
|
|||||||
import { AllServers } from "./Server";
|
import { AllServers } from "./Server";
|
||||||
import { hackWorldDaemon } from "./RedPill";
|
import { hackWorldDaemon } from "./RedPill";
|
||||||
import { StockMarket,
|
import { StockMarket,
|
||||||
SymbolToStockMap } from "./StockMarket";
|
SymbolToStockMap } from "./StockMarket/StockMarket";
|
||||||
import { Stock } from "./Stock";
|
import { Stock } from "./StockMarket/Stock";
|
||||||
import { Terminal } from "./Terminal";
|
import { Terminal } from "./Terminal";
|
||||||
|
|
||||||
import { numeralWrapper } from "./ui/numeralFormat";
|
import { numeralWrapper } from "./ui/numeralFormat";
|
||||||
|
|
||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
import { createElement } from "../utils/uiHelpers/createElement";
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
|
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
|
||||||
|
import { getSelectText } from "../utils/uiHelpers/getSelectData";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
|
|
||||||
const devMenuContainerId = "dev-menu-container";
|
const devMenuContainerId = "dev-menu-container";
|
||||||
@ -222,7 +226,7 @@ export function createDevMenu() {
|
|||||||
innerText: "Receive Invite to Faction",
|
innerText: "Receive Invite to Faction",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Augmentations / Source Files
|
// Augmentations
|
||||||
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
|
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
|
||||||
|
|
||||||
const augmentationsDropdown = createElement("select", {
|
const augmentationsDropdown = createElement("select", {
|
||||||
@ -242,6 +246,32 @@ export function createDevMenu() {
|
|||||||
innerText: "Queue Augmentation",
|
innerText: "Queue Augmentation",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Source Files
|
||||||
|
const sourceFilesHeader = createElement("h2", { innerText: "Source-Files" });
|
||||||
|
|
||||||
|
const removeSourceFileDropdown = createElement("select", {
|
||||||
|
class: "dropdown",
|
||||||
|
margin: "5px",
|
||||||
|
});
|
||||||
|
for (let i = 0; i < 24; ++i) {
|
||||||
|
removeSourceFileDropdown.add(createOptionElement(String(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeSourceFileButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
clickListener: () => {
|
||||||
|
const numToRemove = parseInt(getSelectText(removeSourceFileDropdown));
|
||||||
|
for (let i = 0; i < Player.sourceFiles.length; ++i) {
|
||||||
|
if (Player.sourceFiles[i].n === numToRemove) {
|
||||||
|
Player.sourceFiles.splice(i, 1);
|
||||||
|
hackWorldDaemon(Player.bitNodeN, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
innerText: "Remove Source File and Trigger Bitflume",
|
||||||
|
});
|
||||||
|
|
||||||
// Programs
|
// Programs
|
||||||
const programsHeader = createElement("h2", {innerText: "Programs"});
|
const programsHeader = createElement("h2", {innerText: "Programs"});
|
||||||
|
|
||||||
@ -508,6 +538,9 @@ export function createDevMenu() {
|
|||||||
devMenuContainer.appendChild(augmentationsHeader);
|
devMenuContainer.appendChild(augmentationsHeader);
|
||||||
devMenuContainer.appendChild(augmentationsDropdown);
|
devMenuContainer.appendChild(augmentationsDropdown);
|
||||||
devMenuContainer.appendChild(augmentationsQueueButton);
|
devMenuContainer.appendChild(augmentationsQueueButton);
|
||||||
|
devMenuContainer.appendChild(sourceFilesHeader);
|
||||||
|
devMenuContainer.appendChild(removeSourceFileDropdown);
|
||||||
|
devMenuContainer.appendChild(removeSourceFileButton);
|
||||||
devMenuContainer.appendChild(programsHeader);
|
devMenuContainer.appendChild(programsHeader);
|
||||||
devMenuContainer.appendChild(programsAddDropdown);
|
devMenuContainer.appendChild(programsAddDropdown);
|
||||||
devMenuContainer.appendChild(programsAddButton);
|
devMenuContainer.appendChild(programsAddButton);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Augmentations, AugmentationNames,
|
import { Augmentations } from "../Augmentation/Augmentations";
|
||||||
PlayerOwnedAugmentation } from "../Augmentations";
|
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||||
import { BitNodeMultipliers } from "../BitNodeMultipliers";
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||||
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
import { Engine } from "../engine";
|
import { Engine } from "../engine";
|
||||||
import { Faction } from "./Faction";
|
import { Faction } from "./Faction";
|
||||||
@ -9,8 +10,8 @@ import { FactionInfos } from "./FactionInfo";
|
|||||||
import { Locations} from "../Location";
|
import { Locations} from "../Location";
|
||||||
import { HackingMission, setInMission } from "../Missions";
|
import { HackingMission, setInMission } from "../Missions";
|
||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
import { PurchaseAugmentationsOrderSetting } from "../SettingEnums";
|
import { PurchaseAugmentationsOrderSetting } from "../Settings/SettingEnums";
|
||||||
import { Settings } from "../Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
|
|
||||||
import {Page, routing} from "../ui/navigationTracking";
|
import {Page, routing} from "../ui/navigationTracking";
|
||||||
import {numeralWrapper} from "../ui/numeralFormat";
|
import {numeralWrapper} from "../ui/numeralFormat";
|
||||||
@ -480,7 +481,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
|
|||||||
}
|
}
|
||||||
|
|
||||||
var item = createElement("li");
|
var item = createElement("li");
|
||||||
var span = createElement("span", {display:"inline-block"});
|
var span = createElement("span", { display:"inline-block", margin: "4px", padding: "4px" });
|
||||||
var aDiv = createElement("div", {tooltip:aug.info});
|
var aDiv = createElement("div", {tooltip:aug.info});
|
||||||
var aElem = createElement("a", {
|
var aElem = createElement("a", {
|
||||||
innerText:aug.name, display:"inline",
|
innerText:aug.name, display:"inline",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { Server } from "./Server";
|
import { Server } from "./Server";
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {BitNodeMultipliers} from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
import {CONSTANTS} from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import {Engine} from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {iTutorialSteps, iTutorialNextStep,
|
import {iTutorialSteps, iTutorialNextStep,
|
||||||
ITutorial} from "./InteractiveTutorial";
|
ITutorial} from "./InteractiveTutorial";
|
||||||
import {Player} from "./Player";
|
import {Player} from "./Player";
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import {BitNodeMultipliers} from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
import {CONSTANTS} from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import {Engine} from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {Player} from "./Player";
|
import { Player } from "./Player";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||||
import {getRandomInt} from "../utils/helpers/getRandomInt";
|
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||||
import {infiltrationBoxCreate} from "../utils/InfiltrationBox";
|
import { infiltrationBoxCreate } from "../utils/InfiltrationBox";
|
||||||
import {formatNumber} from "../utils/StringHelperFunctions";
|
import { formatNumber } from "../utils/StringHelperFunctions";
|
||||||
|
|
||||||
/* Infiltration.js
|
/* Infiltration.js
|
||||||
*
|
*
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import {Engine} from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {Player} from "./Player";
|
import { Player } from "./Player";
|
||||||
import {Settings} from "./Settings";
|
import { Settings } from "./Settings/Settings";
|
||||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
import { initializeMainMenuLinks } from "./ui/MainMenu/Links";
|
||||||
import {createElement} from "../utils/uiHelpers/createElement";
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
import {createPopup} from "../utils/uiHelpers/createPopup";
|
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||||
import {removeElementById} from "../utils/uiHelpers/removeElementById";
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
|
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||||
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
|
|
||||||
//Ordered array of keys to Interactive Tutorial Steps
|
//Ordered array of keys to Interactive Tutorial Steps
|
||||||
const orderedITutorialSteps = [
|
const orderedITutorialSteps = [
|
||||||
@ -472,7 +474,19 @@ function iTutorialEnd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log("Ending interactive tutorial");
|
console.log("Ending interactive tutorial");
|
||||||
|
|
||||||
|
// Initialize references to main menu links
|
||||||
|
// We have to call initializeMainMenuLinks() again because the Interactive Tutorial
|
||||||
|
// re-creates Main menu links with clearEventListeners()
|
||||||
|
if (!initializeMainMenuLinks()) {
|
||||||
|
const errorMsg = "Failed to initialize Main Menu Links. Please try refreshing the page. " +
|
||||||
|
"If that doesn't work, report the issue to the developer";
|
||||||
|
exceptionAlert(new Error(errorMsg));
|
||||||
|
console.error(errorMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Engine.init();
|
Engine.init();
|
||||||
|
|
||||||
ITutorial.currStep = iTutorialSteps.End;
|
ITutorial.currStep = iTutorialSteps.End;
|
||||||
ITutorial.isRunning = false;
|
ITutorial.isRunning = false;
|
||||||
document.getElementById("interactive-tutorial-container").style.display = "none";
|
document.getElementById("interactive-tutorial-container").style.display = "none";
|
||||||
|
135
src/Location.js
135
src/Location.js
@ -5,16 +5,18 @@ import {getJobRequirementText} from "./Company/GetJobRequiremen
|
|||||||
import * as posNames from "./Company/data/CompanyPositionNames";
|
import * as posNames from "./Company/data/CompanyPositionNames";
|
||||||
import { Corporation } from "./Corporation/Corporation";
|
import { Corporation } from "./Corporation/Corporation";
|
||||||
import {CONSTANTS} from "./Constants";
|
import {CONSTANTS} from "./Constants";
|
||||||
import {Crimes} from "./Crimes";
|
import { Crimes } from "./Crime/Crimes";
|
||||||
import {Engine} from "./engine";
|
import {Engine} from "./engine";
|
||||||
import {beginInfiltration} from "./Infiltration";
|
import {beginInfiltration} from "./Infiltration";
|
||||||
import {hasBladeburnerSF} from "./NetscriptFunctions";
|
import {hasBladeburnerSF} from "./NetscriptFunctions";
|
||||||
import {Locations} from "./Locations";
|
import {Locations} from "./Locations";
|
||||||
import {Player} from "./Player";
|
import {Player} from "./Player";
|
||||||
import {Server, AllServers, AddToAllServers} from "./Server";
|
import {Server, AllServers, AddToAllServers} from "./Server";
|
||||||
import {purchaseServer,
|
import { getPurchaseServerCost,
|
||||||
purchaseRamForHomeComputer} from "./ServerPurchases";
|
purchaseServer,
|
||||||
import {Settings} from "./Settings";
|
purchaseRamForHomeComputer} from "./ServerPurchases";
|
||||||
|
import {Settings} from "./Settings/Settings";
|
||||||
|
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||||
import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps";
|
import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps";
|
||||||
|
|
||||||
import {numeralWrapper} from "./ui/numeralFormat";
|
import {numeralWrapper} from "./ui/numeralFormat";
|
||||||
@ -121,6 +123,8 @@ function displayLocationContent() {
|
|||||||
|
|
||||||
var nsaBladeburner = document.getElementById("location-nsa-bladeburner");
|
var nsaBladeburner = document.getElementById("location-nsa-bladeburner");
|
||||||
|
|
||||||
|
const vitalifeResleeve = document.getElementById("location-vitalife-resleeve");
|
||||||
|
|
||||||
var loc = Player.location;
|
var loc = Player.location;
|
||||||
|
|
||||||
returnToWorld.addEventListener("click", function() {
|
returnToWorld.addEventListener("click", function() {
|
||||||
@ -188,16 +192,16 @@ function displayLocationContent() {
|
|||||||
purchaseHomeRam.style.display = "none";
|
purchaseHomeRam.style.display = "none";
|
||||||
purchaseHomeCores.style.display = "none";
|
purchaseHomeCores.style.display = "none";
|
||||||
|
|
||||||
purchase2gb.innerHTML = "Purchase 2GB Server - $" + formatNumber(2*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase2gb.innerHTML = "Purchase 2GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(2));
|
||||||
purchase4gb.innerHTML = "Purchase 4GB Server - $" + formatNumber(4*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase4gb.innerHTML = "Purchase 4GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(4));
|
||||||
purchase8gb.innerHTML = "Purchase 8GB Server - $" + formatNumber(8*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase8gb.innerHTML = "Purchase 8GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(8));
|
||||||
purchase16gb.innerHTML = "Purchase 16GB Server - $" + formatNumber(16*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase16gb.innerHTML = "Purchase 16GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(16));
|
||||||
purchase32gb.innerHTML = "Purchase 32GB Server - $" + formatNumber(32*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase32gb.innerHTML = "Purchase 32GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(32));
|
||||||
purchase64gb.innerHTML = "Purchase 64GB Server - $" + formatNumber(64*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase64gb.innerHTML = "Purchase 64GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(64));
|
||||||
purchase128gb.innerHTML = "Purchase 128GB Server - $" + formatNumber(128*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase128gb.innerHTML = "Purchase 128GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(128));
|
||||||
purchase256gb.innerHTML = "Purchase 256GB Server - $" + formatNumber(256*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase256gb.innerHTML = "Purchase 256GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(256));
|
||||||
purchase512gb.innerHTML = "Purchase 512GB Server - $" + formatNumber(512*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase512gb.innerHTML = "Purchase 512GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(512));
|
||||||
purchase1tb.innerHTML = "Purchase 1TB Server - $" + formatNumber(1024*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
|
purchase1tb.innerHTML = "Purchase 1TB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(1024));
|
||||||
if (!SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
if (!SpecialServerIps.hasOwnProperty("Darkweb Server")) {
|
||||||
purchaseTor.classList.add("a-link-button");
|
purchaseTor.classList.add("a-link-button");
|
||||||
purchaseTor.classList.remove("a-link-button-bought");
|
purchaseTor.classList.remove("a-link-button-bought");
|
||||||
@ -237,10 +241,11 @@ function displayLocationContent() {
|
|||||||
|
|
||||||
cityHallCreateCorporation.style.display = "none";
|
cityHallCreateCorporation.style.display = "none";
|
||||||
nsaBladeburner.style.display = "none";
|
nsaBladeburner.style.display = "none";
|
||||||
|
vitalifeResleeve.style.display = "none";
|
||||||
|
|
||||||
//Check if the player is employed at this Location. If he is, display the "Work" button,
|
//Check if the player is employed at this Location. If he is, display the "Work" button,
|
||||||
//update the job title, etc.
|
//update the job title, etc.
|
||||||
if (loc != "" && loc === Player.companyName) {
|
if (loc != "" && Object.keys(Player.jobs).includes(loc)) {
|
||||||
let company = Companies[loc];
|
let company = Companies[loc];
|
||||||
|
|
||||||
jobTitle.style.display = "block";
|
jobTitle.style.display = "block";
|
||||||
@ -249,7 +254,7 @@ function displayLocationContent() {
|
|||||||
locationTxtDiv1.style.display = "block";
|
locationTxtDiv1.style.display = "block";
|
||||||
locationTxtDiv2.style.display = "block";
|
locationTxtDiv2.style.display = "block";
|
||||||
locationTxtDiv3.style.display = "block";
|
locationTxtDiv3.style.display = "block";
|
||||||
jobTitle.innerHTML = "Job Title: " + Player.companyPosition;
|
jobTitle.innerHTML = `Job Title: ${Player.jobs[loc]}`;
|
||||||
let repGain = company.getFavorGain();
|
let repGain = company.getFavorGain();
|
||||||
if (repGain.length != 2) {repGain = 0;}
|
if (repGain.length != 2) {repGain = 0;}
|
||||||
repGain = repGain[0];
|
repGain = repGain[0];
|
||||||
@ -264,16 +269,16 @@ function displayLocationContent() {
|
|||||||
"favor you gain depends on how much reputation you have with the company</span>";
|
"favor you gain depends on how much reputation you have with the company</span>";
|
||||||
work.style.display = "block";
|
work.style.display = "block";
|
||||||
|
|
||||||
let currPos = CompanyPositions[Player.companyPosition];
|
let currPos = CompanyPositions[Player.jobs[loc]];
|
||||||
if (currPos == null) {
|
if (currPos == null) {
|
||||||
throw new Error("Player's companyPosition property has an invalid value");
|
throw new Error("Player's companyPosition property has an invalid value");
|
||||||
}
|
}
|
||||||
|
|
||||||
work.addEventListener("click", function() {
|
work.addEventListener("click", function() {
|
||||||
if (currPos.isPartTimeJob() || currPos.isSoftwareConsultantJob() || currPos.isBusinessConsultantJob()) {
|
if (currPos.isPartTimeJob() || currPos.isSoftwareConsultantJob() || currPos.isBusinessConsultantJob()) {
|
||||||
Player.startWorkPartTime();
|
Player.startWorkPartTime(loc);
|
||||||
} else {
|
} else {
|
||||||
Player.startWork();
|
Player.startWork(loc);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -761,6 +766,10 @@ function displayLocationContent() {
|
|||||||
businessJob.style.display = "block";
|
businessJob.style.display = "block";
|
||||||
setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife,
|
setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife,
|
||||||
605, 22, 100, 3.5);
|
605, 22, 100, 3.5);
|
||||||
|
if (Player.bitNodeN === 10 || SourceFileFlags[10]) {
|
||||||
|
vitalifeResleeve.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Locations.NewTokyoGlobalPharmaceuticals:
|
case Locations.NewTokyoGlobalPharmaceuticals:
|
||||||
@ -979,18 +988,18 @@ function displayLocationContent() {
|
|||||||
case Locations.NewTokyoSlums:
|
case Locations.NewTokyoSlums:
|
||||||
case Locations.IshimaSlums:
|
case Locations.IshimaSlums:
|
||||||
case Locations.VolhavenSlums:
|
case Locations.VolhavenSlums:
|
||||||
var shopliftChance = Crimes.Shoplift.successRate();
|
var shopliftChance = Crimes.Shoplift.successRate(Player);
|
||||||
var robStoreChance = Crimes.RobStore.successRate();
|
var robStoreChance = Crimes.RobStore.successRate(Player);
|
||||||
var mugChance = Crimes.Mug.successRate();
|
var mugChance = Crimes.Mug.successRate(Player);
|
||||||
var larcenyChance = Crimes.Larceny.successRate();
|
var larcenyChance = Crimes.Larceny.successRate(Player);
|
||||||
var drugsChance = Crimes.DealDrugs.successRate();
|
var drugsChance = Crimes.DealDrugs.successRate(Player);
|
||||||
var bondChance = Crimes.BondForgery.successRate();
|
var bondChance = Crimes.BondForgery.successRate(Player);
|
||||||
var armsChance = Crimes.TraffickArms.successRate();
|
var armsChance = Crimes.TraffickArms.successRate(Player);
|
||||||
var homicideChance = Crimes.Homicide.successRate();
|
var homicideChance = Crimes.Homicide.successRate(Player);
|
||||||
var gtaChance = Crimes.GrandTheftAuto.successRate();
|
var gtaChance = Crimes.GrandTheftAuto.successRate(Player);
|
||||||
var kidnapChance = Crimes.Kidnap.successRate();
|
var kidnapChance = Crimes.Kidnap.successRate(Player);
|
||||||
var assassinateChance = Crimes.Assassination.successRate();
|
var assassinateChance = Crimes.Assassination.successRate(Player);
|
||||||
var heistChance = Crimes.Heist.successRate();
|
var heistChance = Crimes.Heist.successRate(Player);
|
||||||
|
|
||||||
slumsDescText.style.display = "block";
|
slumsDescText.style.display = "block";
|
||||||
slumsShoplift.style.display = "block";
|
slumsShoplift.style.display = "block";
|
||||||
@ -1043,8 +1052,8 @@ function displayLocationContent() {
|
|||||||
|
|
||||||
// Make the "Apply to be Employee and Waiter" texts disappear if you already hold the job
|
// Make the "Apply to be Employee and Waiter" texts disappear if you already hold the job
|
||||||
// Includes part-time stuff
|
// Includes part-time stuff
|
||||||
if (loc == Player.companyName) {
|
if (Object.keys(Player.jobs).includes(loc)) {
|
||||||
var currPos = Player.companyPosition;
|
var currPos = Player.jobs[loc];
|
||||||
|
|
||||||
if (currPos == "Employee") {
|
if (currPos == "Employee") {
|
||||||
employeeJob.style.display = "none";
|
employeeJob.style.display = "none";
|
||||||
@ -1634,6 +1643,8 @@ function initLocationButtons() {
|
|||||||
|
|
||||||
var nsaBladeburner = document.getElementById("location-nsa-bladeburner");
|
var nsaBladeburner = document.getElementById("location-nsa-bladeburner");
|
||||||
|
|
||||||
|
const vitalifeResleeve = document.getElementById("location-vitalife-resleeve");
|
||||||
|
|
||||||
var hospitalTreatment = document.getElementById("location-hospital-treatment");
|
var hospitalTreatment = document.getElementById("location-hospital-treatment");
|
||||||
|
|
||||||
softwareJob.addEventListener("click", function(e) {
|
softwareJob.addEventListener("click", function(e) {
|
||||||
@ -1716,61 +1727,61 @@ function initLocationButtons() {
|
|||||||
|
|
||||||
purchase2gb.addEventListener("click", function(e) {
|
purchase2gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(2, 2 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(2);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase4gb.addEventListener("click", function(e) {
|
purchase4gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(4, 4 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(4);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase8gb.addEventListener("click", function(e) {
|
purchase8gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(8, 8 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(8);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase16gb.addEventListener("click", function(e) {
|
purchase16gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(16, 16 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(16);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase32gb.addEventListener("click", function(e) {
|
purchase32gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(32, 32 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(32);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase64gb.addEventListener("click", function(e) {
|
purchase64gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(64, 64 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(64);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase128gb.addEventListener("click", function(e) {
|
purchase128gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(128, 128 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(128);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase256gb.addEventListener("click", function(e) {
|
purchase256gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(256, 256 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(256);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase512gb.addEventListener("click", function(e) {
|
purchase512gb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(512, 512 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(512);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
purchase1tb.addEventListener("click", function(e) {
|
purchase1tb.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
purchaseServerBoxCreate(1024, 1024 * CONSTANTS.BaseCostFor1GBOfRamServer);
|
purchaseServerBoxCreate(1024);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1874,73 +1885,73 @@ function initLocationButtons() {
|
|||||||
|
|
||||||
slumsShoplift.addEventListener("click", function(e) {
|
slumsShoplift.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Shoplift.commit();
|
Crimes.Shoplift.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsRobStore.addEventListener("click", function(e) {
|
slumsRobStore.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.RobStore.commit();
|
Crimes.RobStore.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsMug.addEventListener("click", function(e) {
|
slumsMug.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Mug.commit();
|
Crimes.Mug.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsLarceny.addEventListener("click", function(e) {
|
slumsLarceny.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Larceny.commit();
|
Crimes.Larceny.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsDealDrugs.addEventListener("click", function(e) {
|
slumsDealDrugs.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.DealDrugs.commit();
|
Crimes.DealDrugs.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsBondForgery.addEventListener("click", function(e) {
|
slumsBondForgery.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.BondForgery.commit();
|
Crimes.BondForgery.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsTrafficArms.addEventListener("click", function(e) {
|
slumsTrafficArms.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.TraffickArms.commit();
|
Crimes.TraffickArms.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsHomicide.addEventListener("click", function(e) {
|
slumsHomicide.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Homicide.commit();
|
Crimes.Homicide.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsGta.addEventListener("click", function(e) {
|
slumsGta.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.GrandTheftAuto.commit();
|
Crimes.GrandTheftAuto.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsKidnap.addEventListener("click", function(e) {
|
slumsKidnap.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Kidnap.commit();
|
Crimes.Kidnap.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsAssassinate.addEventListener("click", function(e) {
|
slumsAssassinate.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Assassination.commit();
|
Crimes.Assassination.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
slumsHeist.addEventListener("click", function(e) {
|
slumsHeist.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
Crimes.Heist.commit();
|
Crimes.Heist.commit(Player);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2041,6 +2052,10 @@ function initLocationButtons() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vitalifeResleeve.addEventListener("click", function() {
|
||||||
|
Engine.loadResleevingContent();
|
||||||
|
});
|
||||||
|
|
||||||
hospitalTreatment.addEventListener("click", function(e) {
|
hospitalTreatment.addEventListener("click", function(e) {
|
||||||
if (!e.isTrusted) {return false;}
|
if (!e.isTrusted) {return false;}
|
||||||
if (Player.hp < 0) {Player.hp = 0;}
|
if (Player.hp < 0) {Player.hp = 0;}
|
||||||
@ -2250,13 +2265,19 @@ function travelBoxCreate(destCityName, cost) {
|
|||||||
yesNoBoxCreate("Would you like to travel to " + destCityName + "? The trip will cost $" + formatNumber(cost, 2) + ".");
|
yesNoBoxCreate("Would you like to travel to " + destCityName + "? The trip will cost $" + formatNumber(cost, 2) + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
function purchaseServerBoxCreate(ram, cost) {
|
function purchaseServerBoxCreate(ram) {
|
||||||
|
const cost = getPurchaseServerCost(ram);
|
||||||
|
if (cost === Infinity) {
|
||||||
|
dialogBoxCreate("Something went wrong when trying to purchase this server. Please contact developer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var yesBtn = yesNoTxtInpBoxGetYesButton();
|
var yesBtn = yesNoTxtInpBoxGetYesButton();
|
||||||
var noBtn = yesNoTxtInpBoxGetNoButton();
|
var noBtn = yesNoTxtInpBoxGetNoButton();
|
||||||
yesBtn.innerHTML = "Purchase Server";
|
yesBtn.innerHTML = "Purchase Server";
|
||||||
noBtn.innerHTML = "Cancel";
|
noBtn.innerHTML = "Cancel";
|
||||||
yesBtn.addEventListener("click", function() {
|
yesBtn.addEventListener("click", function() {
|
||||||
purchaseServer(ram, cost);
|
purchaseServer(ram);
|
||||||
yesNoTxtInpBoxClose();
|
yesNoTxtInpBoxClose();
|
||||||
});
|
});
|
||||||
noBtn.addEventListener("click", function() {
|
noBtn.addEventListener("click", function() {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Augmentations,
|
import { Augmentatation } from "./Augmentation/Augmentation";
|
||||||
Augmentation,
|
import { Augmentations } from "./Augmentation/Augmentations";
|
||||||
AugmentationNames } from "./Augmentations";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
import { Programs } from "./Programs/Programs";
|
import { Programs } from "./Programs/Programs";
|
||||||
import { inMission } from "./Missions";
|
import { inMission } from "./Missions";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { redPillFlag } from "./RedPill";
|
import { redPillFlag } from "./RedPill";
|
||||||
import { GetServerByHostname } from "./Server";
|
import { GetServerByHostname } from "./Server";
|
||||||
import { Settings } from "./Settings";
|
import { Settings } from "./Settings/Settings";
|
||||||
import { dialogBoxCreate,
|
import { dialogBoxCreate,
|
||||||
dialogBoxOpened} from "../utils/DialogBox";
|
dialogBoxOpened} from "../utils/DialogBox";
|
||||||
import {Reviver, Generic_toJSON,
|
import {Reviver, Generic_toJSON,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import {BitNodeMultipliers} from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
import {CONSTANTS} from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import {Player} from "./Player";
|
import { Player } from "./Player";
|
||||||
import {Environment} from "./NetscriptEnvironment";
|
import { Environment } from "./NetscriptEnvironment";
|
||||||
import {WorkerScript, addWorkerScript} from "./NetscriptWorker";
|
import { WorkerScript, addWorkerScript} from "./NetscriptWorker";
|
||||||
import {Server, getServer} from "./Server";
|
import { Server, getServer} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import { Settings } from "./Settings/Settings";
|
||||||
import {Script, findRunningScript,
|
import { Script, findRunningScript,
|
||||||
RunningScript} from "./Script";
|
RunningScript } from "./Script";
|
||||||
|
|
||||||
import {parse, Node} from "../utils/acorn";
|
import {parse, Node} from "../utils/acorn";
|
||||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||||
@ -860,6 +860,7 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
|
|||||||
var script = server.scripts[i];
|
var script = server.scripts[i];
|
||||||
var ramUsage = script.ramUsage;
|
var ramUsage = script.ramUsage;
|
||||||
threads = Math.round(Number(threads)); //Convert to number and round
|
threads = Math.round(Number(threads)); //Convert to number and round
|
||||||
|
if (threads === 0) { return Promise.resolve(false); }
|
||||||
ramUsage = ramUsage * threads;
|
ramUsage = ramUsage * threads;
|
||||||
var ramAvailable = server.maxRam - server.ramUsed;
|
var ramAvailable = server.maxRam - server.ramUsed;
|
||||||
|
|
||||||
|
@ -2,11 +2,13 @@ var sprintf = require('sprintf-js').sprintf,
|
|||||||
vsprintf = require('sprintf-js').vsprintf
|
vsprintf = require('sprintf-js').vsprintf
|
||||||
|
|
||||||
import {updateActiveScriptsItems} from "./ActiveScriptsUI";
|
import {updateActiveScriptsItems} from "./ActiveScriptsUI";
|
||||||
import {Augmentations, Augmentation,
|
import { Augmentation } from "./Augmentation/Augmentation";
|
||||||
augmentationExists, installAugmentations,
|
import { Augmentations } from "./Augmentation/Augmentations";
|
||||||
AugmentationNames} from "./Augmentations";
|
import { augmentationExists,
|
||||||
import {BitNodeMultipliers} from "./BitNodeMultipliers";
|
installAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||||
import {determineCrimeSuccess, findCrime} from "./Crimes";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
|
import { determineCrimeSuccess, findCrime } from "./Crime/CrimeHelpers";
|
||||||
import {Bladeburner} from "./Bladeburner";
|
import {Bladeburner} from "./Bladeburner";
|
||||||
import {Company} from "./Company/Company";
|
import {Company} from "./Company/Company";
|
||||||
import {Companies, companyExists} from "./Company/Companies";
|
import {Companies, companyExists} from "./Company/Companies";
|
||||||
@ -38,14 +40,17 @@ import {Script, findRunningScript, RunningScript,
|
|||||||
import {Server, getServer, AddToAllServers,
|
import {Server, getServer, AddToAllServers,
|
||||||
AllServers, processSingleServerGrowth,
|
AllServers, processSingleServerGrowth,
|
||||||
GetServerByHostname, numCycleForGrowth} from "./Server";
|
GetServerByHostname, numCycleForGrowth} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import { getPurchaseServerCost,
|
||||||
|
getPurchaseServerLimit,
|
||||||
|
getPurchaseServerMaxRam } from "./ServerPurchases";
|
||||||
|
import {Settings} from "./Settings/Settings";
|
||||||
import {SpecialServerIps} from "./SpecialServerIps";
|
import {SpecialServerIps} from "./SpecialServerIps";
|
||||||
import {Stock} from "./Stock";
|
import {Stock} from "./StockMarket/Stock";
|
||||||
import {StockMarket, StockSymbols, SymbolToStockMap,
|
import {StockMarket, StockSymbols, SymbolToStockMap,
|
||||||
initStockMarket, initSymbolToStockMap, buyStock,
|
initStockMarket, initSymbolToStockMap, buyStock,
|
||||||
sellStock, updateStockPlayerPosition,
|
sellStock, updateStockPlayerPosition,
|
||||||
shortStock, sellShort, OrderTypes,
|
shortStock, sellShort, OrderTypes,
|
||||||
PositionTypes, placeOrder, cancelOrder} from "./StockMarket";
|
PositionTypes, placeOrder, cancelOrder} from "./StockMarket/StockMarket";
|
||||||
import {post} from "./ui/postToTerminal";
|
import {post} from "./ui/postToTerminal";
|
||||||
import {TextFile, getTextFile, createTextFile} from "./TextFile";
|
import {TextFile, getTextFile, createTextFile} from "./TextFile";
|
||||||
|
|
||||||
@ -232,24 +237,6 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return server.getContract(fn);
|
return server.getContract(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} ram The amount of server RAM to calculate cost of.
|
|
||||||
* @exception {Error} If the value passed in is not numeric, out of range, or too large of a value.
|
|
||||||
* @returns {number} The cost of
|
|
||||||
*/
|
|
||||||
const getPurchaseServerRamCostGuard = (ram) => {
|
|
||||||
const guardedRam = Math.round(ram);
|
|
||||||
if (isNaN(guardedRam) || !isPowerOfTwo(guardedRam)) {
|
|
||||||
throw Error("failed due to invalid ram argument. Must be numeric and a power of 2");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (guardedRam > CONSTANTS.PurchasedServerMaxRam) {
|
|
||||||
throw Error("failed because specified RAM was too high. Maximum RAM on a purchased server is " + CONSTANTS.PurchasedServerMaxRam + "GB");
|
|
||||||
}
|
|
||||||
|
|
||||||
return guardedRam * CONSTANTS.BaseCostFor1GBOfRamServer;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hacknet : {
|
hacknet : {
|
||||||
numNodes : function() {
|
numNodes : function() {
|
||||||
@ -417,7 +404,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
// Check argument validity
|
// Check argument validity
|
||||||
const server = safeGetServer(ip, 'hackAnalyzeThreads');
|
const server = safeGetServer(ip, 'hackAnalyzeThreads');
|
||||||
if (isNaN(hackAmount)) {
|
if (isNaN(hackAmount)) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, `Invalid growth argument passed into growthAnalyze: ${hackAmount}. Must be numeric`);
|
throw makeRuntimeRejectMsg(workerScript, `Invalid growth argument passed into hackAnalyzeThreads: ${hackAmount}. Must be numeric`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hackAmount < 0 || hackAmount > server.moneyAvailable) {
|
if (hackAmount < 0 || hackAmount > server.moneyAvailable) {
|
||||||
@ -819,7 +806,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if (scriptname === undefined) {
|
if (scriptname === undefined) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Usage: run(scriptname, [numThreads], [arg1], [arg2]...)");
|
throw makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Usage: run(scriptname, [numThreads], [arg1], [arg2]...)");
|
||||||
}
|
}
|
||||||
if (isNaN(threads) || threads < 1) {
|
if (isNaN(threads) || threads < 0) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0");
|
throw makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0");
|
||||||
}
|
}
|
||||||
var argsForNewScript = [];
|
var argsForNewScript = [];
|
||||||
@ -841,7 +828,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if (scriptname === undefined || ip === undefined) {
|
if (scriptname === undefined || ip === undefined) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Usage: exec(scriptname, server, [numThreads], [arg1], [arg2]...)");
|
throw makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Usage: exec(scriptname, server, [numThreads], [arg1], [arg2]...)");
|
||||||
}
|
}
|
||||||
if (isNaN(threads) || threads < 1) {
|
if (isNaN(threads) || threads < 0) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0");
|
throw makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0");
|
||||||
}
|
}
|
||||||
var argsForNewScript = [];
|
var argsForNewScript = [];
|
||||||
@ -866,7 +853,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if (scriptname === undefined) {
|
if (scriptname === undefined) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, "spawn() call has incorrect number of arguments. Usage: spawn(scriptname, numThreads, [arg1], [arg2]...)");
|
throw makeRuntimeRejectMsg(workerScript, "spawn() call has incorrect number of arguments. Usage: spawn(scriptname, numThreads, [arg1], [arg2]...)");
|
||||||
}
|
}
|
||||||
if (isNaN(threads) || threads < 1) {
|
if (isNaN(threads) || threads < 0) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0");
|
throw makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0");
|
||||||
}
|
}
|
||||||
var argsForNewScript = [];
|
var argsForNewScript = [];
|
||||||
@ -1537,6 +1524,22 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
||||||
},
|
},
|
||||||
|
getStockMaxShares : function(symbol) {
|
||||||
|
if (workerScript.checkingRam) {
|
||||||
|
return updateStaticRam("getStockMaxShares", CONSTANTS.ScriptGetStockRamCost);
|
||||||
|
}
|
||||||
|
updateDynamicRam("getStockMaxShares", CONSTANTS.ScriptGetStockRamCost);
|
||||||
|
|
||||||
|
if (!Player.hasTixApiAccess) {
|
||||||
|
throw makeRuntimeRejectMsg(workerScript, "You don't have TIX API Access! Cannot use getStockMaxShares()");
|
||||||
|
}
|
||||||
|
const stock = SymbolToStockMap[symbol];
|
||||||
|
if (stock == null) {
|
||||||
|
throw makeRuntimeRejectMsg(workerScript, "Invalid stock symbol passed into getStockMaxShares()");
|
||||||
|
}
|
||||||
|
|
||||||
|
return stock.maxShares;
|
||||||
|
},
|
||||||
buyStock : function(symbol, shares) {
|
buyStock : function(symbol, shares) {
|
||||||
if (workerScript.checkingRam) {
|
if (workerScript.checkingRam) {
|
||||||
return updateStaticRam("buyStock", CONSTANTS.ScriptBuySellStockRamCost);
|
return updateStaticRam("buyStock", CONSTANTS.ScriptBuySellStockRamCost);
|
||||||
@ -1556,6 +1559,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
shares = Math.round(shares);
|
shares = Math.round(shares);
|
||||||
if (shares === 0) {return 0;}
|
if (shares === 0) {return 0;}
|
||||||
|
|
||||||
|
// Does player have enough money?
|
||||||
var totalPrice = stock.price * shares;
|
var totalPrice = stock.price * shares;
|
||||||
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
|
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
|
||||||
workerScript.scriptRef.log("Not enough money to purchase " + formatNumber(shares, 0) + " shares of " +
|
workerScript.scriptRef.log("Not enough money to purchase " + formatNumber(shares, 0) + " shares of " +
|
||||||
@ -1564,6 +1568,13 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Would this purchase exceed the maximum number of shares?
|
||||||
|
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
|
||||||
|
workerScript.scriptRef.log(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ` +
|
||||||
|
`${stock.maxShares} shares.`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
var origTotal = stock.playerShares * stock.playerAvgPx;
|
var origTotal = stock.playerShares * stock.playerAvgPx;
|
||||||
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
|
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
|
||||||
var newTotal = origTotal + totalPrice;
|
var newTotal = origTotal + totalPrice;
|
||||||
@ -1885,7 +1896,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
updateDynamicRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit);
|
updateDynamicRam("getPurchasedServerLimit", CONSTANTS.ScriptGetPurchasedServerLimit);
|
||||||
|
|
||||||
return CONSTANTS.PurchasedServerLimit;
|
return getPurchaseServerLimit();
|
||||||
},
|
},
|
||||||
getPurchasedServerMaxRam: function() {
|
getPurchasedServerMaxRam: function() {
|
||||||
if (workerScript.checkingRam) {
|
if (workerScript.checkingRam) {
|
||||||
@ -1893,7 +1904,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
updateDynamicRam("getPurchasedServerMaxRam", CONSTANTS.ScriptGetPurchasedServerMaxRam);
|
updateDynamicRam("getPurchasedServerMaxRam", CONSTANTS.ScriptGetPurchasedServerMaxRam);
|
||||||
|
|
||||||
return CONSTANTS.PurchasedServerMaxRam;
|
return getPurchaseServerMaxRam();
|
||||||
},
|
},
|
||||||
getPurchasedServerCost: function(ram) {
|
getPurchasedServerCost: function(ram) {
|
||||||
if (workerScript.checkingRam) {
|
if (workerScript.checkingRam) {
|
||||||
@ -1901,11 +1912,9 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
updateDynamicRam("getPurchasedServerCost", CONSTANTS.ScriptGetPurchaseServerRamCost);
|
updateDynamicRam("getPurchasedServerCost", CONSTANTS.ScriptGetPurchaseServerRamCost);
|
||||||
|
|
||||||
let cost = 0;
|
const cost = getPurchaseServerCost(ram);
|
||||||
try {
|
if (cost === Infinity) {
|
||||||
cost = getPurchaseServerRamCostGuard(ram);
|
workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' failed due to an invalid 'ram' argument");
|
||||||
} catch (e) {
|
|
||||||
workerScript.scriptRef.log("ERROR: 'getPurchasedServerCost()' " + e.message);
|
|
||||||
return Infinity;
|
return Infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1919,26 +1928,23 @@ function NetscriptFunctions(workerScript) {
|
|||||||
var hostnameStr = String(hostname);
|
var hostnameStr = String(hostname);
|
||||||
hostnameStr = hostnameStr.replace(/\s+/g, '');
|
hostnameStr = hostnameStr.replace(/\s+/g, '');
|
||||||
if (hostnameStr == "") {
|
if (hostnameStr == "") {
|
||||||
workerScript.scriptRef.log("ERROR: Passed empty string for hostname argument of purchaseServer()");
|
workerScript.log("ERROR: Passed empty string for hostname argument of purchaseServer()");
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.purchasedServers.length >= CONSTANTS.PurchasedServerLimit) {
|
if (Player.purchasedServers.length >= getPurchaseServerLimit()) {
|
||||||
workerScript.scriptRef.log("ERROR: You have reached the maximum limit of " + CONSTANTS.PurchasedServerLimit +
|
workerScript.log(`ERROR: You have reached the maximum limit of ${getPurchaseServerLimit()} servers. You cannot purchase any more.`);
|
||||||
" servers. You cannot purchase any more.");
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
let cost = 0;
|
const cost = getPurchaseServerCost(ram);
|
||||||
try {
|
if (cost === Infinity) {
|
||||||
cost = getPurchaseServerRamCostGuard(ram);
|
workerScript.log("ERROR: 'purchaseServer()' failed due to an invalid 'ram' argument");
|
||||||
} catch (e) {
|
return Infinity;
|
||||||
workerScript.scriptRef.log("ERROR: 'purchaseServer()' " + e.message);
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player.money.lt(cost)) {
|
if (Player.money.lt(cost)) {
|
||||||
workerScript.scriptRef.log("ERROR: Not enough money to purchase server. Need $" + formatNumber(cost, 2));
|
workerScript.log("ERROR: Not enough money to purchase server. Need $" + formatNumber(cost, 2));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
var newServ = new Server({
|
var newServ = new Server({
|
||||||
@ -2878,16 +2884,12 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var companyPositionTitle = "";
|
|
||||||
if (CompanyPositions[Player.companyPosition] instanceof CompanyPosition) {
|
|
||||||
companyPositionTitle = Player.companyPosition;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
bitnode: Player.bitNodeN,
|
bitnode: Player.bitNodeN,
|
||||||
city: Player.city,
|
city: Player.city,
|
||||||
company: Player.companyName,
|
|
||||||
factions: Player.factions.slice(),
|
factions: Player.factions.slice(),
|
||||||
jobTitle: companyPositionTitle,
|
jobs: Object.keys(Player.jobs),
|
||||||
|
jobTitles: Object.values(Player.jobs),
|
||||||
mult: {
|
mult: {
|
||||||
agility: Player.agility_mult,
|
agility: Player.agility_mult,
|
||||||
agilityExp: Player.agility_exp_mult,
|
agilityExp: Player.agility_exp_mult,
|
||||||
@ -2968,16 +2970,20 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cost = Player.getUpgradeHomeRamCost();
|
// Check if we're at max RAM
|
||||||
|
const homeComputer = Player.getHomeComputer();
|
||||||
|
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
|
||||||
|
workerScript.log(`ERROR: upgradeHomeRam() failed because your home computer is at max RAM`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cost = Player.getUpgradeHomeRamCost();
|
||||||
if (Player.money.lt(cost)) {
|
if (Player.money.lt(cost)) {
|
||||||
workerScript.scriptRef.log("ERROR: upgradeHomeRam() failed because you don't have enough money");
|
workerScript.scriptRef.log("ERROR: upgradeHomeRam() failed because you don't have enough money");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var homeComputer = Player.getHomeComputer();
|
|
||||||
homeComputer.maxRam *= 2;
|
homeComputer.maxRam *= 2;
|
||||||
|
|
||||||
Player.loseMoney(cost);
|
Player.loseMoney(cost);
|
||||||
|
|
||||||
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
|
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
|
||||||
@ -3002,7 +3008,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
|
|
||||||
return Player.getUpgradeHomeRamCost();
|
return Player.getUpgradeHomeRamCost();
|
||||||
},
|
},
|
||||||
workForCompany : function() {
|
workForCompany : function(companyName) {
|
||||||
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
|
var ramCost = CONSTANTS.ScriptSingularityFn2RamCost;
|
||||||
if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
|
if (Player.bitNodeN !== 4) {ramCost *= CONSTANTS.ScriptSingularityFnRamMult;}
|
||||||
if (workerScript.checkingRam) {
|
if (workerScript.checkingRam) {
|
||||||
@ -3016,13 +3022,33 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inMission) {
|
// Sanitize input
|
||||||
workerScript.scriptRef.log("ERROR: workForCompany() failed because you are in the middle of a mission.");
|
if (companyName == null) {
|
||||||
return;
|
companyName = Player.companyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const companyPosition = CompanyPositions[Player.companyPosition];
|
// Make sure its a valid company
|
||||||
if (Player.companyPosition === "" || !(companyPosition instanceof CompanyPosition)) {
|
if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) {
|
||||||
|
workerScript.scriptRef.log(`ERROR: workForCompany() failed because of an invalid company specified: ${companyName}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure player is actually employed at the comapny
|
||||||
|
if (!Object.keys(Player.jobs).includes(companyName)) {
|
||||||
|
workerScript.scriptRef.log(`ERROR: workForCompany() failed because you do not have a job at ${companyName}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cant work while in a mission
|
||||||
|
if (inMission) {
|
||||||
|
workerScript.scriptRef.log("ERROR: workForCompany() failed because you are in the middle of a mission.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to make sure company position data is valid
|
||||||
|
const companyPositionName = Player.jobs[companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
|
if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) {
|
||||||
workerScript.scriptRef.log("ERROR: workForCompany() failed because you do not have a job");
|
workerScript.scriptRef.log("ERROR: workForCompany() failed because you do not have a job");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3035,12 +3061,12 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (companyPosition.isPartTimeJob()) {
|
if (companyPosition.isPartTimeJob()) {
|
||||||
Player.startWorkPartTime();
|
Player.startWorkPartTime(companyName);
|
||||||
} else {
|
} else {
|
||||||
Player.startWork();
|
Player.startWork(companyName);
|
||||||
}
|
}
|
||||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.workForCompany == null) {
|
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.workForCompany == null) {
|
||||||
workerScript.log(`Began working at ${Player.companyName} as a ${Player.companyPosition}`);
|
workerScript.log(`Began working at ${Player.companyName} as a ${companyPositionName}`);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -3116,7 +3142,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
if (res) {
|
if (res) {
|
||||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
|
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
|
||||||
workerScript.log(`You were offered a new job at ${companyName} as a ${Player.companyPosition}`);
|
workerScript.log(`You were offered a new job at ${companyName} as a ${Player.jobs[companyName]}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
|
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.applyToCompany == null) {
|
||||||
@ -3554,7 +3580,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.commitCrime == null) {
|
if(workerScript.disableLogs.ALL == null && workerScript.disableLogs.commitCrime == null) {
|
||||||
workerScript.scriptRef.log("Attempting to commit crime: "+crime.name+"...");
|
workerScript.scriptRef.log("Attempting to commit crime: "+crime.name+"...");
|
||||||
}
|
}
|
||||||
return crime.commit(1, {workerscript: workerScript});
|
return crime.commit(Player, 1, {workerscript: workerScript});
|
||||||
},
|
},
|
||||||
getCrimeChance : function(crimeRoughName) {
|
getCrimeChance : function(crimeRoughName) {
|
||||||
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
|
var ramCost = CONSTANTS.ScriptSingularityFn3RamCost;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {Settings} from "./Settings";
|
import {Settings} from "./Settings/Settings";
|
||||||
|
|
||||||
function NetscriptPort() {
|
function NetscriptPort() {
|
||||||
this.data = [];
|
this.data = [];
|
||||||
|
@ -12,7 +12,7 @@ import {NetscriptFunctions} from "./NetscriptFunctions";
|
|||||||
import {executeJSScript} from "./NetscriptJSEvaluator";
|
import {executeJSScript} from "./NetscriptJSEvaluator";
|
||||||
import {NetscriptPort} from "./NetscriptPort";
|
import {NetscriptPort} from "./NetscriptPort";
|
||||||
import {AllServers} from "./Server";
|
import {AllServers} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import {Settings} from "./Settings/Settings";
|
||||||
|
|
||||||
import {generate} from 'escodegen';
|
import {generate} from 'escodegen';
|
||||||
|
|
||||||
@ -347,6 +347,9 @@ function processNetscript1Imports(code, workerScript) {
|
|||||||
ImportDeclaration: (node) => {
|
ImportDeclaration: (node) => {
|
||||||
hasImports = true;
|
hasImports = true;
|
||||||
let scriptName = node.source.value;
|
let scriptName = node.source.value;
|
||||||
|
if (scriptName.startsWith("./")) {
|
||||||
|
scriptName = scriptName.slice(2);
|
||||||
|
}
|
||||||
let script = getScript(scriptName);
|
let script = getScript(scriptName);
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
throw new Error("'Import' failed due to invalid script: " + scriptName);
|
throw new Error("'Import' failed due to invalid script: " + scriptName);
|
||||||
@ -496,19 +499,6 @@ function runScriptsLoop() {
|
|||||||
} else {
|
} else {
|
||||||
p = startNetscript1Script(workerScripts[i]);
|
p = startNetscript1Script(workerScripts[i]);
|
||||||
if (!(p instanceof Promise)) {continue;}
|
if (!(p instanceof Promise)) {continue;}
|
||||||
/*
|
|
||||||
try {
|
|
||||||
var ast = parse(workerScripts[i].code, {sourceType:"module"});
|
|
||||||
//console.log(ast);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error parsing script: " + workerScripts[i].name);
|
|
||||||
dialogBoxCreate("Syntax ERROR in " + workerScripts[i].name + ":<br>" + e);
|
|
||||||
workerScripts[i].env.stopFlag = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
workerScripts[i].running = true;
|
|
||||||
p = evaluate(ast, workerScripts[i]);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Once the code finishes (either resolved or rejected, doesnt matter), set its
|
//Once the code finishes (either resolved or rejected, doesnt matter), set its
|
||||||
@ -521,7 +511,7 @@ function runScriptsLoop() {
|
|||||||
}).catch(function(w) {
|
}).catch(function(w) {
|
||||||
if (w instanceof Error) {
|
if (w instanceof Error) {
|
||||||
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
|
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
|
||||||
console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + w.toString());
|
console.error("Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + w.toString());
|
||||||
return;
|
return;
|
||||||
} else if (w.constructor === Array && w.length === 2 && w[0] === "RETURNSTATEMENT") {
|
} else if (w.constructor === Array && w.length === 2 && w[0] === "RETURNSTATEMENT") {
|
||||||
//Script ends with a return statement
|
//Script ends with a return statement
|
||||||
|
74
src/PersonObjects/IPlayer.ts
Normal file
74
src/PersonObjects/IPlayer.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Interface for an object that represents the player (PlayerObject)
|
||||||
|
// Used because at the time of implementation, the PlayerObject
|
||||||
|
// cant be converted to TypeScript.
|
||||||
|
//
|
||||||
|
// Only contains the needed properties for Sleeve implementation
|
||||||
|
import { Resleeve } from "./Resleeving/Resleeve";
|
||||||
|
import { Sleeve } from "./Sleeve/Sleeve";
|
||||||
|
|
||||||
|
import { IMap } from "../types";
|
||||||
|
|
||||||
|
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||||
|
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
|
||||||
|
|
||||||
|
export interface IPlayer {
|
||||||
|
// Class members
|
||||||
|
augmentations: IPlayerOwnedAugmentation[];
|
||||||
|
bladeburner: any;
|
||||||
|
companyName: string;
|
||||||
|
corporation: any;
|
||||||
|
factions: string[];
|
||||||
|
hasWseAccount: boolean;
|
||||||
|
jobs: IMap<string>;
|
||||||
|
money: any;
|
||||||
|
queuedAugmentations: IPlayerOwnedAugmentation[];
|
||||||
|
resleeves: Resleeve[];
|
||||||
|
sleeves: Sleeve[];
|
||||||
|
sourceFiles: IPlayerOwnedSourceFile[];
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
hacking_skill: number;
|
||||||
|
strength: number;
|
||||||
|
defense: number;
|
||||||
|
dexterity: number;
|
||||||
|
agility: number;
|
||||||
|
charisma: number;
|
||||||
|
intelligence: number;
|
||||||
|
|
||||||
|
// Experience
|
||||||
|
hacking_exp: number;
|
||||||
|
strength_exp: number;
|
||||||
|
defense_exp: number;
|
||||||
|
dexterity_exp: number;
|
||||||
|
agility_exp: number;
|
||||||
|
charisma_exp: number;
|
||||||
|
|
||||||
|
// Multipliers
|
||||||
|
crime_success_mult: number;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
canAfford(cost: number): boolean;
|
||||||
|
gainHackingExp(exp: number): void;
|
||||||
|
gainStrengthExp(exp: number): void;
|
||||||
|
gainDefenseExp(exp: number): void;
|
||||||
|
gainDexterityExp(exp: number): void;
|
||||||
|
gainAgilityExp(exp: number): void;
|
||||||
|
gainCharismaExp(exp: number): void;
|
||||||
|
gainMoney(money: number): void;
|
||||||
|
hasCorporation(): boolean;
|
||||||
|
inBladeburner(): boolean;
|
||||||
|
inGang(): boolean;
|
||||||
|
loseMoney(money: number): void;
|
||||||
|
reapplyAllAugmentations(resetMultipliers: boolean): void;
|
||||||
|
reapplyAllSourceFiles(): void;
|
||||||
|
startCrime(crimeType: string,
|
||||||
|
hackExp: number,
|
||||||
|
strExp: number,
|
||||||
|
defExp: number,
|
||||||
|
dexExp: number,
|
||||||
|
agiExp: number,
|
||||||
|
chaExp: number,
|
||||||
|
money: number,
|
||||||
|
time: number,
|
||||||
|
singParams: any): void;
|
||||||
|
}
|
@ -1,63 +1,11 @@
|
|||||||
// Base class representing a person-like object
|
// Base class representing a person-like object
|
||||||
import { BitNodeMultipliers } from "../BitNodeMultipliers";
|
import { Augmentation } from "../Augmentation/Augmentation";
|
||||||
|
import { Augmentations } from "../Augmentation/Augmentations";
|
||||||
|
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||||
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
import { Cities } from "../Locations/Cities";
|
import { Cities } from "../Locations/Cities";
|
||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { IMap } from "../types";
|
||||||
// Interface for an object that represents the player (PlayerObject)
|
|
||||||
// Used because at the time of implementation, the PlayerObject
|
|
||||||
// cant be converted to TypeScript.
|
|
||||||
//
|
|
||||||
// Only contains the needed properties for Sleeve implementation
|
|
||||||
export interface IPlayer {
|
|
||||||
companyName: string;
|
|
||||||
factions: string[];
|
|
||||||
money: any;
|
|
||||||
gainHackingExp(exp: number): void;
|
|
||||||
gainStrengthExp(exp: number): void;
|
|
||||||
gainDefenseExp(exp: number): void;
|
|
||||||
gainDexterityExp(exp: number): void;
|
|
||||||
gainAgilityExp(exp: number): void;
|
|
||||||
gainCharismaExp(exp: number): void;
|
|
||||||
gainMoney(money: number): void;
|
|
||||||
loseMoney(money: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface for a Crime object
|
|
||||||
// Used because at the time of implementation, the Crime object has not been converted
|
|
||||||
// to Typescript
|
|
||||||
export interface ICrime {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
time: number;
|
|
||||||
money: number;
|
|
||||||
difficulty: number;
|
|
||||||
karma: number;
|
|
||||||
|
|
||||||
hacking_success_weight: number;
|
|
||||||
strength_success_weight: number;
|
|
||||||
defense_success_weight: number;
|
|
||||||
dexterity_success_weight: number;
|
|
||||||
agility_success_weight: number;
|
|
||||||
charisma_success_weight: number;
|
|
||||||
|
|
||||||
hacking_exp: number;
|
|
||||||
strength_exp: number;
|
|
||||||
defense_exp: number;
|
|
||||||
dexterity_exp: number;
|
|
||||||
agility_exp: number;
|
|
||||||
charisma_exp: number;
|
|
||||||
intelligence_exp: number;
|
|
||||||
|
|
||||||
kills: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface for Faction object
|
|
||||||
// Used because at the time of implementation, the Faction object has not been
|
|
||||||
// converted to TypeScript
|
|
||||||
export interface IFaction {
|
|
||||||
name: string;
|
|
||||||
playerReputation: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface that defines a generic object used to track experience/money
|
// Interface that defines a generic object used to track experience/money
|
||||||
// earnings for tasks
|
// earnings for tasks
|
||||||
@ -87,95 +35,91 @@ export abstract class Person {
|
|||||||
/**
|
/**
|
||||||
* Stats
|
* Stats
|
||||||
*/
|
*/
|
||||||
hacking_skill: number;
|
hacking_skill: number = 1;
|
||||||
strength: number;
|
strength: number = 1;
|
||||||
defense: number;
|
defense: number = 1;
|
||||||
dexterity: number;
|
dexterity: number = 1;
|
||||||
agility: number;
|
agility: number = 1;
|
||||||
charisma: number;
|
charisma: number = 1;
|
||||||
hp: number;
|
hp: number = 10;
|
||||||
max_hp: number;
|
max_hp: number = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Experience
|
||||||
|
*/
|
||||||
|
hacking_exp: number = 0;
|
||||||
|
strength_exp: number = 0;
|
||||||
|
defense_exp: number = 0;
|
||||||
|
dexterity_exp: number = 0;
|
||||||
|
agility_exp: number = 0;
|
||||||
|
charisma_exp: number = 0;
|
||||||
|
intelligence_exp: number = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multipliers
|
* Multipliers
|
||||||
*/
|
*/
|
||||||
hacking_exp: number;
|
hacking_mult: number = 1;
|
||||||
strength_exp: number;
|
strength_mult: number = 1;
|
||||||
defense_exp: number;
|
defense_mult: number = 1;
|
||||||
dexterity_exp: number;
|
dexterity_mult: number = 1;
|
||||||
agility_exp: number;
|
agility_mult: number = 1;
|
||||||
charisma_exp: number;
|
charisma_mult: number = 1;
|
||||||
intelligence_exp: number;
|
|
||||||
|
|
||||||
hacking_mult: number;
|
hacking_exp_mult: number = 1;
|
||||||
strength_mult: number;
|
strength_exp_mult: number = 1;
|
||||||
defense_mult: number;
|
defense_exp_mult: number = 1;
|
||||||
dexterity_mult: number;
|
dexterity_exp_mult: number = 1;
|
||||||
agility_mult: number;
|
agility_exp_mult: number = 1;
|
||||||
charisma_mult: number;
|
charisma_exp_mult: number = 1;
|
||||||
|
|
||||||
hacking_exp_mult: number;
|
hacking_chance_mult: number = 1;
|
||||||
strength_exp_mult: number;
|
hacking_speed_mult: number = 1;
|
||||||
defense_exp_mult: number;
|
hacking_money_mult: number = 1;
|
||||||
dexterity_exp_mult: number;
|
hacking_grow_mult: number = 1;
|
||||||
agility_exp_mult: number;
|
|
||||||
charisma_exp_mult: number;
|
|
||||||
|
|
||||||
company_rep_mult: number;
|
company_rep_mult: number = 1;
|
||||||
faction_rep_mult: number;
|
faction_rep_mult: number = 1;
|
||||||
|
|
||||||
crime_money_mult: number;
|
crime_money_mult: number = 1;
|
||||||
crime_success_mult: number;
|
crime_success_mult: number = 1;
|
||||||
|
|
||||||
work_money_mult: number;
|
work_money_mult: number = 1;
|
||||||
|
|
||||||
|
hacknet_node_money_mult: number = 1;
|
||||||
|
hacknet_node_purchase_cost_mult: number = 1;
|
||||||
|
hacknet_node_ram_cost_mult: number = 1;
|
||||||
|
hacknet_node_core_cost_mult: number = 1;
|
||||||
|
hacknet_node_level_cost_mult: number = 1;
|
||||||
|
|
||||||
|
bladeburner_max_stamina_mult: number = 1;
|
||||||
|
bladeburner_stamina_gain_mult: number = 1;
|
||||||
|
bladeburner_analysis_mult: number = 1;
|
||||||
|
bladeburner_success_chance_mult : number = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Augmentations
|
||||||
|
*/
|
||||||
|
augmentations: IPlayerOwnedAugmentation[] = [];
|
||||||
|
queuedAugmentations: IPlayerOwnedAugmentation[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* City that the person is in
|
* City that the person is in
|
||||||
*/
|
*/
|
||||||
city: string;
|
city: string = Cities.Sector12;
|
||||||
|
|
||||||
constructor() {
|
constructor() {}
|
||||||
this.hacking_skill = 1;
|
|
||||||
this.strength = 1;
|
|
||||||
this.defense = 1;
|
|
||||||
this.dexterity = 1;
|
|
||||||
this.agility = 1;
|
|
||||||
this.charisma = 1;
|
|
||||||
this.hp = 10;
|
|
||||||
this.max_hp = 10;
|
|
||||||
|
|
||||||
// Multipliers
|
/**
|
||||||
this.hacking_exp = 0;
|
* Updates this object's multipliers for the given augmentation
|
||||||
this.strength_exp = 0;
|
*/
|
||||||
this.defense_exp = 0;
|
applyAugmentation(aug: Augmentation) {
|
||||||
this.dexterity_exp = 0;
|
for (const mult in aug.mults) {
|
||||||
this.agility_exp = 0;
|
if ((<any>this)[mult] == null) {
|
||||||
this.charisma_exp = 0;
|
console.warn(`Augmentation has unrecognized multiplier property: ${mult}`);
|
||||||
this.intelligence_exp = 0;
|
} else {
|
||||||
|
(<any>this)[mult] *= aug.mults[mult];
|
||||||
this.hacking_mult = 1;
|
}
|
||||||
this.strength_mult = 1;
|
}
|
||||||
this.defense_mult = 1;
|
|
||||||
this.dexterity_mult = 1;
|
|
||||||
this.agility_mult = 1;
|
|
||||||
this.charisma_mult = 1;
|
|
||||||
|
|
||||||
this.hacking_exp_mult = 1;
|
|
||||||
this.strength_exp_mult = 1;
|
|
||||||
this.defense_exp_mult = 1;
|
|
||||||
this.dexterity_exp_mult = 1;
|
|
||||||
this.agility_exp_mult = 1;
|
|
||||||
this.charisma_exp_mult = 1;
|
|
||||||
|
|
||||||
this.company_rep_mult = 1;
|
|
||||||
this.faction_rep_mult = 1;
|
|
||||||
|
|
||||||
this.crime_money_mult = 1;
|
|
||||||
this.crime_success_mult = 1;
|
|
||||||
|
|
||||||
this.work_money_mult = 1;
|
|
||||||
|
|
||||||
this.city = Cities.Sector12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -255,11 +199,11 @@ export abstract class Person {
|
|||||||
*/
|
*/
|
||||||
updateStatLevels(): void {
|
updateStatLevels(): void {
|
||||||
this.hacking_skill = Math.max(1, Math.floor(this.calculateStat(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
|
this.hacking_skill = Math.max(1, Math.floor(this.calculateStat(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
|
||||||
this.strength = Math.max(1, Math.floor(this.calculateStat(this.strength_exp, this.strength_mult)));
|
this.strength = Math.max(1, Math.floor(this.calculateStat(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier)));
|
||||||
this.defense = Math.max(1, Math.floor(this.calculateStat(this.defense_exp, this.defense_mult)));
|
this.defense = Math.max(1, Math.floor(this.calculateStat(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier)));
|
||||||
this.dexterity = Math.max(1, Math.floor(this.calculateStat(this.dexterity_exp, this.dexterity_mult)));
|
this.dexterity = Math.max(1, Math.floor(this.calculateStat(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier)));
|
||||||
this.agility = Math.max(1, Math.floor(this.calculateStat(this.agility_exp, this.agility_mult)));
|
this.agility = Math.max(1, Math.floor(this.calculateStat(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier)));
|
||||||
this.charisma = Math.max(1, Math.floor(this.calculateStat(this.charisma_exp, this.charisma_mult)));
|
this.charisma = Math.max(1, Math.floor(this.calculateStat(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier)));
|
||||||
|
|
||||||
const ratio: number = this.hp / this.max_hp;
|
const ratio: number = this.hp / this.max_hp;
|
||||||
this.max_hp = Math.floor(10 + this.defense / 10);
|
this.max_hp = Math.floor(10 + this.defense / 10);
|
||||||
|
10
src/PersonObjects/Resleeving/README.md
Normal file
10
src/PersonObjects/Resleeving/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Implements the Re-sleeving feature, which allows players to purchase a new body
|
||||||
|
that comes with pre-existing Augmentations and experience. Note that purchasing
|
||||||
|
a new body causes you to lose all of your old Augmentations and experience
|
||||||
|
|
||||||
|
This feature is introduced in BitNode-10, and destroying BitNode-10 allows
|
||||||
|
the user to use it in other BitNodes (provided that they purchase the required
|
||||||
|
cortical stack Augmentation)
|
||||||
|
|
||||||
|
While they are based on the same concept, this feature is different than the
|
||||||
|
"Duplicate Sleeve" mechanic (which is referred to as just "Sleeve" in the source code).
|
61
src/PersonObjects/Resleeving/Resleeve.ts
Normal file
61
src/PersonObjects/Resleeving/Resleeve.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Implements the Resleeve class, which defines a new body
|
||||||
|
* that the player can "re-sleeve" into.
|
||||||
|
*/
|
||||||
|
import { Person } from "../Person";
|
||||||
|
|
||||||
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||||
|
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||||
|
|
||||||
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
|
||||||
|
|
||||||
|
export class Resleeve extends Person {
|
||||||
|
/**
|
||||||
|
* Initiatizes a Resleeve object from a JSON save state.
|
||||||
|
*/
|
||||||
|
static fromJSON(value: any): Resleeve {
|
||||||
|
return Generic_fromJSON(Resleeve, value.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
getCost(): number {
|
||||||
|
// Each experience point adds this to the cost
|
||||||
|
const CostPerExp: number = 25e3;
|
||||||
|
|
||||||
|
// Final cost is multiplied by this constant ^ # Augs
|
||||||
|
const NumAugsExponent: number = 1.2;
|
||||||
|
|
||||||
|
// Get total exp in this re-sleeve
|
||||||
|
let totalExp: number = this.hacking_exp +
|
||||||
|
this.strength_exp +
|
||||||
|
this.defense_exp +
|
||||||
|
this.dexterity_exp +
|
||||||
|
this.agility_exp +
|
||||||
|
this.charisma_exp;
|
||||||
|
|
||||||
|
// Get total base Augmentation cost for this re-sleeve
|
||||||
|
let totalAugmentationCost: number = 0;
|
||||||
|
for (let i = 0; i < this.augmentations.length; ++i) {
|
||||||
|
const aug: Augmentation | null = Augmentations[this.augmentations[i].name];
|
||||||
|
if (aug == null) {
|
||||||
|
console.error(`Could not find Augmentation ${this.augmentations[i].name}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
totalAugmentationCost += aug!.baseCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(NumAugsExponent, this.augmentations.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the current object to a JSON save state.
|
||||||
|
*/
|
||||||
|
toJSON(): any {
|
||||||
|
return Generic_toJSON("Resleeve", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reviver.constructors.Resleeve = Resleeve;
|
120
src/PersonObjects/Resleeving/Resleeving.ts
Normal file
120
src/PersonObjects/Resleeving/Resleeving.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* Implements the Re-sleeving mechanic for BitNode-10.
|
||||||
|
* This allows the player to purchase and "use" new sleeves at VitaLife.
|
||||||
|
* These new sleeves come with different starting experience and Augmentations
|
||||||
|
* The cost of these new sleeves scales based on the exp and Augs.
|
||||||
|
*
|
||||||
|
* Note that this is different from the "Sleeve mechanic". The "Sleeve" mechanic
|
||||||
|
* provides new sleeves, essentially clones. This Re-sleeving mechanic lets
|
||||||
|
* the player purchase a new body with pre-existing Augmentations and experience
|
||||||
|
*
|
||||||
|
* As of right now, this feature is only available in BitNode 10
|
||||||
|
*/
|
||||||
|
import { Resleeve } from "./Resleeve";
|
||||||
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||||
|
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||||
|
import { IPlayerOwnedAugmentation,
|
||||||
|
PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
|
||||||
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
|
|
||||||
|
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
|
||||||
|
|
||||||
|
|
||||||
|
// Executes the actual re-sleeve when one is purchased
|
||||||
|
export function purchaseResleeve(r: Resleeve, p: IPlayer): boolean {
|
||||||
|
const cost: number = r.getCost();
|
||||||
|
if (!p.canAfford(cost)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
p.loseMoney(cost);
|
||||||
|
|
||||||
|
// Set the player's exp
|
||||||
|
p.hacking_exp = r.hacking_exp;
|
||||||
|
p.strength_exp = r.strength_exp;
|
||||||
|
p.defense_exp = r.defense_exp;
|
||||||
|
p.dexterity_exp = r.dexterity_exp;
|
||||||
|
p.agility_exp = r.agility_exp;
|
||||||
|
p.charisma_exp = r.charisma_exp;
|
||||||
|
|
||||||
|
// Reset Augmentation "owned" data
|
||||||
|
for (const augKey in Augmentations) {
|
||||||
|
Augmentations[augKey].owned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all of the player's augmentations, except the NeuroFlux Governor
|
||||||
|
// which is kept
|
||||||
|
for (let i = p.augmentations.length - 1; i >= 0; --i) {
|
||||||
|
if (p.augmentations[i].name !== AugmentationNames.NeuroFluxGovernor) {
|
||||||
|
p.augmentations.splice(i, 1);
|
||||||
|
} else {
|
||||||
|
// NeuroFlux Governor
|
||||||
|
Augmentations[AugmentationNames.NeuroFluxGovernor].owned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < r.augmentations.length; ++i) {
|
||||||
|
p.augmentations.push(new PlayerOwnedAugmentation(r.augmentations[i].name));
|
||||||
|
Augmentations[r.augmentations[i].name].owned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The player's purchased Augmentations should remain the same, but any purchased
|
||||||
|
// Augmentations that are given by the resleeve should be removed so there are no duplicates
|
||||||
|
for (let i = p.queuedAugmentations.length - 1; i >= 0; --i) {
|
||||||
|
const name: string = p.queuedAugmentations[i].name;
|
||||||
|
|
||||||
|
if (p.augmentations.filter((e: IPlayerOwnedAugmentation) => {return e.name !== AugmentationNames.NeuroFluxGovernor && e.name === name}).length >= 1) {
|
||||||
|
p.queuedAugmentations.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.reapplyAllAugmentations(true);
|
||||||
|
p.reapplyAllSourceFiles(); //Multipliers get reset, so have to re-process source files too
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates all of the Re-sleeves that will be available for purchase at VitaLife
|
||||||
|
export function generateResleeves(): Resleeve[] {
|
||||||
|
const NumResleeves: number = 40; // Total number of Resleeves to generate
|
||||||
|
|
||||||
|
let ret: Resleeve[] = [];
|
||||||
|
for (let i = 0; i < NumResleeves; ++i) {
|
||||||
|
// i will be a number indicating how "powerful" the Re-sleeve should be
|
||||||
|
let r: Resleeve = new Resleeve();
|
||||||
|
|
||||||
|
// Generate experience
|
||||||
|
const expMult: number = (5 * i) + 1;
|
||||||
|
r.hacking_exp = expMult * getRandomInt(1000, 5000);
|
||||||
|
r.strength_exp = expMult * getRandomInt(1000, 5000);
|
||||||
|
r.defense_exp = expMult * getRandomInt(1000, 5000);
|
||||||
|
r.dexterity_exp = expMult * getRandomInt(1000, 5000);
|
||||||
|
r.agility_exp = expMult * getRandomInt(1000, 5000);
|
||||||
|
r.charisma_exp = expMult * getRandomInt(1000, 5000);
|
||||||
|
|
||||||
|
// Generate Augs
|
||||||
|
// Augmentation prequisites will be ignored for this
|
||||||
|
const baseNumAugs: number = Math.max(2, Math.ceil((i + 3) / 2));
|
||||||
|
const numAugs: number = getRandomInt(baseNumAugs, baseNumAugs + 2);
|
||||||
|
const augKeys: string[] = Object.keys(Augmentations);
|
||||||
|
for (let a = 0; a < numAugs; ++a) {
|
||||||
|
// Get a random aug
|
||||||
|
const randIndex: number = getRandomInt(0, augKeys.length - 1)
|
||||||
|
const randKey: string = augKeys[randIndex];
|
||||||
|
if (randKey === AugmentationNames.TheRedPill) {
|
||||||
|
continue; // A sleeve can't have The Red Pill
|
||||||
|
}
|
||||||
|
const randAug: Augmentation | null = Augmentations[randKey];
|
||||||
|
r.augmentations.push({name: randAug!.name, level: 1});
|
||||||
|
r.applyAugmentation(Augmentations[randKey]);
|
||||||
|
r.updateStatLevels();
|
||||||
|
|
||||||
|
// Remove Augmentation so that there are no duplicates
|
||||||
|
augKeys.splice(randIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.push(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
360
src/PersonObjects/Resleeving/ResleevingUI.ts
Normal file
360
src/PersonObjects/Resleeving/ResleevingUI.ts
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
/**
|
||||||
|
* Module for handling the Re-sleeving UI
|
||||||
|
*/
|
||||||
|
import { Resleeve } from "./Resleeve";
|
||||||
|
import { generateResleeves,
|
||||||
|
purchaseResleeve } from "./Resleeving";
|
||||||
|
|
||||||
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||||
|
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
import { Page,
|
||||||
|
routing } from "../../ui/navigationTracking";
|
||||||
|
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
|
||||||
|
import { exceptionAlert } from "../../../utils/helpers/exceptionAlert";
|
||||||
|
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
|
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||||
|
|
||||||
|
interface IResleeveUIElems {
|
||||||
|
container: HTMLElement | null;
|
||||||
|
statsPanel: HTMLElement | null;
|
||||||
|
stats: HTMLElement | null;
|
||||||
|
multipliersButton: HTMLElement | null;
|
||||||
|
augPanel: HTMLElement | null;
|
||||||
|
augSelector: HTMLSelectElement | null;
|
||||||
|
augDescription: HTMLElement | null;
|
||||||
|
costPanel: HTMLElement | null;
|
||||||
|
costText: HTMLElement | null;
|
||||||
|
buyButton: HTMLElement | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IPageUIElems {
|
||||||
|
container: HTMLElement | null;
|
||||||
|
info: HTMLElement | null;
|
||||||
|
sortTag: HTMLElement | null;
|
||||||
|
sortSelector: HTMLSelectElement | null;
|
||||||
|
resleeveList: HTMLElement | null;
|
||||||
|
resleeves: IResleeveUIElems[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIElems: IPageUIElems = {
|
||||||
|
container: null,
|
||||||
|
info: null,
|
||||||
|
sortTag: null,
|
||||||
|
sortSelector: null,
|
||||||
|
resleeveList: null,
|
||||||
|
resleeves: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
let playerRef: IPlayer | null;
|
||||||
|
|
||||||
|
export function createResleevesPage(p: IPlayer) {
|
||||||
|
if (!routing.isOn(Page.Resleeves)) { return; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
playerRef = p;
|
||||||
|
|
||||||
|
UIElems.container = createElement("div", {
|
||||||
|
class: "generic-menupage-container",
|
||||||
|
id: "resleeves-container",
|
||||||
|
position: "fixed",
|
||||||
|
});
|
||||||
|
|
||||||
|
UIElems.info = createElement("p", {
|
||||||
|
display: "block",
|
||||||
|
innerHTML: "Re-sleeving is the process of digitizing and transferring your consciousness " +
|
||||||
|
"into a new human body, or 'sleeve'. Here at VitaLife, you can purchase new " +
|
||||||
|
"specially-engineered bodies for the re-sleeve process. Many of these bodies " +
|
||||||
|
"even come with genetic and cybernetic Augmentations!<br><br>" +
|
||||||
|
"Re-sleeving will change your experience for every stat. It will also REMOVE " +
|
||||||
|
"all of your currently-installed Augmentations, and replace " +
|
||||||
|
"them with the ones provided by the purchased sleeve. However, Augmentations that you have " +
|
||||||
|
"purchased but not installed will NOT be removed. If you have purchased an " +
|
||||||
|
"Augmentation and then re-sleeve into a body which already has that Augmentation, " +
|
||||||
|
"it will be removed (since you cannot have duplicate Augmentations).<br><br>" +
|
||||||
|
"NOTE: The stats and multipliers displayed on this page do NOT include your bonuses from " +
|
||||||
|
"Source-File.",
|
||||||
|
width: "75%",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Randomly create all Resleeves if they dont already exist
|
||||||
|
if (p.resleeves.length === 0) {
|
||||||
|
p.resleeves = generateResleeves();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a selector for sorting the list of Resleeves
|
||||||
|
UIElems.sortTag = createElement("p", {
|
||||||
|
display: "inline-block",
|
||||||
|
innerText: "Sort By: "
|
||||||
|
});
|
||||||
|
UIElems.sortSelector = createElement("select") as HTMLSelectElement;
|
||||||
|
|
||||||
|
enum SortOption {
|
||||||
|
Cost = "Cost",
|
||||||
|
Hacking = "Hacking",
|
||||||
|
Strength = "Strength",
|
||||||
|
Defense = "Defense",
|
||||||
|
Dexterity = "Dexterity",
|
||||||
|
Agility = "Agility",
|
||||||
|
Charisma = "Charisma",
|
||||||
|
AverageCombatStats = "AverageCombat",
|
||||||
|
AverageAllStats = "AverageAllStats",
|
||||||
|
TotalNumAugmentations = "TotalNumAugmentations",
|
||||||
|
}
|
||||||
|
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Cost", SortOption.Cost));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Hacking Level", SortOption.Hacking));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Strength Level", SortOption.Strength));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Defense Level", SortOption.Defense));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Dexterity Level", SortOption.Dexterity));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Agility Level", SortOption.Agility));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Charisma Level", SortOption.Charisma));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Average Combat Stats", SortOption.AverageCombatStats));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Average Stats", SortOption.AverageAllStats));
|
||||||
|
UIElems.sortSelector!.add(createOptionElement("Number of Augmentations", SortOption.TotalNumAugmentations));
|
||||||
|
|
||||||
|
UIElems.resleeveList = createElement("ul");
|
||||||
|
UIElems.sortSelector!.onchange = () => {
|
||||||
|
removeChildrenFromElement(UIElems.resleeveList);
|
||||||
|
UIElems.resleeves = [];
|
||||||
|
|
||||||
|
// Helper function for averaging
|
||||||
|
function getAverage(...values: number[]) {
|
||||||
|
let sum: number = 0;
|
||||||
|
for (let i = 0; i < values.length; ++i) {
|
||||||
|
sum += values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / values.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortOpt = getSelectValue(UIElems.sortSelector!);
|
||||||
|
switch (sortOpt) {
|
||||||
|
case SortOption.Hacking:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.hacking_skill - b.hacking_skill;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.Strength:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.strength - b.strength;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.Defense:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.defense - b.defense;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.Dexterity:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.dexterity - b.dexterity;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.Agility:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.agility - b.agility;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.Charisma:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.charisma - b.charisma;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.AverageCombatStats:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
let aAvg = getAverage(a.strength, a.defense, a.dexterity, a.agility);
|
||||||
|
let bAvg = getAverage(b.strength, b.defense, b.dexterity, b.agility);
|
||||||
|
|
||||||
|
return aAvg - bAvg;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.AverageAllStats:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
let aAvg = getAverage(a.hacking_skill, a.strength, a.defense, a.dexterity, a.agility, a.charisma);
|
||||||
|
let bAvg = getAverage(b.hacking_skill, b.strength, b.defense, b.dexterity, b.agility, b.charisma);
|
||||||
|
|
||||||
|
return aAvg - bAvg;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.TotalNumAugmentations:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.augmentations.length - b.augmentations.length;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SortOption.Cost:
|
||||||
|
default:
|
||||||
|
p.resleeves.sort((a, b) => {
|
||||||
|
return a.getCost() - b.getCost();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create UI for all Resleeves
|
||||||
|
for (const resleeve of p.resleeves) {
|
||||||
|
const resleeveUi = createResleeveUi(resleeve);
|
||||||
|
UIElems.resleeveList!.appendChild(resleeveUi.container!);
|
||||||
|
UIElems.resleeves!.push(resleeveUi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UIElems.sortSelector!.dispatchEvent(new Event('change')); // Force onchange event
|
||||||
|
|
||||||
|
UIElems.container.appendChild(UIElems.info);
|
||||||
|
UIElems.container.appendChild(createElement("br"));
|
||||||
|
UIElems.container.appendChild(UIElems.sortTag);
|
||||||
|
UIElems.container.appendChild(UIElems.sortSelector);
|
||||||
|
UIElems.container.appendChild(UIElems.resleeveList);
|
||||||
|
|
||||||
|
document.getElementById("entire-game-container")!.appendChild(UIElems.container);
|
||||||
|
} catch(e) {
|
||||||
|
exceptionAlert(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearResleevesPage() {
|
||||||
|
if (UIElems.container instanceof HTMLElement) {
|
||||||
|
removeElement(UIElems.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const prop in UIElems) {
|
||||||
|
(<any>UIElems)[prop] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerRef = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createResleeveUi(resleeve: Resleeve): IResleeveUIElems {
|
||||||
|
const elems: IResleeveUIElems = {
|
||||||
|
container: null,
|
||||||
|
statsPanel: null,
|
||||||
|
stats: null,
|
||||||
|
multipliersButton: null,
|
||||||
|
augPanel: null,
|
||||||
|
augSelector: null,
|
||||||
|
augDescription: null,
|
||||||
|
costPanel: null,
|
||||||
|
costText: null,
|
||||||
|
buyButton: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!routing.isOn(Page.Resleeves)) { return elems; }
|
||||||
|
|
||||||
|
elems.container = createElement("div", {
|
||||||
|
class: "resleeve-container",
|
||||||
|
display: "block",
|
||||||
|
});
|
||||||
|
|
||||||
|
elems.statsPanel = createElement("div", { class: "resleeve-panel", width: "30%" });
|
||||||
|
elems.stats = createElement("p", {
|
||||||
|
class: "resleeve-stats-text",
|
||||||
|
innerHTML:
|
||||||
|
`Hacking: ${numeralWrapper.format(resleeve.hacking_skill, "0,0")} (${numeralWrapper.formatBigNumber(resleeve.hacking_exp)} exp)<br>` +
|
||||||
|
`Strength: ${numeralWrapper.format(resleeve.strength, "0,0")} (${numeralWrapper.formatBigNumber(resleeve.strength_exp)} exp)<br>` +
|
||||||
|
`Defense: ${numeralWrapper.format(resleeve.defense, "0,0")} (${numeralWrapper.formatBigNumber(resleeve.defense_exp)} exp)<br>` +
|
||||||
|
`Dexterity: ${numeralWrapper.format(resleeve.dexterity, "0,0")} (${numeralWrapper.formatBigNumber(resleeve.dexterity_exp)} exp)<br>` +
|
||||||
|
`Agility: ${numeralWrapper.format(resleeve.agility, "0,0")} (${numeralWrapper.formatBigNumber(resleeve.agility_exp)} exp)<br>` +
|
||||||
|
`Charisma: ${numeralWrapper.format(resleeve.charisma, "0,0")} (${numeralWrapper.formatBigNumber(resleeve.charisma_exp)} exp)<br>` +
|
||||||
|
`# Augmentations: ${resleeve.augmentations.length}`,
|
||||||
|
});
|
||||||
|
elems.multipliersButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "Multipliers",
|
||||||
|
clickListener: () => {
|
||||||
|
dialogBoxCreate(
|
||||||
|
[
|
||||||
|
"<h2><u>Total Multipliers:</u></h2>",
|
||||||
|
`Hacking Level multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_mult)}`,
|
||||||
|
`Hacking Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_exp_mult)}`,
|
||||||
|
`Strength Level multiplier: ${numeralWrapper.formatPercentage(resleeve.strength_mult)}`,
|
||||||
|
`Strength Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.strength_exp_mult)}`,
|
||||||
|
`Defense Level multiplier: ${numeralWrapper.formatPercentage(resleeve.defense_mult)}`,
|
||||||
|
`Defense Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.defense_exp_mult)}`,
|
||||||
|
`Dexterity Level multiplier: ${numeralWrapper.formatPercentage(resleeve.dexterity_mult)}`,
|
||||||
|
`Dexterity Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.dexterity_exp_mult)}`,
|
||||||
|
`Agility Level multiplier: ${numeralWrapper.formatPercentage(resleeve.agility_mult)}`,
|
||||||
|
`Agility Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.agility_exp_mult)}`,
|
||||||
|
`Charisma Level multiplier: ${numeralWrapper.formatPercentage(resleeve.charisma_mult)}`,
|
||||||
|
`Charisma Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.charisma_exp_mult)}`,
|
||||||
|
`Hacking Chance multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_chance_mult)}`,
|
||||||
|
`Hacking Speed multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_speed_mult)}`,
|
||||||
|
`Hacking Money multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_money_mult)}`,
|
||||||
|
`Hacking Growth multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_grow_mult)}`,
|
||||||
|
`Salary multiplier: ${numeralWrapper.formatPercentage(resleeve.work_money_mult)}`,
|
||||||
|
`Company Reputation Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.company_rep_mult)}`,
|
||||||
|
`Faction Reputation Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.faction_rep_mult)}`,
|
||||||
|
`Crime Money multiplier: ${numeralWrapper.formatPercentage(resleeve.crime_money_mult)}`,
|
||||||
|
`Crime Success multiplier: ${numeralWrapper.formatPercentage(resleeve.crime_success_mult)}`,
|
||||||
|
`Hacknet Income multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_money_mult)}`,
|
||||||
|
`Hacknet Purchase Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_purchase_cost_mult)}`,
|
||||||
|
`Hacknet Level Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_level_cost_mult)}`,
|
||||||
|
`Hacknet Ram Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_ram_cost_mult)}`,
|
||||||
|
`Hacknet Core Upgrade Cost multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_core_cost_mult)}`,
|
||||||
|
`Bladeburner Max Stamina multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_max_stamina_mult)}`,
|
||||||
|
`Bladeburner Stamina Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_stamina_gain_mult)}`,
|
||||||
|
`Bladeburner Field Analysis multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_analysis_mult)}`,
|
||||||
|
`Bladeburner Success Chance multiplier: ${numeralWrapper.formatPercentage(resleeve.bladeburner_success_chance_mult)}`
|
||||||
|
].join("<br>"), false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elems.statsPanel.appendChild(elems.stats);
|
||||||
|
elems.statsPanel.appendChild(elems.multipliersButton);
|
||||||
|
|
||||||
|
elems.augPanel = createElement("div", { class: "resleeve-panel", width: "50%" });
|
||||||
|
elems.augSelector = createElement("select", { class: "resleeve-aug-selector" }) as HTMLSelectElement;
|
||||||
|
elems.augDescription = createElement("p");
|
||||||
|
for (let i = 0; i < resleeve.augmentations.length; ++i) {
|
||||||
|
elems.augSelector.add(createOptionElement(resleeve.augmentations[i].name));
|
||||||
|
};
|
||||||
|
elems.augSelector.addEventListener("change", () => {
|
||||||
|
updateAugDescription(elems);
|
||||||
|
});
|
||||||
|
elems.augSelector.dispatchEvent(new Event('change')); // Set inital description by manually triggering change event
|
||||||
|
elems.augPanel.appendChild(elems.augSelector);
|
||||||
|
elems.augPanel.appendChild(elems.augDescription);
|
||||||
|
|
||||||
|
const cost: number = resleeve.getCost();
|
||||||
|
elems.costPanel = createElement("div", { class: "resleeve-panel", width: "20%" });
|
||||||
|
elems.costText = createElement("p", {
|
||||||
|
innerText: `It costs ${numeralWrapper.formatMoney(cost)} ` +
|
||||||
|
`to purchase this Sleeve.`,
|
||||||
|
});
|
||||||
|
elems.buyButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "Purchase",
|
||||||
|
clickListener: () => {
|
||||||
|
if (purchaseResleeve(resleeve, playerRef!)) {
|
||||||
|
dialogBoxCreate(`You re-sleeved for ${numeralWrapper.formatMoney(cost)}!`, false);
|
||||||
|
} else {
|
||||||
|
dialogBoxCreate(`You cannot afford to re-sleeve into this body`, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elems.costPanel.appendChild(elems.costText);
|
||||||
|
elems.costPanel.appendChild(elems.buyButton);
|
||||||
|
|
||||||
|
elems.container.appendChild(elems.statsPanel);
|
||||||
|
elems.container.appendChild(elems.augPanel);
|
||||||
|
elems.container.appendChild(elems.costPanel);
|
||||||
|
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAugDescription(elems: IResleeveUIElems) {
|
||||||
|
const augName: string = getSelectValue(elems.augSelector);
|
||||||
|
const aug: Augmentation | null = Augmentations[augName];
|
||||||
|
if (aug == null) {
|
||||||
|
console.warn(`Could not find Augmentation with name ${augName}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elems.augDescription!.innerHTML = aug!.info;
|
||||||
|
}
|
9
src/PersonObjects/Sleeve/README.md
Normal file
9
src/PersonObjects/Sleeve/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Implements the "Duplicate Sleeves" feature, which allows the player to purchase
|
||||||
|
new duplicate sleeves. These are synthetic bodies that contain the player's
|
||||||
|
cloned consciousness. The player can use these sleeves to perform
|
||||||
|
different tasks synchronously.
|
||||||
|
|
||||||
|
This feature is introduced and unlocked in BitNode-10.
|
||||||
|
|
||||||
|
Note that while they are based on the same concept, this feature is different
|
||||||
|
than the "Re-sleeving" mechanic (which is referred to as "Resleeve" in the source code).
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Sleeves are clones of the player that can be used to perform
|
* Sleeves are bodies that contain the player's cloned consciousness.
|
||||||
* different tasks synchronously.
|
* The player can use these bodies to perform different tasks synchronously.
|
||||||
*
|
*
|
||||||
* Each sleeve is its own individual, meaning it has its own stats/exp
|
* Each sleeve is its own individual, meaning it has its own stats/exp
|
||||||
*
|
*
|
||||||
@ -8,21 +8,29 @@
|
|||||||
*/
|
*/
|
||||||
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
||||||
|
|
||||||
|
import { IPlayer } from "../IPlayer";
|
||||||
import { Person,
|
import { Person,
|
||||||
IPlayer,
|
|
||||||
ICrime,
|
|
||||||
IFaction,
|
|
||||||
ITaskTracker,
|
ITaskTracker,
|
||||||
createTaskTracker } from "../Person";
|
createTaskTracker } from "../Person";
|
||||||
|
|
||||||
import { BitNodeMultipliers } from "../../BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
|
|
||||||
|
import { Crime } from "../../Crime/Crime";
|
||||||
|
import { Crimes } from "../../Crime/Crimes";
|
||||||
|
|
||||||
import { Cities } from "../../Locations/Cities";
|
import { Cities } from "../../Locations/Cities";
|
||||||
|
|
||||||
import { Companies } from "../../Company/Companies";
|
import { Companies } from "../../Company/Companies";
|
||||||
import { Company } from "../../Company/Company";
|
import { Company } from "../../Company/Company";
|
||||||
|
import { CompanyPosition } from "../../Company/CompanyPosition";
|
||||||
|
import { CompanyPositions } from "../../Company/CompanyPositions";
|
||||||
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
|
||||||
import { Faction } from "../../Faction/Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { Factions } from "../../Faction/Factions";
|
import { Factions } from "../../Faction/Factions";
|
||||||
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
|
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
|
||||||
|
|
||||||
import { Locations } from "../../Locations";
|
import { Locations } from "../../Locations";
|
||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
|
||||||
@ -35,19 +43,24 @@ export class Sleeve extends Person {
|
|||||||
return Generic_fromJSON(Sleeve, value.data);
|
return Generic_fromJSON(Sleeve, value.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the type of crime the sleeve is currently attempting
|
||||||
|
* Must match the name of a Crime object
|
||||||
|
*/
|
||||||
|
crimeType: string = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum value for current task
|
* Enum value for current task
|
||||||
*/
|
*/
|
||||||
currentTask: SleeveTaskType = SleeveTaskType.Idle;
|
currentTask: SleeveTaskType = SleeveTaskType.Idle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description of current task. Used only for logging purposes
|
* Contains details about the sleeve's current task. The info stored
|
||||||
*/
|
* in this depends on the task type
|
||||||
currentTaskDescription: string = "";
|
*
|
||||||
|
* Faction/Company Work: Name of Faction/Company
|
||||||
/**
|
* Crime: Money earned if successful
|
||||||
* For what company/faction the current task is assigned to.
|
* Class/Gym: Name of university/gym
|
||||||
* Only applicable when working for faction or company, obviously
|
|
||||||
*/
|
*/
|
||||||
currentTaskLocation: string = "";
|
currentTaskLocation: string = "";
|
||||||
|
|
||||||
@ -86,6 +99,11 @@ export class Sleeve extends Person {
|
|||||||
*/
|
*/
|
||||||
gainRatesForTask: ITaskTracker = createTaskTracker();
|
gainRatesForTask: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String that stores what stat the sleeve is training at the gym
|
||||||
|
*/
|
||||||
|
gymStatType: string = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of events/notifications for this sleeve
|
* Keeps track of events/notifications for this sleeve
|
||||||
*/
|
*/
|
||||||
@ -101,6 +119,8 @@ export class Sleeve extends Person {
|
|||||||
* Sleeve shock. Number between 1 and 100
|
* Sleeve shock. Number between 1 and 100
|
||||||
* Trauma/shock that comes with being in a sleeve. Experience earned
|
* Trauma/shock that comes with being in a sleeve. Experience earned
|
||||||
* is multipled by shock%. This gets applied before synchronization
|
* is multipled by shock%. This gets applied before synchronization
|
||||||
|
*
|
||||||
|
* Reputation earned is also multiplied by shock%
|
||||||
*/
|
*/
|
||||||
shock: number = 1;
|
shock: number = 1;
|
||||||
|
|
||||||
@ -118,29 +138,17 @@ export class Sleeve extends Person {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
/*
|
|
||||||
this.currentTask = SleeveTaskType.Idle;
|
|
||||||
this.currentTaskDescription = "";
|
|
||||||
this.currentTaskTime = 0;
|
|
||||||
this.currentTaskMaxTime = 0;
|
|
||||||
this.earningsForSleeves = createTaskTracker();
|
|
||||||
this.earningsForPlayer = createTaskTracker();
|
|
||||||
this.earningsForTask = createTaskTracker();
|
|
||||||
this.gainRatesForTask = createTaskTracker();
|
|
||||||
this.logs = [];
|
|
||||||
this.memory = 0;
|
|
||||||
this.shock = 1;
|
|
||||||
this.storedCycles = 0;
|
|
||||||
this.sync = 1;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit crimes
|
* Commit crimes
|
||||||
*/
|
*/
|
||||||
commitCrime(p: IPlayer, crime: ICrime): void {
|
commitCrime(p: IPlayer, crimeKey: string): boolean {
|
||||||
|
const crime: Crime | null = Crimes[crimeKey];
|
||||||
|
if (!(crime instanceof Crime)) { return false; }
|
||||||
|
|
||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask();
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus();
|
||||||
}
|
}
|
||||||
@ -151,29 +159,94 @@ export class Sleeve extends Person {
|
|||||||
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.dex = crime.dexterity_exp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.agi = crime.agility_exp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
this.gainRatesForTask.cha = crime.charisma_exp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain;
|
||||||
|
this.gainRatesForTask.money = crime.money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
|
||||||
|
|
||||||
|
this.currentTaskLocation = String(this.gainRatesForTask.money);
|
||||||
|
|
||||||
|
this.crimeType = crimeKey;
|
||||||
this.currentTaskMaxTime = crime.time;
|
this.currentTaskMaxTime = crime.time;
|
||||||
|
|
||||||
this.currentTask = SleeveTaskType.Crime;
|
this.currentTask = SleeveTaskType.Crime;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to stop the current task
|
* Called to stop the current task
|
||||||
*/
|
*/
|
||||||
finishTask(): void {
|
finishTask(p: IPlayer): ITaskTracker {
|
||||||
if (this.currentTask === SleeveTaskType.Crime) {
|
let retValue: ITaskTracker = createTaskTracker(); // Amount of exp to be gained by other sleeves
|
||||||
} else {
|
|
||||||
|
|
||||||
|
if (this.currentTask === SleeveTaskType.Crime) {
|
||||||
|
// For crimes, all experience and money is gained at the end
|
||||||
|
if (this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||||
|
const crime: Crime | null = Crimes[this.crimeType];
|
||||||
|
if (!(crime instanceof Crime)) {
|
||||||
|
console.error(`Invalid data stored in sleeve.crimeType: ${this.crimeType}`);
|
||||||
|
this.resetTaskStatus();
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
if (Math.random() < crime.successRate(p)) {
|
||||||
|
// Success
|
||||||
|
const successGainRates: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
const keysForIteration: (keyof ITaskTracker)[] = (<(keyof ITaskTracker)[]>Object.keys(successGainRates));
|
||||||
|
for (let i = 0; i < keysForIteration.length; ++i) {
|
||||||
|
const key = keysForIteration[i];
|
||||||
|
successGainRates[key] = this.gainRatesForTask[key] * 2;
|
||||||
|
}
|
||||||
|
retValue = this.gainExperience(p, successGainRates);
|
||||||
|
this.gainMoney(p, this.gainRatesForTask);
|
||||||
|
} else {
|
||||||
|
retValue = this.gainExperience(p, this.gainRatesForTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not reset task to IDLE
|
||||||
|
this.currentTaskTime = 0;
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other crimes... I dont think anything else needs to be done
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus();
|
||||||
|
|
||||||
|
return retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Earn experience for any stats (supports multiple)
|
* Earn experience for any stats (supports multiple)
|
||||||
* This function also handles experience propogating to Player and other sleeves
|
* This function also handles experience propogating to Player and other sleeves
|
||||||
*/
|
*/
|
||||||
gainExperience(p: IPlayer, exp: ITaskTracker, numCycles: number=1): ITaskTracker {
|
gainExperience(p: IPlayer, exp: ITaskTracker, numCycles: number=1, fromOtherSleeve: boolean=false): ITaskTracker {
|
||||||
|
// If the experience is coming from another sleeve, it is not multiplied by anything.
|
||||||
|
// Also the player does not earn anything
|
||||||
|
if (fromOtherSleeve) {
|
||||||
|
if (exp.hack > 0) {
|
||||||
|
this.hacking_exp += exp.hack;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp.str > 0) {
|
||||||
|
this.strength_exp += exp.str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp.def > 0) {
|
||||||
|
this.defense_exp += exp.def;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp.dex > 0) {
|
||||||
|
this.dexterity_exp += exp.dex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp.agi > 0) {
|
||||||
|
this.agility_exp += exp.agi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp.cha > 0) {
|
||||||
|
this.charisma_exp += exp.cha;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createTaskTracker();
|
||||||
|
}
|
||||||
|
|
||||||
// Experience is first multiplied by shock. Then 'synchronization'
|
// Experience is first multiplied by shock. Then 'synchronization'
|
||||||
// is accounted for
|
// is accounted for
|
||||||
const multFac = (this.shock / 100) * (this.sync / 100) * numCycles;
|
const multFac = (this.shock / 100) * (this.sync / 100) * numCycles;
|
||||||
@ -203,7 +276,7 @@ export class Sleeve extends Person {
|
|||||||
this.defense_exp += pDefExp;
|
this.defense_exp += pDefExp;
|
||||||
p.gainDefenseExp(pDefExp);
|
p.gainDefenseExp(pDefExp);
|
||||||
this.earningsForPlayer.def += pDefExp;
|
this.earningsForPlayer.def += pDefExp;
|
||||||
this.earningsForTask.dex += pDefExp;
|
this.earningsForTask.def += pDefExp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDexExp > 0) {
|
if (pDexExp > 0) {
|
||||||
@ -251,28 +324,49 @@ export class Sleeve extends Person {
|
|||||||
* Earn money for player
|
* Earn money for player
|
||||||
*/
|
*/
|
||||||
gainMoney(p: IPlayer, task: ITaskTracker, numCycles: number=1): void {
|
gainMoney(p: IPlayer, task: ITaskTracker, numCycles: number=1): void {
|
||||||
p.gainMoney(task.money * numCycles);
|
const gain: number = (task.money * numCycles);
|
||||||
|
this.earningsForTask.money += gain;
|
||||||
|
this.earningsForPlayer.money += gain;
|
||||||
|
p.gainMoney(gain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets reputation gain for the current task
|
* Gets reputation gain for the current task
|
||||||
* Only applicable when working for company or faction
|
* Only applicable when working for company or faction
|
||||||
*/
|
*/
|
||||||
getRepGain(): number {
|
getRepGain(p: IPlayer): number {
|
||||||
if (this.currentTask === SleeveTaskType.Faction) {
|
if (this.currentTask === SleeveTaskType.Faction) {
|
||||||
switch (this.factionWorkType) {
|
switch (this.factionWorkType) {
|
||||||
case FactionWorkType.Hacking:
|
case FactionWorkType.Hacking:
|
||||||
return this.getFactionHackingWorkRepGain();
|
return this.getFactionHackingWorkRepGain() * (this.shock / 100);
|
||||||
case FactionWorkType.Field:
|
case FactionWorkType.Field:
|
||||||
return this.getFactionFieldWorkRepGain();
|
return this.getFactionFieldWorkRepGain() * (this.shock / 100);
|
||||||
case FactionWorkType.Security:
|
case FactionWorkType.Security:
|
||||||
return this.getFactionSecurityWorkRepGain();
|
return this.getFactionSecurityWorkRepGain() * (this.shock / 100);
|
||||||
default:
|
default:
|
||||||
console.warn(`Invalid Sleeve.factionWorkType property in Sleeve.getRepGain(): ${this.factionWorkType}`);
|
console.warn(`Invalid Sleeve.factionWorkType property in Sleeve.getRepGain(): ${this.factionWorkType}`);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (this.currentTask === SleeveTaskType.Company) {
|
} else if (this.currentTask === SleeveTaskType.Company) {
|
||||||
return 0;
|
const companyName: string = this.currentTaskLocation;
|
||||||
|
const company: Company | null = Companies[companyName];
|
||||||
|
if (company == null) {
|
||||||
|
console.error(`Invalid company found when trying to calculate rep gain: ${companyName}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const companyPosition: CompanyPosition | null = CompanyPositions[p.jobs[companyName]];
|
||||||
|
if (companyPosition == null) {
|
||||||
|
console.error(`Invalid company position name found when trying to calculate rep gain: ${p.jobs[companyName]}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const jobPerformance: number = companyPosition!.calculateJobPerformance(this.hacking_skill, this.strength,
|
||||||
|
this.defense, this.dexterity,
|
||||||
|
this.agility, this.charisma);
|
||||||
|
const favorMult = 1 + (company!.favor / 100);
|
||||||
|
|
||||||
|
return jobPerformance * this.company_rep_mult * favorMult;
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Sleeve.getRepGain() called for invalid task type: ${this.currentTask}`);
|
console.warn(`Sleeve.getRepGain() called for invalid task type: ${this.currentTask}`);
|
||||||
return 0;
|
return 0;
|
||||||
@ -298,14 +392,9 @@ export class Sleeve extends Person {
|
|||||||
this.storedCycles += numCycles;
|
this.storedCycles += numCycles;
|
||||||
if (this.storedCycles < CyclesPerSecond) { return null; }
|
if (this.storedCycles < CyclesPerSecond) { return null; }
|
||||||
|
|
||||||
// Shock gradually goes towards 100
|
|
||||||
this.shock = Math.max(100, this.shock + (0.0001 * this.storedCycles));
|
|
||||||
|
|
||||||
if (this.currentTask === SleeveTaskType.Idle) { return null; }
|
|
||||||
|
|
||||||
let time = this.storedCycles * CONSTANTS.MilliPerCycle;
|
let time = this.storedCycles * CONSTANTS.MilliPerCycle;
|
||||||
let cyclesUsed = this.storedCycles;
|
let cyclesUsed = this.storedCycles;
|
||||||
if (this.currentTaskTime + time > this.currentTaskMaxTime) {
|
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime + time > this.currentTaskMaxTime) {
|
||||||
time = this.currentTaskMaxTime - this.currentTaskTime;
|
time = this.currentTaskMaxTime - this.currentTaskTime;
|
||||||
cyclesUsed = Math.floor(time / CONSTANTS.MilliPerCycle);
|
cyclesUsed = Math.floor(time / CONSTANTS.MilliPerCycle);
|
||||||
|
|
||||||
@ -317,9 +406,15 @@ export class Sleeve extends Person {
|
|||||||
}
|
}
|
||||||
this.currentTaskTime += time;
|
this.currentTaskTime += time;
|
||||||
|
|
||||||
|
// Shock gradually goes towards 100
|
||||||
|
this.shock = Math.min(100, this.shock + (0.0001 * this.storedCycles));
|
||||||
|
|
||||||
let retValue: ITaskTracker = createTaskTracker();
|
let retValue: ITaskTracker = createTaskTracker();
|
||||||
switch (this.currentTask) {
|
switch (this.currentTask) {
|
||||||
|
case SleeveTaskType.Idle:
|
||||||
|
break;
|
||||||
case SleeveTaskType.Class:
|
case SleeveTaskType.Class:
|
||||||
|
case SleeveTaskType.Gym:
|
||||||
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||||
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||||
break;
|
break;
|
||||||
@ -327,34 +422,50 @@ export class Sleeve extends Person {
|
|||||||
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||||
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
|
||||||
// TODO REP for both this and company
|
// Gain faction reputation
|
||||||
const fac = Factions[this.currentTaskLocation];
|
const fac: Faction = Factions[this.currentTaskLocation];
|
||||||
if (!(fac instanceof Faction)) {
|
if (!(fac instanceof Faction)) {
|
||||||
console.error(`Invalid faction for Sleeve task: ${this.currentTaskLocation}`);
|
console.error(`Invalid faction for Sleeve task: ${this.currentTaskLocation}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fac.playerReputation += (this.getRepGain(p) * cyclesUsed);
|
||||||
break;
|
break;
|
||||||
case SleeveTaskType.Company:
|
case SleeveTaskType.Company:
|
||||||
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||||
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||||
|
|
||||||
|
const company: Company = Companies[this.currentTaskLocation];
|
||||||
|
if (!(company instanceof Company)) {
|
||||||
|
console.error(`Invalid company for Sleeve task: ${this.currentTaskLocation}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
company!.playerReputation += (this.getRepGain(p) * cyclesUsed);
|
||||||
break;
|
break;
|
||||||
case SleeveTaskType.Recovery:
|
case SleeveTaskType.Recovery:
|
||||||
this.shock = Math.max(100, this.shock + (0.001 * this.storedCycles));
|
this.shock = Math.min(100, this.shock + (0.0001 * cyclesUsed));
|
||||||
break;
|
break;
|
||||||
case SleeveTaskType.Sync:
|
case SleeveTaskType.Sync:
|
||||||
this.sync = Math.max(100, this.sync + (0.001 * this.storedCycles));
|
this.sync = Math.min(100, this.sync + (0.0001 * cyclesUsed));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
|
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||||
this.finishTask();
|
if (this.currentTask === SleeveTaskType.Crime) {
|
||||||
|
retValue = this.finishTask(p);
|
||||||
|
} else {
|
||||||
|
this.finishTask(p);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateStatLevels();
|
||||||
|
|
||||||
this.storedCycles -= cyclesUsed;
|
this.storedCycles -= cyclesUsed;
|
||||||
|
|
||||||
// TODO Finish this
|
|
||||||
return retValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +479,9 @@ export class Sleeve extends Person {
|
|||||||
this.currentTaskTime = 0;
|
this.currentTaskTime = 0;
|
||||||
this.currentTaskMaxTime = 0;
|
this.currentTaskMaxTime = 0;
|
||||||
this.factionWorkType = FactionWorkType.None;
|
this.factionWorkType = FactionWorkType.None;
|
||||||
|
this.crimeType = "";
|
||||||
|
this.currentTaskLocation = "";
|
||||||
|
this.gymStatType = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -375,7 +489,7 @@ export class Sleeve extends Person {
|
|||||||
*/
|
*/
|
||||||
takeUniversityCourse(p: IPlayer, universityName: string, className: string): boolean {
|
takeUniversityCourse(p: IPlayer, universityName: string, className: string): boolean {
|
||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask();
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus();
|
||||||
}
|
}
|
||||||
@ -387,16 +501,19 @@ export class Sleeve extends Person {
|
|||||||
switch (universityName.toLowerCase()) {
|
switch (universityName.toLowerCase()) {
|
||||||
case Locations.AevumSummitUniversity.toLowerCase():
|
case Locations.AevumSummitUniversity.toLowerCase():
|
||||||
if (this.city !== Cities.Aevum) { return false; }
|
if (this.city !== Cities.Aevum) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.AevumSummitUniversity;
|
||||||
costMult = 4;
|
costMult = 4;
|
||||||
expMult = 3;
|
expMult = 3;
|
||||||
break;
|
break;
|
||||||
case Locations.Sector12RothmanUniversity.toLowerCase():
|
case Locations.Sector12RothmanUniversity.toLowerCase():
|
||||||
if (this.city !== Cities.Sector12) { return false; }
|
if (this.city !== Cities.Sector12) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.Sector12RothmanUniversity;
|
||||||
costMult = 3;
|
costMult = 3;
|
||||||
expMult = 2;
|
expMult = 2;
|
||||||
break;
|
break;
|
||||||
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
|
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
|
||||||
if (this.city !== Cities.Volhaven) { return false; }
|
if (this.city !== Cities.Volhaven) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.VolhavenZBInstituteOfTechnology;
|
||||||
costMult = 5;
|
costMult = 5;
|
||||||
expMult = 4;
|
expMult = 4;
|
||||||
break;
|
break;
|
||||||
@ -404,9 +521,6 @@ export class Sleeve extends Person {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of game cycles in a second
|
|
||||||
const cps: number = 1000 / CONSTANTS.MilliPerCycle;
|
|
||||||
|
|
||||||
// Set experience/money gains based on class
|
// Set experience/money gains based on class
|
||||||
// TODO Refactor University Courses into its own class or something
|
// TODO Refactor University Courses into its own class or something
|
||||||
const baseStudyComputerScienceExp: number = 0.5;
|
const baseStudyComputerScienceExp: number = 0.5;
|
||||||
@ -464,32 +578,86 @@ export class Sleeve extends Person {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Work for a company
|
* Start work for one of the player's companies
|
||||||
|
* Returns boolean indicating success
|
||||||
*/
|
*/
|
||||||
workForCompany(p: IPlayer): boolean {
|
workForCompany(p: IPlayer, companyName: string): boolean {
|
||||||
return true;
|
if (!(Companies[companyName] instanceof Company) || p.jobs[companyName] == null) {
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Work for one of the player's factions
|
|
||||||
*/
|
|
||||||
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
|
|
||||||
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask();
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const company: Company | null = Companies[companyName];
|
||||||
|
const companyPosition: CompanyPosition | null = CompanyPositions[p.jobs[companyName]];
|
||||||
|
if (company == null) { throw new Error(`Invalid company name specified in Sleeve.workForCompany(): ${companyName}`); }
|
||||||
|
if (companyPosition == null) { throw new Error(`Invalid CompanyPosition data in Sleeve.workForCompany(): ${companyName}`); }
|
||||||
|
this.gainRatesForTask.money = companyPosition.baseSalary *
|
||||||
|
company.salaryMultiplier *
|
||||||
|
this.work_money_mult *
|
||||||
|
BitNodeMultipliers.CompanyWorkMoney;
|
||||||
|
this.gainRatesForTask.hack = companyPosition.hackingExpGain *
|
||||||
|
company.expMultiplier *
|
||||||
|
this.hacking_exp_mult *
|
||||||
|
BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.str = companyPosition.strengthExpGain *
|
||||||
|
company.expMultiplier *
|
||||||
|
this.strength_exp_mult *
|
||||||
|
BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.def = companyPosition.defenseExpGain *
|
||||||
|
company.expMultiplier *
|
||||||
|
this.defense_exp_mult *
|
||||||
|
BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.dex = companyPosition.dexterityExpGain *
|
||||||
|
company.expMultiplier *
|
||||||
|
this.dexterity_exp_mult *
|
||||||
|
BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.agi = companyPosition.agilityExpGain *
|
||||||
|
company.expMultiplier *
|
||||||
|
this.agility_exp_mult *
|
||||||
|
BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
this.gainRatesForTask.cha = companyPosition.charismaExpGain *
|
||||||
|
company.expMultiplier *
|
||||||
|
this.charisma_exp_mult *
|
||||||
|
BitNodeMultipliers.FactionWorkExpGain;
|
||||||
|
|
||||||
|
this.currentTaskLocation = companyName;
|
||||||
|
this.currentTask = SleeveTaskType.Company;
|
||||||
|
this.currentTaskMaxTime = CONSTANTS.MillisecondsPer8Hours;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start work for one of the player's factions
|
||||||
|
* Returns boolean indicating success
|
||||||
|
*/
|
||||||
|
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
|
||||||
|
if (!(Factions[factionName] instanceof Faction) || !p.factions.includes(factionName)) {
|
||||||
|
throw new Error(`Invalid Faction specified for Sleeve.workForFaction(): ${factionName}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
|
this.finishTask(p);
|
||||||
|
} else {
|
||||||
|
this.resetTaskStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
const factionInfo = Factions[factionName].getInfo();
|
||||||
|
|
||||||
// Set type of work (hacking/field/security), and the experience gains
|
// Set type of work (hacking/field/security), and the experience gains
|
||||||
const sanitizedWorkType: string = workType.toLowerCase();
|
const sanitizedWorkType: string = workType.toLowerCase();
|
||||||
if (sanitizedWorkType.includes("hack")) {
|
if (sanitizedWorkType.includes("hack")) {
|
||||||
|
if (!factionInfo.offerHackingWork) { return false; }
|
||||||
this.factionWorkType = FactionWorkType.Hacking;
|
this.factionWorkType = FactionWorkType.Hacking;
|
||||||
this.gainRatesForTask.hack = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.hack = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
} else if (sanitizedWorkType.includes("field")) {
|
} else if (sanitizedWorkType.includes("field")) {
|
||||||
|
if (!factionInfo.offerFieldWork) { return false; }
|
||||||
this.factionWorkType = FactionWorkType.Field;
|
this.factionWorkType = FactionWorkType.Field;
|
||||||
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.gainRatesForTask.str = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.str = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
@ -498,6 +666,7 @@ export class Sleeve extends Person {
|
|||||||
this.gainRatesForTask.agi = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.agi = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.gainRatesForTask.cha = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.cha = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
} else if (sanitizedWorkType.includes("security")) {
|
} else if (sanitizedWorkType.includes("security")) {
|
||||||
|
if (!factionInfo.offerSecurityWork) { return false; }
|
||||||
this.factionWorkType = FactionWorkType.Security;
|
this.factionWorkType = FactionWorkType.Security;
|
||||||
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.hack = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
this.gainRatesForTask.str = .15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
this.gainRatesForTask.str = .15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||||
@ -510,6 +679,7 @@ export class Sleeve extends Person {
|
|||||||
|
|
||||||
this.currentTaskLocation = factionName;
|
this.currentTaskLocation = factionName;
|
||||||
this.currentTask = SleeveTaskType.Faction;
|
this.currentTask = SleeveTaskType.Faction;
|
||||||
|
this.currentTaskMaxTime = CONSTANTS.MillisecondsPer20Hours;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -519,7 +689,7 @@ export class Sleeve extends Person {
|
|||||||
*/
|
*/
|
||||||
workoutAtGym(p: IPlayer, gymName: string, stat: string): boolean {
|
workoutAtGym(p: IPlayer, gymName: string, stat: string): boolean {
|
||||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||||
this.finishTask();
|
this.finishTask(p);
|
||||||
} else {
|
} else {
|
||||||
this.resetTaskStatus();
|
this.resetTaskStatus();
|
||||||
}
|
}
|
||||||
@ -531,26 +701,31 @@ export class Sleeve extends Person {
|
|||||||
switch (gymName.toLowerCase()) {
|
switch (gymName.toLowerCase()) {
|
||||||
case Locations.AevumCrushFitnessGym.toLowerCase():
|
case Locations.AevumCrushFitnessGym.toLowerCase():
|
||||||
if (this.city != Cities.Aevum) { return false; }
|
if (this.city != Cities.Aevum) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.AevumCrushFitnessGym;
|
||||||
costMult = 3;
|
costMult = 3;
|
||||||
expMult = 2;
|
expMult = 2;
|
||||||
break;
|
break;
|
||||||
case Locations.AevumSnapFitnessGym.toLowerCase():
|
case Locations.AevumSnapFitnessGym.toLowerCase():
|
||||||
if (this.city != Cities.Aevum) { return false; }
|
if (this.city != Cities.Aevum) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.AevumSnapFitnessGym;
|
||||||
costMult = 10;
|
costMult = 10;
|
||||||
expMult = 5;
|
expMult = 5;
|
||||||
break;
|
break;
|
||||||
case Locations.Sector12IronGym.toLowerCase():
|
case Locations.Sector12IronGym.toLowerCase():
|
||||||
if (this.city != Cities.Sector12) { return false; }
|
if (this.city != Cities.Sector12) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.Sector12IronGym;
|
||||||
costMult = 1;
|
costMult = 1;
|
||||||
expMult = 1;
|
expMult = 1;
|
||||||
break;
|
break;
|
||||||
case Locations.Sector12PowerhouseGym.toLowerCase():
|
case Locations.Sector12PowerhouseGym.toLowerCase():
|
||||||
if (this.city != Cities.Sector12) { return false; }
|
if (this.city != Cities.Sector12) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.Sector12PowerhouseGym;
|
||||||
costMult = 20;
|
costMult = 20;
|
||||||
expMult = 10;
|
expMult = 10;
|
||||||
break;
|
break;
|
||||||
case Locations.VolhavenMilleniumFitnessGym:
|
case Locations.VolhavenMilleniumFitnessGym:
|
||||||
if (this.city != Cities.Volhaven) { return false; }
|
if (this.city != Cities.Volhaven) { return false; }
|
||||||
|
this.currentTaskLocation = Locations.VolhavenMilleniumFitnessGym;
|
||||||
costMult = 7;
|
costMult = 7;
|
||||||
expMult = 4;
|
expMult = 4;
|
||||||
break;
|
break;
|
||||||
@ -558,9 +733,6 @@ export class Sleeve extends Person {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of game cycles in a second
|
|
||||||
const cps = 1000 / CONSTANTS.MilliPerCycle;
|
|
||||||
|
|
||||||
// Set experience/money gains based on class
|
// Set experience/money gains based on class
|
||||||
// TODO Refactor University Courses into its own class or something
|
// TODO Refactor University Courses into its own class or something
|
||||||
const baseGymExp: number = 1;
|
const baseGymExp: number = 1;
|
||||||
@ -582,7 +754,8 @@ export class Sleeve extends Person {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentTask = SleeveTaskType.Class;
|
this.gymStatType = stat;
|
||||||
|
this.currentTask = SleeveTaskType.Gym;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
* Enum for different types of tasks that a Sleeve can perform
|
* Enum for different types of tasks that a Sleeve can perform
|
||||||
*/
|
*/
|
||||||
export enum SleeveTaskType {
|
export enum SleeveTaskType {
|
||||||
Class,
|
// Same Order as selectable order in UI
|
||||||
Company,
|
|
||||||
Crime,
|
|
||||||
Faction,
|
|
||||||
Idle,
|
Idle,
|
||||||
|
Company,
|
||||||
|
Faction,
|
||||||
|
Crime,
|
||||||
|
Class,
|
||||||
|
Gym,
|
||||||
Recovery,
|
Recovery,
|
||||||
Sync,
|
Sync,
|
||||||
}
|
}
|
||||||
|
741
src/PersonObjects/Sleeve/SleeveUI.ts
Normal file
741
src/PersonObjects/Sleeve/SleeveUI.ts
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
/**
|
||||||
|
* Module for handling the Sleeve UI
|
||||||
|
*/
|
||||||
|
import { Sleeve } from "./Sleeve";
|
||||||
|
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
||||||
|
import { SleeveFaq } from "./data/SleeveFaq";
|
||||||
|
|
||||||
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
import { Locations } from "../../Locations";
|
||||||
|
|
||||||
|
import { Faction } from "../../Faction/Faction";
|
||||||
|
import { Factions } from "../../Faction/Factions";
|
||||||
|
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
|
||||||
|
|
||||||
|
import { Cities } from "../../Locations/Cities";
|
||||||
|
import { Crime } from "../../Crime/Crime";
|
||||||
|
import { Crimes } from "../../Crime/Crimes";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
import { Page,
|
||||||
|
routing } from "../../ui/navigationTracking";
|
||||||
|
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
|
||||||
|
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
||||||
|
import { exceptionAlert } from "../../../utils/helpers/exceptionAlert";
|
||||||
|
|
||||||
|
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners";
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { createPopup } from "../../../utils/uiHelpers/createPopup";
|
||||||
|
import { createPopupCloseButton } from "../../../utils/uiHelpers/createPopupCloseButton";
|
||||||
|
import { getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
|
import { removeElement } from "../../../utils/uiHelpers/removeElement";
|
||||||
|
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
||||||
|
|
||||||
|
// Object that keeps track of all DOM elements for the UI for a single Sleeve
|
||||||
|
interface ISleeveUIElems {
|
||||||
|
container: HTMLElement | null;
|
||||||
|
statsPanel: HTMLElement | null;
|
||||||
|
stats: HTMLElement | null;
|
||||||
|
moreStatsButton: HTMLElement | null;
|
||||||
|
travelButton: HTMLElement | null;
|
||||||
|
taskPanel: HTMLElement | null;
|
||||||
|
taskSelector: HTMLSelectElement | null;
|
||||||
|
taskDetailsSelector: HTMLSelectElement | null;
|
||||||
|
taskDetailsSelector2: HTMLSelectElement | null;
|
||||||
|
taskDescription: HTMLElement | null;
|
||||||
|
taskSetButton: HTMLElement | null;
|
||||||
|
taskProgressBar: HTMLElement | null;
|
||||||
|
earningsPanel: HTMLElement | null;
|
||||||
|
currentEarningsInfo: HTMLElement | null;
|
||||||
|
totalEarningsButton: HTMLElement | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object that keeps track of all DOM elements for the entire Sleeve UI
|
||||||
|
interface IPageUIElems {
|
||||||
|
container: HTMLElement | null;
|
||||||
|
docButton: HTMLElement | null;
|
||||||
|
faqButton: HTMLElement | null;
|
||||||
|
info: HTMLElement | null;
|
||||||
|
sleeveList: HTMLElement | null;
|
||||||
|
sleeves: ISleeveUIElems[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UIElems: IPageUIElems = {
|
||||||
|
container: null,
|
||||||
|
docButton: null,
|
||||||
|
faqButton: null,
|
||||||
|
info: null,
|
||||||
|
sleeveList: null,
|
||||||
|
sleeves: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the UI for the entire Sleeves page
|
||||||
|
let playerRef: IPlayer | null;
|
||||||
|
export function createSleevesPage(p: IPlayer) {
|
||||||
|
if (!routing.isOn(Page.Sleeves)) { return; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
playerRef = p;
|
||||||
|
|
||||||
|
UIElems.container = createElement("div", {
|
||||||
|
class: "generic-menupage-container",
|
||||||
|
id: "sleeves-container",
|
||||||
|
position: "fixed",
|
||||||
|
});
|
||||||
|
|
||||||
|
UIElems.info = createElement("p", {
|
||||||
|
class: "sleeves-page-info",
|
||||||
|
innerHTML: "Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your " +
|
||||||
|
"consciousness has been copied. In other words, these Synthoids contain " +
|
||||||
|
"a perfect duplicate of your mind.<br><br>" +
|
||||||
|
"Sleeves can be used to perform different tasks synchronously.<br><br>",
|
||||||
|
});
|
||||||
|
|
||||||
|
UIElems.faqButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
display: "inline-block",
|
||||||
|
innerText: "FAQ",
|
||||||
|
clickListener: () => {
|
||||||
|
dialogBoxCreate(SleeveFaq, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
UIElems.docButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
display: "inline-block",
|
||||||
|
innerText: "Documentation",
|
||||||
|
});
|
||||||
|
|
||||||
|
UIElems.sleeveList = createElement("ul");
|
||||||
|
UIElems.sleeves = [];
|
||||||
|
|
||||||
|
// Create UI modules for all Sleeve
|
||||||
|
for (const sleeve of p.sleeves) {
|
||||||
|
const sleeveUi = createSleeveUi(sleeve, p.sleeves);
|
||||||
|
UIElems.sleeveList.appendChild(sleeveUi.container!);
|
||||||
|
UIElems.sleeves.push(sleeveUi);
|
||||||
|
}
|
||||||
|
|
||||||
|
UIElems.container.appendChild(UIElems.info);
|
||||||
|
UIElems.container.appendChild(UIElems.faqButton);
|
||||||
|
UIElems.container.appendChild(UIElems.sleeveList);
|
||||||
|
|
||||||
|
document.getElementById("entire-game-container")!.appendChild(UIElems.container);
|
||||||
|
} catch(e) {
|
||||||
|
exceptionAlert(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the UI for the entire Sleeves page
|
||||||
|
export function updateSleevesPage() {
|
||||||
|
if (!routing.isOn(Page.Sleeves)) { return; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < playerRef!.sleeves.length; ++i) {
|
||||||
|
const sleeve: Sleeve = playerRef!.sleeves[i];
|
||||||
|
const elems: ISleeveUIElems = UIElems.sleeves![i];
|
||||||
|
updateSleeveUi(sleeve!, elems!);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
exceptionAlert(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearSleevesPage() {
|
||||||
|
if (UIElems.container instanceof HTMLElement) {
|
||||||
|
removeElement(UIElems.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const prop in UIElems) {
|
||||||
|
(<any>UIElems)[prop] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerRef = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the UI for a single Sleeve
|
||||||
|
// Returns an object containing the DOM elements in the UI (ISleeveUIElems)
|
||||||
|
function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||||
|
const elems: ISleeveUIElems = {
|
||||||
|
container: null,
|
||||||
|
statsPanel: null,
|
||||||
|
stats: null,
|
||||||
|
moreStatsButton: null,
|
||||||
|
travelButton: null,
|
||||||
|
taskPanel: null,
|
||||||
|
taskSelector: null,
|
||||||
|
taskDetailsSelector: null,
|
||||||
|
taskDetailsSelector2: null,
|
||||||
|
taskDescription: null,
|
||||||
|
taskSetButton: null,
|
||||||
|
taskProgressBar: null,
|
||||||
|
earningsPanel: null,
|
||||||
|
currentEarningsInfo: null,
|
||||||
|
totalEarningsButton: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!routing.isOn(Page.Sleeves)) { return elems; }
|
||||||
|
|
||||||
|
elems.container = createElement("div", {
|
||||||
|
class: "sleeve-container",
|
||||||
|
display: "block",
|
||||||
|
});
|
||||||
|
|
||||||
|
elems.statsPanel = createElement("div", { class: "sleeve-panel", width: "25%" });
|
||||||
|
elems.stats = createElement("p", { class: "sleeve-stats-text" });
|
||||||
|
elems.moreStatsButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "More Stats",
|
||||||
|
clickListener: () => {
|
||||||
|
dialogBoxCreate(
|
||||||
|
[
|
||||||
|
"<h2><u>Stats:</u></h2>",
|
||||||
|
`Hacking: ${sleeve.hacking_skill} (${numeralWrapper.formatBigNumber(sleeve.hacking_exp)} exp)`,
|
||||||
|
`Strength: ${sleeve.strength} (${numeralWrapper.formatBigNumber(sleeve.strength_exp)} exp)`,
|
||||||
|
`Defense: ${sleeve.defense} (${numeralWrapper.formatBigNumber(sleeve.defense_exp)} exp)`,
|
||||||
|
`Dexterity: ${sleeve.dexterity} (${numeralWrapper.formatBigNumber(sleeve.dexterity_exp)} exp)`,
|
||||||
|
`Agility: ${sleeve.agility} (${numeralWrapper.formatBigNumber(sleeve.agility_exp)} exp)`,
|
||||||
|
`Charisma: ${sleeve.charisma} (${numeralWrapper.formatBigNumber(sleeve.charisma_exp)} exp)<br>`,
|
||||||
|
"<h2><u>Multipliers:</u></h2>",
|
||||||
|
`Hacking Level multiplier: ${numeralWrapper.formatPercentage(sleeve.hacking_mult)}`,
|
||||||
|
`Hacking Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.hacking_exp_mult)}`,
|
||||||
|
`Strength Level multiplier: ${numeralWrapper.formatPercentage(sleeve.strength_mult)}`,
|
||||||
|
`Strength Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.strength_exp_mult)}`,
|
||||||
|
`Defense Level multiplier: ${numeralWrapper.formatPercentage(sleeve.defense_mult)}`,
|
||||||
|
`Defense Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.defense_exp_mult)}`,
|
||||||
|
`Dexterity Level multiplier: ${numeralWrapper.formatPercentage(sleeve.dexterity_mult)}`,
|
||||||
|
`Dexterity Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.dexterity_exp_mult)}`,
|
||||||
|
`Agility Level multiplier: ${numeralWrapper.formatPercentage(sleeve.agility_mult)}`,
|
||||||
|
`Agility Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.agility_exp_mult)}`,
|
||||||
|
`Charisma Level multiplier: ${numeralWrapper.formatPercentage(sleeve.charisma_mult)}`,
|
||||||
|
`Charisma Experience multiplier: ${numeralWrapper.formatPercentage(sleeve.charisma_exp_mult)}`,
|
||||||
|
`Faction Reputation Gain multiplier: ${numeralWrapper.formatPercentage(sleeve.faction_rep_mult)}`,
|
||||||
|
`Company Reputation Gain multiplier: ${numeralWrapper.formatPercentage(sleeve.company_rep_mult)}`,
|
||||||
|
`Salary multiplier: ${numeralWrapper.formatPercentage(sleeve.work_money_mult)}`,
|
||||||
|
`Crime Money multiplier: ${numeralWrapper.formatPercentage(sleeve.crime_money_mult)}`,
|
||||||
|
`Crime Success multiplier: ${numeralWrapper.formatPercentage(sleeve.crime_success_mult)}`,
|
||||||
|
].join("<br>"), false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elems.travelButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "Travel",
|
||||||
|
clickListener: () => {
|
||||||
|
const popupId: string = "sleeve-travel-popup";
|
||||||
|
const popupArguments: HTMLElement[] = [];
|
||||||
|
popupArguments.push(createPopupCloseButton(popupId, { class: "std-button" }));
|
||||||
|
popupArguments.push(createElement("p", {
|
||||||
|
innerText: "Have this sleeve travel to a different city. This affects " +
|
||||||
|
"the gyms and universities at which this sleeve can study. " +
|
||||||
|
`Traveling to a different city costs ${numeralWrapper.formatMoney(CONSTANTS.TravelCost)}. ` +
|
||||||
|
"It will also CANCEL the sleeve's current task (setting it to idle)",
|
||||||
|
}));
|
||||||
|
for (const label in Cities) {
|
||||||
|
if (sleeve.city === Cities[label]) { continue; }
|
||||||
|
(function(sleeve, label) {
|
||||||
|
popupArguments.push(createElement("div", {
|
||||||
|
// Reusing this css class. It adds a border and makes it so that
|
||||||
|
// the background color changes when you hover
|
||||||
|
class: "cmpy-mgmt-find-employee-option",
|
||||||
|
innerText: Cities[label],
|
||||||
|
clickListener: () => {
|
||||||
|
if (!playerRef!.canAfford(CONSTANTS.TravelCost)) {
|
||||||
|
dialogBoxCreate("You cannot afford to have this sleeve travel to another city", false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sleeve.city = Cities[label];
|
||||||
|
playerRef!.loseMoney(CONSTANTS.TravelCost);
|
||||||
|
sleeve.resetTaskStatus();
|
||||||
|
removeElementById(popupId);
|
||||||
|
updateSleeveUi(sleeve, elems);
|
||||||
|
updateSleeveTaskSelector(sleeve, elems, allSleeves);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
})(sleeve, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
createPopup(popupId, popupArguments);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
elems.statsPanel.appendChild(elems.stats);
|
||||||
|
elems.statsPanel.appendChild(elems.moreStatsButton);
|
||||||
|
elems.statsPanel.appendChild(elems.travelButton);
|
||||||
|
|
||||||
|
elems.taskPanel = createElement("div", { class: "sleeve-panel", width: "40%" });
|
||||||
|
elems.taskSelector = createElement("select") as HTMLSelectElement;
|
||||||
|
elems.taskSelector.add(createOptionElement("------"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Work for Company"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Work for Faction"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Commit Crime"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Take University Course"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Workout at Gym"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Shock Recovery"));
|
||||||
|
elems.taskSelector.add(createOptionElement("Synchronize"));
|
||||||
|
elems.taskDetailsSelector = createElement("select") as HTMLSelectElement;
|
||||||
|
elems.taskDetailsSelector2 = createElement("select") as HTMLSelectElement;
|
||||||
|
elems.taskDescription = createElement("p");
|
||||||
|
elems.taskProgressBar = createElement("p");
|
||||||
|
elems.taskSelector.addEventListener("change", () => {
|
||||||
|
updateSleeveTaskSelector(sleeve, elems, allSleeves);
|
||||||
|
});
|
||||||
|
elems.taskSelector.selectedIndex = sleeve.currentTask; // Set initial value for Task Selector
|
||||||
|
elems.taskSelector.dispatchEvent(new Event('change'));
|
||||||
|
updateSleeveTaskDescription(sleeve, elems);
|
||||||
|
elems.taskSetButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "Set Task",
|
||||||
|
clickListener: () => {
|
||||||
|
setSleeveTask(sleeve, elems);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elems.taskPanel.appendChild(elems.taskSelector);
|
||||||
|
elems.taskPanel.appendChild(elems.taskDetailsSelector);
|
||||||
|
elems.taskPanel.appendChild(elems.taskDetailsSelector2);
|
||||||
|
elems.taskPanel.appendChild(elems.taskSetButton);
|
||||||
|
elems.taskPanel.appendChild(elems.taskDescription);
|
||||||
|
elems.taskPanel.appendChild(elems.taskProgressBar);
|
||||||
|
|
||||||
|
elems.earningsPanel = createElement("div", { class: "sleeve-panel", width: "35%" });
|
||||||
|
elems.currentEarningsInfo = createElement("p");
|
||||||
|
elems.totalEarningsButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "More Earnings Info",
|
||||||
|
clickListener: () => {
|
||||||
|
dialogBoxCreate(
|
||||||
|
[
|
||||||
|
"<h2><u>Earnings for Current Task:</u></h2>",
|
||||||
|
`Money: ${numeralWrapper.formatMoney(sleeve.earningsForTask.money)}`,
|
||||||
|
`Hacking Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.hack)}`,
|
||||||
|
`Strength Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.str)}`,
|
||||||
|
`Defense Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.def)}`,
|
||||||
|
`Dexterity Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.dex)}`,
|
||||||
|
`Agility Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.agi)}`,
|
||||||
|
`Charisma Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForTask.cha)}<br>`,
|
||||||
|
"<h2><u>Total Earnings for Host Consciousness:</u></h2>",
|
||||||
|
`Money: ${numeralWrapper.formatMoney(sleeve.earningsForPlayer.money)}`,
|
||||||
|
`Hacking Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.hack)}`,
|
||||||
|
`Strength Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.str)}`,
|
||||||
|
`Defense Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.def)}`,
|
||||||
|
`Dexterity Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.dex)}`,
|
||||||
|
`Agility Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.agi)}`,
|
||||||
|
`Charisma Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForPlayer.cha)}<br>`,
|
||||||
|
"<h2><u>Total Earnings for Other Sleeves:</u></h2>",
|
||||||
|
`Money: ${numeralWrapper.formatMoney(sleeve.earningsForSleeves.money)}`,
|
||||||
|
`Hacking Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.hack)}`,
|
||||||
|
`Strength Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.str)}`,
|
||||||
|
`Defense Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.def)}`,
|
||||||
|
`Dexterity Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.dex)}`,
|
||||||
|
`Agility Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.agi)}`,
|
||||||
|
`Charisma Exp: ${numeralWrapper.formatBigNumber(sleeve.earningsForSleeves.cha)}`,
|
||||||
|
].join("<br>"), false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
elems.earningsPanel.appendChild(elems.currentEarningsInfo);
|
||||||
|
elems.earningsPanel.appendChild(elems.totalEarningsButton);
|
||||||
|
|
||||||
|
updateSleeveUi(sleeve, elems);
|
||||||
|
|
||||||
|
elems.container.appendChild(elems.statsPanel);
|
||||||
|
elems.container.appendChild(elems.taskPanel);
|
||||||
|
elems.container.appendChild(elems.earningsPanel);
|
||||||
|
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the UI for a single Sleeve
|
||||||
|
function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
|
||||||
|
if (!routing.isOn(Page.Sleeves)) { return; }
|
||||||
|
|
||||||
|
elems.stats!.innerHTML = [`Hacking: ${numeralWrapper.format(sleeve.hacking_skill, "0,0")}`,
|
||||||
|
`Strength: ${numeralWrapper.format(sleeve.strength, "0,0")}`,
|
||||||
|
`Defense: ${numeralWrapper.format(sleeve.defense, "0,0")}`,
|
||||||
|
`Dexterity: ${numeralWrapper.format(sleeve.dexterity, "0,0")}`,
|
||||||
|
`Agility: ${numeralWrapper.format(sleeve.agility, "0,0")}`,
|
||||||
|
`Charisma: ${numeralWrapper.format(sleeve.charisma, "0,0")}`,
|
||||||
|
`HP: ${numeralWrapper.format(sleeve.hp, "0,0")} / ${numeralWrapper.format(sleeve.max_hp, "0,0")}`,
|
||||||
|
`City: ${sleeve.city}`,
|
||||||
|
`Shock: ${numeralWrapper.format(100 - sleeve.shock, "0,0.000")}`,
|
||||||
|
`Sync: ${numeralWrapper.format(sleeve.sync, "0,0.000")}`].join("<br>");
|
||||||
|
|
||||||
|
let repGainText: string = "";
|
||||||
|
if (sleeve.currentTask === SleeveTaskType.Company || sleeve.currentTask === SleeveTaskType.Faction) {
|
||||||
|
const repGain: number = sleeve.getRepGain(playerRef!);
|
||||||
|
repGainText = `Reputation: ${numeralWrapper.format(5 * repGain, "0.00")} / s`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sleeve.currentTask === SleeveTaskType.Crime) {
|
||||||
|
elems.currentEarningsInfo!.innerHTML = [
|
||||||
|
`Earnings (Pre-Synchronization):`,
|
||||||
|
`Money: ${numeralWrapper.formatMoney(parseFloat(sleeve.currentTaskLocation))} if successful`,
|
||||||
|
`Hacking Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.hack, "0.00")} (2x if successful)`,
|
||||||
|
`Strength Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.str, "0.00")} (2x if successful)`,
|
||||||
|
`Defense Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.def, "0.00")} (2x if successful)`,
|
||||||
|
`Dexterity Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.dex, "0.00")} (2x if successful)`,
|
||||||
|
`Agility Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.agi, "0.00")} (2x if successful)`,
|
||||||
|
`Charisma Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.cha, "0.00")} (2x if successful)`
|
||||||
|
].join("<br>");
|
||||||
|
|
||||||
|
elems.taskProgressBar!.innerText = createProgressBarText({
|
||||||
|
progress: sleeve.currentTaskTime / sleeve.currentTaskMaxTime,
|
||||||
|
totalTicks: 25,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const lines = [
|
||||||
|
`Earnings (Pre-Synchronization):`,
|
||||||
|
`Money: ${numeralWrapper.formatMoney(5 * sleeve.gainRatesForTask.money)} / s`,
|
||||||
|
`Hacking Exp: ${numeralWrapper.format(5 * sleeve.gainRatesForTask.hack, "0.00")} / s`,
|
||||||
|
`Strength Exp: ${numeralWrapper.format(5 * sleeve.gainRatesForTask.str, "0.00")} / s`,
|
||||||
|
`Defense Exp: ${numeralWrapper.format(5 * sleeve.gainRatesForTask.def, "0.00")} / s`,
|
||||||
|
`Dexterity Exp: ${numeralWrapper.format(5 * sleeve.gainRatesForTask.dex, "0.00")} / s`,
|
||||||
|
`Agility Exp: ${numeralWrapper.format(5 * sleeve.gainRatesForTask.agi, "0.00")} / s`,
|
||||||
|
`Charisma Exp: ${numeralWrapper.format(5 * sleeve.gainRatesForTask.cha, "0.00")} / s`
|
||||||
|
];
|
||||||
|
if (repGainText !== "") { lines.push(repGainText); }
|
||||||
|
elems.currentEarningsInfo!.innerHTML = lines.join("<br>");
|
||||||
|
|
||||||
|
elems.taskProgressBar!.innerText = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const universitySelectorOptions: string[] = [
|
||||||
|
"Study Computer Science",
|
||||||
|
"Data Structures",
|
||||||
|
"Networks",
|
||||||
|
"Algorithms",
|
||||||
|
"Management",
|
||||||
|
"Leadership"
|
||||||
|
];
|
||||||
|
|
||||||
|
const gymSelectorOptions: string[] = [
|
||||||
|
"Train Strength",
|
||||||
|
"Train Defense",
|
||||||
|
"Train Dexterity",
|
||||||
|
"Train Agility"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Whenever a new task is selected, the "details" selector must update accordingly
|
||||||
|
function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSleeves: Sleeve[]) {
|
||||||
|
if (playerRef == null) {
|
||||||
|
throw new Error(`playerRef is null in updateSleeveTaskSelector()`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of all companies that other sleeves are working at
|
||||||
|
const forbiddenCompanies: string[] = [];
|
||||||
|
for (const otherSleeve of allSleeves) {
|
||||||
|
if (sleeve === otherSleeve) { continue; }
|
||||||
|
if (otherSleeve.currentTask === SleeveTaskType.Company) {
|
||||||
|
forbiddenCompanies.push(otherSleeve.currentTaskLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of all factions that other sleeves are working for
|
||||||
|
const forbiddenFactions: string[] = [];
|
||||||
|
for (const otherSleeve of allSleeves) {
|
||||||
|
if (sleeve === otherSleeve) { continue; }
|
||||||
|
if (otherSleeve.currentTask === SleeveTaskType.Faction) {
|
||||||
|
forbiddenFactions.push(otherSleeve.currentTaskLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Selectors
|
||||||
|
removeChildrenFromElement(elems.taskDetailsSelector);
|
||||||
|
removeChildrenFromElement(elems.taskDetailsSelector2);
|
||||||
|
elems.taskDetailsSelector2 = clearEventListeners(elems.taskDetailsSelector2!) as HTMLSelectElement;
|
||||||
|
|
||||||
|
const value: string = getSelectValue(elems.taskSelector);
|
||||||
|
switch(value) {
|
||||||
|
case "Work for Company":
|
||||||
|
let companyCount: number = 0;
|
||||||
|
const allJobs: string[] = Object.keys(playerRef!.jobs!);
|
||||||
|
for (let i = 0; i < allJobs.length; ++i) {
|
||||||
|
if (!forbiddenCompanies.includes(allJobs[i])) {
|
||||||
|
elems.taskDetailsSelector!.add(createOptionElement(allJobs[i]));
|
||||||
|
|
||||||
|
// Set initial value of the 'Details' selector
|
||||||
|
if (sleeve.currentTaskLocation === allJobs[i]) {
|
||||||
|
elems.taskDetailsSelector!.selectedIndex = companyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
++companyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Work for Faction":
|
||||||
|
let factionCount: number = 0;
|
||||||
|
for (let i = 0; i < playerRef!.factions!.length; ++i) {
|
||||||
|
const fac: string = playerRef!.factions[i]!;
|
||||||
|
if (!forbiddenFactions.includes(fac)) {
|
||||||
|
elems.taskDetailsSelector!.add(createOptionElement(fac));
|
||||||
|
|
||||||
|
// Set initial value of the 'Details' Selector
|
||||||
|
if (sleeve.currentTaskLocation === fac) {
|
||||||
|
elems.taskDetailsSelector!.selectedIndex = factionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
++factionCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The available faction work types depends on the faction
|
||||||
|
elems.taskDetailsSelector!.addEventListener("change", () => {
|
||||||
|
const facName = getSelectValue(elems.taskDetailsSelector!);
|
||||||
|
const faction: Faction | null = Factions[facName];
|
||||||
|
if (faction == null) {
|
||||||
|
console.warn(`Invalid faction name when trying to update Sleeve Task Selector: ${facName}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const facInfo = faction.getInfo();
|
||||||
|
removeChildrenFromElement(elems.taskDetailsSelector2!);
|
||||||
|
let numOptionsAdded = 0;
|
||||||
|
if (facInfo.offerHackingWork) {
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("Hacking Contracts"));
|
||||||
|
if (sleeve.factionWorkType === FactionWorkType.Hacking) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = numOptionsAdded;
|
||||||
|
}
|
||||||
|
++numOptionsAdded;
|
||||||
|
}
|
||||||
|
if (facInfo.offerFieldWork) {
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("Field Work"));
|
||||||
|
if (sleeve.factionWorkType === FactionWorkType.Field) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = numOptionsAdded;
|
||||||
|
}
|
||||||
|
++numOptionsAdded;
|
||||||
|
}
|
||||||
|
if (facInfo.offerSecurityWork) {
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("Security Work"));
|
||||||
|
if (sleeve.factionWorkType === FactionWorkType.Security) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = numOptionsAdded;
|
||||||
|
}
|
||||||
|
++numOptionsAdded;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elems.taskDetailsSelector!.dispatchEvent(new Event("change"));
|
||||||
|
break;
|
||||||
|
case "Commit Crime":
|
||||||
|
let i = 0;
|
||||||
|
for (const crimeLabel in Crimes) {
|
||||||
|
const name: string = Crimes[crimeLabel].name;
|
||||||
|
elems.taskDetailsSelector!.add(createOptionElement(name, crimeLabel));
|
||||||
|
|
||||||
|
// Set initial value for crime type
|
||||||
|
if (sleeve.crimeType === "") { continue; }
|
||||||
|
const crime: Crime | null = Crimes[sleeve.crimeType];
|
||||||
|
if (crime == null) { continue; }
|
||||||
|
if (name === crime!.name) {
|
||||||
|
elems.taskDetailsSelector!.selectedIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||||
|
break;
|
||||||
|
case "Take University Course":
|
||||||
|
// First selector has class type
|
||||||
|
for (let i = 0; i < universitySelectorOptions.length; ++i) {
|
||||||
|
elems.taskDetailsSelector!.add(createOptionElement(universitySelectorOptions[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second selector has which university
|
||||||
|
switch (sleeve.city) {
|
||||||
|
case Cities.Aevum:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSummitUniversity));
|
||||||
|
break;
|
||||||
|
case Cities.Sector12:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12RothmanUniversity));
|
||||||
|
break;
|
||||||
|
case Cities.Volhaven:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenZBInstituteOfTechnology));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("No university available in city!"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Workout at Gym":
|
||||||
|
// First selector has what stat is being trained
|
||||||
|
for (let i = 0; i < gymSelectorOptions.length; ++i) {
|
||||||
|
elems.taskDetailsSelector!.add(createOptionElement(gymSelectorOptions[i]));
|
||||||
|
|
||||||
|
// Set initial value
|
||||||
|
if (sleeve.gymStatType === gymSelectorOptions[i]) {
|
||||||
|
elems.taskDetailsSelector!.selectedIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second selector has gym
|
||||||
|
// In this switch statement we also set the initial value of the second selector
|
||||||
|
switch (sleeve.city) {
|
||||||
|
case Cities.Aevum:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumCrushFitnessGym));
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSnapFitnessGym));
|
||||||
|
|
||||||
|
// Set initial value
|
||||||
|
if (sleeve.currentTaskLocation === Locations.AevumCrushFitnessGym) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||||
|
} else if (sleeve.currentTaskLocation === Locations.AevumSnapFitnessGym) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Cities.Sector12:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12IronGym));
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12PowerhouseGym));
|
||||||
|
|
||||||
|
// Set initial value
|
||||||
|
if (sleeve.currentTaskLocation === Locations.Sector12IronGym) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = 0;
|
||||||
|
} else if (sleeve.currentTaskLocation === Locations.Sector12PowerhouseGym) {
|
||||||
|
elems.taskDetailsSelector2!.selectedIndex = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Cities.Volhaven:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenMilleniumFitnessGym));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("No gym available in city!"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "Shock Recovery":
|
||||||
|
case "Synchronize":
|
||||||
|
case "------":
|
||||||
|
// No options in "Details" selector
|
||||||
|
elems.taskDetailsSelector!.add(createOptionElement("------"));
|
||||||
|
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): boolean {
|
||||||
|
try {
|
||||||
|
if (playerRef == null) {
|
||||||
|
throw new Error("playerRef is null in Sleeve UI's setSleeveTask()");
|
||||||
|
}
|
||||||
|
|
||||||
|
const taskValue: string = getSelectValue(elems.taskSelector);
|
||||||
|
const detailValue: string = getSelectValue(elems.taskDetailsSelector);
|
||||||
|
const detailValue2: string = getSelectValue(elems.taskDetailsSelector2);
|
||||||
|
|
||||||
|
let res: boolean = false;
|
||||||
|
switch(taskValue) {
|
||||||
|
case "------":
|
||||||
|
elems.taskDescription!.innerText = "This sleeve is currently idle";
|
||||||
|
break;
|
||||||
|
case "Work for Company":
|
||||||
|
res = sleeve.workForCompany(playerRef!, detailValue);
|
||||||
|
break;
|
||||||
|
case "Work for Faction":
|
||||||
|
res = sleeve.workForFaction(playerRef!, detailValue, detailValue2);
|
||||||
|
break;
|
||||||
|
case "Commit Crime":
|
||||||
|
res = sleeve.commitCrime(playerRef!, detailValue);
|
||||||
|
break;
|
||||||
|
case "Take University Course":
|
||||||
|
res = sleeve.takeUniversityCourse(playerRef!, detailValue2, detailValue);
|
||||||
|
break;
|
||||||
|
case "Workout at Gym":
|
||||||
|
res = sleeve.workoutAtGym(playerRef!, detailValue2, detailValue);
|
||||||
|
break;
|
||||||
|
case "Shock Recovery":
|
||||||
|
sleeve.currentTask = SleeveTaskType.Recovery;
|
||||||
|
res = true;
|
||||||
|
break;
|
||||||
|
case "Synchronize":
|
||||||
|
sleeve.currentTask = SleeveTaskType.Sync;
|
||||||
|
res = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error(`Invalid/Unrecognized taskValue in setSleeveTask(): ${taskValue}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
updateSleeveTaskDescription(sleeve, elems);
|
||||||
|
} else {
|
||||||
|
switch (taskValue) {
|
||||||
|
case "Work for Faction":
|
||||||
|
elems.taskDescription!.innerText = "Failed to assign sleeve to task. This is most likely because the selected faction does not offer the selected work type.";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing.isOn(Page.Sleeves)) {
|
||||||
|
updateSleevesPage();
|
||||||
|
|
||||||
|
// Update the task selector for all sleeves by triggering a change event
|
||||||
|
for (const e of UIElems.sleeves!) {
|
||||||
|
e.taskSelector!.dispatchEvent(new Event('change'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} catch(e) {
|
||||||
|
console.error(`Exception caught in setSleeveTask(): ${e}`);
|
||||||
|
exceptionAlert(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSleeveTaskDescription(sleeve: Sleeve, elems: ISleeveUIElems): void {
|
||||||
|
try {
|
||||||
|
if (playerRef == null) {
|
||||||
|
throw new Error("playerRef is null in Sleeve UI's setSleeveTask()");
|
||||||
|
}
|
||||||
|
|
||||||
|
const taskValue: string = getSelectValue(elems.taskSelector);
|
||||||
|
const detailValue: string = getSelectValue(elems.taskDetailsSelector);
|
||||||
|
const detailValue2: string = getSelectValue(elems.taskDetailsSelector2);
|
||||||
|
|
||||||
|
switch(taskValue) {
|
||||||
|
case "------":
|
||||||
|
elems.taskDescription!.innerText = "This sleeve is currently idle";
|
||||||
|
break;
|
||||||
|
case "Work for Company":
|
||||||
|
elems.taskDescription!.innerText = `This sleeve is currently working your job at ${sleeve.currentTaskLocation}.`;
|
||||||
|
break;
|
||||||
|
case "Work for Faction":
|
||||||
|
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ${sleeve.currentTaskLocation}.`;
|
||||||
|
break;
|
||||||
|
case "Commit Crime":
|
||||||
|
elems.taskDescription!.innerText = `This sleeve is currently attempting to ${Crimes[detailValue].type} (Success Rate: ${numeralWrapper.formatPercentage(Crimes[detailValue].successRate(playerRef))}).`;
|
||||||
|
break;
|
||||||
|
case "Take University Course":
|
||||||
|
elems.taskDescription!.innerText = `This sleeve is currently studying/taking a course at ${sleeve.currentTaskLocation}.`;
|
||||||
|
break;
|
||||||
|
case "Workout at Gym":
|
||||||
|
elems.taskDescription!.innerText = `This sleeve is currently working out at ${sleeve.currentTaskLocation}.`;
|
||||||
|
break;
|
||||||
|
case "Shock Recovery":
|
||||||
|
elems.taskDescription!.innerText = "This sleeve is currently set to focus on shock recovery. This causes " +
|
||||||
|
"the Sleeve's shock to decrease at a faster rate.";
|
||||||
|
break;
|
||||||
|
case "Synchronize":
|
||||||
|
elems.taskDescription!.innerText = "This sleeve is currently set to synchronize with the original consciousness. " +
|
||||||
|
"This causes the Sleeve's synchronization to increase."
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error(`Invalid/Unrecognized taskValue in updateSleeveTaskDescription(): ${taskValue}`);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.error(`Exception caught in updateSleeveTaskDescription(): ${e}`);
|
||||||
|
exceptionAlert(e);
|
||||||
|
}
|
||||||
|
}
|
36
src/PersonObjects/Sleeve/data/SleeveFaq.ts
Normal file
36
src/PersonObjects/Sleeve/data/SleeveFaq.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export const SleeveFaq: string =
|
||||||
|
[
|
||||||
|
"<strong><u>How do sleeves work?</strong></u><br>",
|
||||||
|
"Sleeves are essentially clones. You can use them to perform any work type",
|
||||||
|
"action, such as working for a company/faction or committing a crime.",
|
||||||
|
"Having sleeves perform these tasks earns you money, experience, and reputation.<br><br>",
|
||||||
|
"Sleeves are their own individuals, which means they each have their own",
|
||||||
|
"experience and stats.<br><br>",
|
||||||
|
"When a sleeve earns experience, it earns experience for itself, the player's",
|
||||||
|
"original 'consciousness', as well as all of the player's other sleeves.<br><br>",
|
||||||
|
|
||||||
|
"<strong><u>What is Synchronization (Sync)?</strong></u><br>",
|
||||||
|
"Synchronization is a measure of how aligned your consciousness is with",
|
||||||
|
"that of your Duplicate Sleeves. It is a numerical value between 1 and 100, and",
|
||||||
|
"it affects how much experience is earned when the sleeve is performing a task.<br><br>",
|
||||||
|
"Let N be the sleeve's synchronization. When the sleeve earns experience by performing a",
|
||||||
|
"task, both the sleeve and the player's original host consciousness earn N%",
|
||||||
|
"of the amount of experience normally earned by the task. All of the player's",
|
||||||
|
"other sleeves earn ((N/100)^2 * 100)% of the experience.<br><br>",
|
||||||
|
"Synchronization can be increased by assigning sleeves to the 'Synchronize' task.<br><br>",
|
||||||
|
|
||||||
|
"<strong><u>What is Shock?</u></strong><br>",
|
||||||
|
"Sleeve shock is a measure of how much trauma the sleeve has due to being placed in a new",
|
||||||
|
"body. It is a numerical value between 0 and 99, where 99 indicates full shock and 0 indicates",
|
||||||
|
"no shock. Shock affects the amount of experience earned by the sleeve.<br><br>",
|
||||||
|
"Sleeve shock slowly decreases over time. You can further increase the rate at which",
|
||||||
|
"it decreases by assigning sleeves to the 'Shock Recovery' task.<br><br>",
|
||||||
|
|
||||||
|
"<strong><u>Why can't I work for this company or faction?</u></strong><br>",
|
||||||
|
"Only one of your sleeves can work for a given company/faction a time.",
|
||||||
|
"To clarify further, if you have two sleeves they can work for two different",
|
||||||
|
"companies, but they cannot both work for the same company.<br><br>",
|
||||||
|
|
||||||
|
"<strong><u>Do sleeves get reset when installing Augmentations or switching BitNodes?</u></strong><br>",
|
||||||
|
"Sleeves are reset when switching BitNodes, but not when installing Augmentations."
|
||||||
|
].join(" ");
|
220
src/Player.js
220
src/Player.js
@ -1,8 +1,9 @@
|
|||||||
import { Augmentations,
|
import { Augmentations } from "./Augmentation/Augmentations";
|
||||||
applyAugmentation,
|
import { applyAugmentation } from "./Augmentation/AugmentationHelpers";
|
||||||
AugmentationNames,
|
import { PlayerOwnedAugmentation } from "./Augmentation/PlayerOwnedAugmentation";
|
||||||
PlayerOwnedAugmentation } from "./Augmentations";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
|
import { Bladeburner } from "./Bladeburner";
|
||||||
import { CodingContractRewardType } from "./CodingContracts";
|
import { CodingContractRewardType } from "./CodingContracts";
|
||||||
import { Company } from "./Company/Company";
|
import { Company } from "./Company/Company";
|
||||||
import { Companies } from "./Company/Companies";
|
import { Companies } from "./Company/Companies";
|
||||||
@ -13,7 +14,8 @@ import * as posNames from "./Company/data/CompanyPosi
|
|||||||
import {CONSTANTS} from "./Constants";
|
import {CONSTANTS} from "./Constants";
|
||||||
import { Corporation } from "./Corporation/Corporation";
|
import { Corporation } from "./Corporation/Corporation";
|
||||||
import { Programs } from "./Programs/Programs";
|
import { Programs } from "./Programs/Programs";
|
||||||
import {determineCrimeSuccess, Crimes} from "./Crimes";
|
import { determineCrimeSuccess } from "./Crime/CrimeHelpers";
|
||||||
|
import { Crimes } from "./Crime/Crimes";
|
||||||
import {Engine} from "./engine";
|
import {Engine} from "./engine";
|
||||||
import { Faction } from "./Faction/Faction";
|
import { Faction } from "./Faction/Faction";
|
||||||
import { Factions } from "./Faction/Factions";
|
import { Factions } from "./Faction/Factions";
|
||||||
@ -21,10 +23,12 @@ import { displayFactionContent } from "./Faction/FactionHelpers";
|
|||||||
import {Gang, resetGangs} from "./Gang";
|
import {Gang, resetGangs} from "./Gang";
|
||||||
import {Locations} from "./Locations";
|
import {Locations} from "./Locations";
|
||||||
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
|
import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions";
|
||||||
|
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
||||||
import {AllServers, Server, AddToAllServers} from "./Server";
|
import {AllServers, Server, AddToAllServers} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import {Settings} from "./Settings/Settings";
|
||||||
import {SpecialServerIps, SpecialServerNames} from "./SpecialServerIps";
|
import {SpecialServerIps, SpecialServerNames} from "./SpecialServerIps";
|
||||||
import {SourceFiles, applySourceFile} from "./SourceFile";
|
import {SourceFiles, applySourceFile} from "./SourceFile";
|
||||||
|
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||||
import Decimal from "decimal.js";
|
import Decimal from "decimal.js";
|
||||||
import {numeralWrapper} from "./ui/numeralFormat";
|
import {numeralWrapper} from "./ui/numeralFormat";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||||
@ -98,9 +102,13 @@ function PlayerObject() {
|
|||||||
this.city = Locations.Sector12;
|
this.city = Locations.Sector12;
|
||||||
this.location = "";
|
this.location = "";
|
||||||
|
|
||||||
//Company Information
|
// Jobs that the player holds
|
||||||
|
// Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object)
|
||||||
|
// The CompanyPosition name must match a key value in CompanyPositions
|
||||||
|
this.jobs = {};
|
||||||
|
|
||||||
|
// Company at which player is CURRENTLY working (only valid when the player is actively working)
|
||||||
this.companyName = ""; // Name of Company. Must match a key value in Companies map
|
this.companyName = ""; // Name of Company. Must match a key value in Companies map
|
||||||
this.companyPosition = ""; // Name of Company Position. Must match a key value in CompanyPositions map
|
|
||||||
|
|
||||||
//Servers
|
//Servers
|
||||||
this.currentServer = ""; //IP address of Server currently being accessed through terminal
|
this.currentServer = ""; //IP address of Server currently being accessed through terminal
|
||||||
@ -190,6 +198,11 @@ function PlayerObject() {
|
|||||||
this.bladeburner_analysis_mult = 1; //Field Analysis Only
|
this.bladeburner_analysis_mult = 1; //Field Analysis Only
|
||||||
this.bladeburner_success_chance_mult = 1;
|
this.bladeburner_success_chance_mult = 1;
|
||||||
|
|
||||||
|
// Sleeves & Re-sleeving
|
||||||
|
this.sleeves = [];
|
||||||
|
this.resleeves = [];
|
||||||
|
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant
|
||||||
|
|
||||||
//bitnode
|
//bitnode
|
||||||
this.bitNodeN = 1;
|
this.bitNodeN = 1;
|
||||||
|
|
||||||
@ -256,7 +269,7 @@ PlayerObject.prototype.prestigeAugmentation = function() {
|
|||||||
this.location = "";
|
this.location = "";
|
||||||
|
|
||||||
this.companyName = "";
|
this.companyName = "";
|
||||||
this.companyPosition = "";
|
this.jobs = {};
|
||||||
|
|
||||||
this.purchasedServers = [];
|
this.purchasedServers = [];
|
||||||
|
|
||||||
@ -265,6 +278,14 @@ PlayerObject.prototype.prestigeAugmentation = function() {
|
|||||||
|
|
||||||
this.queuedAugmentations = [];
|
this.queuedAugmentations = [];
|
||||||
|
|
||||||
|
this.resleeves = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.sleeves.length; ++i) {
|
||||||
|
if (this.sleeves[i] instanceof Sleeve) {
|
||||||
|
this.sleeves[i].resetTaskStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.isWorking = false;
|
this.isWorking = false;
|
||||||
this.currentWorkFactionName = "";
|
this.currentWorkFactionName = "";
|
||||||
this.currentWorkFactionDescription = "";
|
this.currentWorkFactionDescription = "";
|
||||||
@ -336,7 +357,7 @@ PlayerObject.prototype.prestigeSourceFile = function() {
|
|||||||
this.location = "";
|
this.location = "";
|
||||||
|
|
||||||
this.companyName = "";
|
this.companyName = "";
|
||||||
this.companyPosition = "";
|
this.jobs = {};
|
||||||
|
|
||||||
this.purchasedServers = [];
|
this.purchasedServers = [];
|
||||||
|
|
||||||
@ -346,6 +367,14 @@ PlayerObject.prototype.prestigeSourceFile = function() {
|
|||||||
this.queuedAugmentations = [];
|
this.queuedAugmentations = [];
|
||||||
this.augmentations = [];
|
this.augmentations = [];
|
||||||
|
|
||||||
|
this.resleeves = [];
|
||||||
|
|
||||||
|
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
|
||||||
|
this.sleeves.length = SourceFileFlags[10] + this.sleevesFromCovenant;
|
||||||
|
for (let i = 0; i < this.sleeves.length; ++i) {
|
||||||
|
this.sleeves[i] = new Sleeve();
|
||||||
|
}
|
||||||
|
|
||||||
this.isWorking = false;
|
this.isWorking = false;
|
||||||
this.currentWorkFactionName = "";
|
this.currentWorkFactionName = "";
|
||||||
this.currentWorkFactionDescription = "";
|
this.currentWorkFactionDescription = "";
|
||||||
@ -434,11 +463,11 @@ PlayerObject.prototype.calculateSkill = function(exp, mult=1) {
|
|||||||
|
|
||||||
PlayerObject.prototype.updateSkillLevels = function() {
|
PlayerObject.prototype.updateSkillLevels = function() {
|
||||||
this.hacking_skill = Math.max(1, Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
|
this.hacking_skill = Math.max(1, Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier)));
|
||||||
this.strength = this.calculateSkill(this.strength_exp, this.strength_mult);
|
this.strength = Math.max(1, Math.floor(this.calculateSkill(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier)));
|
||||||
this.defense = this.calculateSkill(this.defense_exp, this.defense_mult);
|
this.defense = Math.max(1, Math.floor(this.calculateSkill(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier)));
|
||||||
this.dexterity = this.calculateSkill(this.dexterity_exp, this.dexterity_mult);
|
this.dexterity = Math.max(1, Math.floor(this.calculateSkill(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier)));
|
||||||
this.agility = this.calculateSkill(this.agility_exp, this.agility_mult);
|
this.agility = Math.max(1, Math.floor(this.calculateSkill(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier)));
|
||||||
this.charisma = this.calculateSkill(this.charisma_exp, this.charisma_mult);
|
this.charisma = Math.max(1, Math.floor(this.calculateSkill(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier)));
|
||||||
|
|
||||||
if (this.intelligence > 0) {
|
if (this.intelligence > 0) {
|
||||||
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
|
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
|
||||||
@ -524,6 +553,14 @@ PlayerObject.prototype.loseMoney = function(money) {
|
|||||||
this.money = this.money.minus(money);
|
this.money = this.money.minus(money);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlayerObject.prototype.canAfford = function(cost) {
|
||||||
|
if (isNaN(cost)) {
|
||||||
|
console.error(`NaN passed into Player.canAfford()`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.money.gte(cost);
|
||||||
|
}
|
||||||
|
|
||||||
PlayerObject.prototype.gainHackingExp = function(exp) {
|
PlayerObject.prototype.gainHackingExp = function(exp) {
|
||||||
if (isNaN(exp)) {
|
if (isNaN(exp)) {
|
||||||
console.log("ERR: NaN passed into Player.gainHackingExp()"); return;
|
console.log("ERR: NaN passed into Player.gainHackingExp()"); return;
|
||||||
@ -665,9 +702,10 @@ PlayerObject.prototype.processWorkEarnings = function(numCycles=1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Working for Company */
|
/* Working for Company */
|
||||||
PlayerObject.prototype.startWork = function() {
|
PlayerObject.prototype.startWork = function(companyName) {
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
|
this.companyName = companyName;
|
||||||
this.workType = CONSTANTS.WorkTypeCompany;
|
this.workType = CONSTANTS.WorkTypeCompany;
|
||||||
|
|
||||||
this.workHackExpGainRate = this.getWorkHackExpGain();
|
this.workHackExpGainRate = this.getWorkHackExpGain();
|
||||||
@ -718,8 +756,10 @@ PlayerObject.prototype.work = function(numCycles) {
|
|||||||
companyRep = comp.playerReputation;
|
companyRep = comp.playerReputation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const position = this.jobs[this.companyName];
|
||||||
|
|
||||||
var txt = document.getElementById("work-in-progress-text");
|
var txt = document.getElementById("work-in-progress-text");
|
||||||
txt.innerHTML = "You are currently working as a " + this.companyPosition +
|
txt.innerHTML = "You are currently working as a " + position +
|
||||||
" at " + this.companyName + " (Current Company Reputation: " +
|
" at " + this.companyName + " (Current Company Reputation: " +
|
||||||
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
|
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
|
||||||
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
|
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
|
||||||
@ -786,9 +826,10 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) {
|
|||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerObject.prototype.startWorkPartTime = function() {
|
PlayerObject.prototype.startWorkPartTime = function(companyName) {
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
|
this.companyName = companyName;
|
||||||
this.workType = CONSTANTS.WorkTypeCompanyPartTime;
|
this.workType = CONSTANTS.WorkTypeCompanyPartTime;
|
||||||
|
|
||||||
this.workHackExpGainRate = this.getWorkHackExpGain();
|
this.workHackExpGainRate = this.getWorkHackExpGain();
|
||||||
@ -838,9 +879,11 @@ PlayerObject.prototype.workPartTime = function(numCycles) {
|
|||||||
companyRep = comp.playerReputation;
|
companyRep = comp.playerReputation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const position = this.jobs[this.companyName];
|
||||||
|
|
||||||
var txt = document.getElementById("work-in-progress-text");
|
var txt = document.getElementById("work-in-progress-text");
|
||||||
txt.innerHTML = "You are currently working as a " + this.companyPosition +
|
txt.innerHTML = "You are currently working as a " + position +
|
||||||
" at " + Player.companyName + " (Current Company Reputation: " +
|
" at " + this.companyName + " (Current Company Reputation: " +
|
||||||
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
|
numeralWrapper.format(companyRep, '0,0') + ")<br><br>" +
|
||||||
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
|
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
|
||||||
"You have earned: <br><br>" +
|
"You have earned: <br><br>" +
|
||||||
@ -1073,9 +1116,10 @@ PlayerObject.prototype.getWorkMoneyGain = function() {
|
|||||||
if (hasBn11SF) { bn11Mult = 1 + (company.favor / 100); }
|
if (hasBn11SF) { bn11Mult = 1 + (company.favor / 100); }
|
||||||
|
|
||||||
// Get base salary
|
// Get base salary
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (companyPosition == null) {
|
if (companyPosition == null) {
|
||||||
console.error(`Could not find CompanyPosition object for ${this.companyPosition}. Work salary will be 0`);
|
console.error(`Could not find CompanyPosition object for ${companyPositionName}. Work salary will be 0`);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1085,10 +1129,11 @@ PlayerObject.prototype.getWorkMoneyGain = function() {
|
|||||||
//Hack exp gained per game cycle
|
//Hack exp gained per game cycle
|
||||||
PlayerObject.prototype.getWorkHackExpGain = function() {
|
PlayerObject.prototype.getWorkHackExpGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work hack exp gain will be 0`].join(" "));
|
`Work hack exp gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1099,10 +1144,11 @@ PlayerObject.prototype.getWorkHackExpGain = function() {
|
|||||||
//Str exp gained per game cycle
|
//Str exp gained per game cycle
|
||||||
PlayerObject.prototype.getWorkStrExpGain = function() {
|
PlayerObject.prototype.getWorkStrExpGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work str exp gain will be 0`].join(" "));
|
`Work str exp gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1113,10 +1159,11 @@ PlayerObject.prototype.getWorkStrExpGain = function() {
|
|||||||
//Def exp gained per game cycle
|
//Def exp gained per game cycle
|
||||||
PlayerObject.prototype.getWorkDefExpGain = function() {
|
PlayerObject.prototype.getWorkDefExpGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work def exp gain will be 0`].join(" "));
|
`Work def exp gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1127,10 +1174,11 @@ PlayerObject.prototype.getWorkDefExpGain = function() {
|
|||||||
//Dex exp gained per game cycle
|
//Dex exp gained per game cycle
|
||||||
PlayerObject.prototype.getWorkDexExpGain = function() {
|
PlayerObject.prototype.getWorkDexExpGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work dex exp gain will be 0`].join(" "));
|
`Work dex exp gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1141,10 +1189,11 @@ PlayerObject.prototype.getWorkDexExpGain = function() {
|
|||||||
//Agi exp gained per game cycle
|
//Agi exp gained per game cycle
|
||||||
PlayerObject.prototype.getWorkAgiExpGain = function() {
|
PlayerObject.prototype.getWorkAgiExpGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work agi exp gain will be 0`].join(" "));
|
`Work agi exp gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1155,10 +1204,11 @@ PlayerObject.prototype.getWorkAgiExpGain = function() {
|
|||||||
//Charisma exp gained per game cycle
|
//Charisma exp gained per game cycle
|
||||||
PlayerObject.prototype.getWorkChaExpGain = function() {
|
PlayerObject.prototype.getWorkChaExpGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work cha exp gain will be 0`].join(" "));
|
`Work cha exp gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1169,10 +1219,11 @@ PlayerObject.prototype.getWorkChaExpGain = function() {
|
|||||||
//Reputation gained per game cycle
|
//Reputation gained per game cycle
|
||||||
PlayerObject.prototype.getWorkRepGain = function() {
|
PlayerObject.prototype.getWorkRepGain = function() {
|
||||||
const company = Companies[this.companyName];
|
const company = Companies[this.companyName];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
const companyPositionName = this.jobs[this.companyName];
|
||||||
|
const companyPosition = CompanyPositions[companyPositionName];
|
||||||
if (company == null || companyPosition == null) {
|
if (company == null || companyPosition == null) {
|
||||||
console.error([`Could not find Company object for ${this.companyName}`,
|
console.error([`Could not find Company object for ${this.companyName}`,
|
||||||
`or CompanyPosition object for ${this.companyPosition}.`,
|
`or CompanyPosition object for ${companyPositionName}.`,
|
||||||
`Work rep gain will be 0`].join(" "));
|
`Work rep gain will be 0`].join(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1455,7 +1506,9 @@ PlayerObject.prototype.finishClass = function(sing=false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//The EXP and $ gains are hardcoded. Time is in ms
|
//The EXP and $ gains are hardcoded. Time is in ms
|
||||||
PlayerObject.prototype.startCrime = function(hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams=null) {
|
PlayerObject.prototype.startCrime = function(crimeType, hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams=null) {
|
||||||
|
this.crimeType = crimeType;
|
||||||
|
|
||||||
this.resetWorkStatus();
|
this.resetWorkStatus();
|
||||||
this.isWorking = true;
|
this.isWorking = true;
|
||||||
this.workType = CONSTANTS.WorkTypeCrime;
|
this.workType = CONSTANTS.WorkTypeCrime;
|
||||||
@ -1669,7 +1722,7 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
|
|||||||
if (this.companyName !== "") {
|
if (this.companyName !== "") {
|
||||||
currCompany = Companies[this.companyName];
|
currCompany = Companies[this.companyName];
|
||||||
}
|
}
|
||||||
const currPositionName = this.companyPosition;
|
const currPositionName = this.jobs[this.companyName];
|
||||||
|
|
||||||
// Get company that's being applied to
|
// Get company that's being applied to
|
||||||
const company = Companies[this.location]; //Company being applied to
|
const company = Companies[this.location]; //Company being applied to
|
||||||
@ -1726,33 +1779,14 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Lose reputation from a Company if you are leaving it for another job
|
|
||||||
let leaveCompany = false;
|
|
||||||
let oldCompanyName = "";
|
|
||||||
if (currCompany != null) {
|
|
||||||
if (currCompany.name != company.name) {
|
|
||||||
leaveCompany = true;
|
|
||||||
oldCompanyName = currCompany.name;
|
|
||||||
currCompany.playerReputation -= 1000;
|
|
||||||
if (currCompany.playerReputation < 0) { currCompany.playerReputation = 0; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.companyPosition = pos.name;
|
this.jobs[company.name] = pos.name;
|
||||||
|
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
|
|
||||||
if (leaveCompany) {
|
if (sing) { return true; }
|
||||||
if (sing) { return true; }
|
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
|
||||||
dialogBoxCreate([`Congratulations! You were offered a new job at ${this.companyName} as a ${pos.name}!`,
|
|
||||||
`You lost 1000 reputation at your old company ${oldCompanyName} because you left.`].join("<br>"));
|
|
||||||
} else {
|
|
||||||
if (sing) { return true; }
|
|
||||||
dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine.loadLocationContent();
|
Engine.loadLocationContent();
|
||||||
}
|
}
|
||||||
@ -1772,7 +1806,8 @@ PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType)
|
|||||||
//If the entry pos type and the player's current position have the same type,
|
//If the entry pos type and the player's current position have the same type,
|
||||||
//return the player's "nextCompanyPosition". Otherwise return the entryposType
|
//return the player's "nextCompanyPosition". Otherwise return the entryposType
|
||||||
//Employed at this company, so just return the next position if it exists.
|
//Employed at this company, so just return the next position if it exists.
|
||||||
const currentPosition = CompanyPositions[this.companyPosition];
|
const currentPositionName = this.jobs[this.companyName];
|
||||||
|
const currentPosition = CompanyPositions[currentPositionName];
|
||||||
if ((currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) ||
|
if ((currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) ||
|
||||||
(currentPosition.isITJob() && entryPosType.isITJob()) ||
|
(currentPosition.isITJob() && entryPosType.isITJob()) ||
|
||||||
(currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) ||
|
(currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) ||
|
||||||
@ -1849,7 +1884,7 @@ PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
|
|||||||
var company = Companies[this.location]; //Company being applied to
|
var company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.companyPosition = posNames.MiscCompanyPositions[1];
|
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
if (sing) {return true;}
|
if (sing) {return true;}
|
||||||
@ -1865,7 +1900,7 @@ PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
|
|||||||
var company = Companies[this.location]; //Company being applied to
|
var company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.companyPosition = posNames.PartTimeCompanyPositions[1];
|
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
if (sing) {return true;}
|
if (sing) {return true;}
|
||||||
@ -1881,7 +1916,7 @@ PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
|
|||||||
var company = Companies[this.location]; //Company being applied to
|
var company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.companyPosition = posNames.MiscCompanyPositions[0];
|
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
if (sing) {return true;}
|
if (sing) {return true;}
|
||||||
@ -1897,7 +1932,7 @@ PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) {
|
|||||||
var company = Companies[this.location]; //Company being applied to
|
var company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.companyPosition = posNames.PartTimeCompanyPositions[0];
|
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
if (sing) {return true;}
|
if (sing) {return true;}
|
||||||
@ -1992,6 +2027,9 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
companyRep = company.playerReputation;
|
companyRep = company.playerReputation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allCompanies = Object.keys(this.jobs);
|
||||||
|
const allPositions = Object.values(this.jobs);
|
||||||
|
|
||||||
//Illuminati
|
//Illuminati
|
||||||
var illuminatiFac = Factions["Illuminati"];
|
var illuminatiFac = Factions["Illuminati"];
|
||||||
if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited &&
|
if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited &&
|
||||||
@ -2030,14 +2068,14 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
//ECorp
|
//ECorp
|
||||||
var ecorpFac = Factions["ECorp"];
|
var ecorpFac = Factions["ECorp"];
|
||||||
if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited &&
|
if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited &&
|
||||||
this.companyName == Locations.AevumECorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.AevumECorp) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(ecorpFac);
|
invitedFactions.push(ecorpFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//MegaCorp
|
//MegaCorp
|
||||||
var megacorpFac = Factions["MegaCorp"];
|
var megacorpFac = Factions["MegaCorp"];
|
||||||
if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited &&
|
if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited &&
|
||||||
this.companyName == Locations.Sector12MegaCorp && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.Sector12MegaCorp) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(megacorpFac);
|
invitedFactions.push(megacorpFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2045,42 +2083,42 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
var bachmanandassociatesFac = Factions["Bachman & Associates"];
|
var bachmanandassociatesFac = Factions["Bachman & Associates"];
|
||||||
if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember &&
|
if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember &&
|
||||||
!bachmanandassociatesFac.alreadyInvited &&
|
!bachmanandassociatesFac.alreadyInvited &&
|
||||||
this.companyName == Locations.AevumBachmanAndAssociates && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.AevumBachmanAndAssociates) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(bachmanandassociatesFac);
|
invitedFactions.push(bachmanandassociatesFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Blade Industries
|
//Blade Industries
|
||||||
var bladeindustriesFac = Factions["Blade Industries"];
|
var bladeindustriesFac = Factions["Blade Industries"];
|
||||||
if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited &&
|
if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited &&
|
||||||
this.companyName == Locations.Sector12BladeIndustries && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.Sector12BladeIndustries) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(bladeindustriesFac);
|
invitedFactions.push(bladeindustriesFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//NWO
|
//NWO
|
||||||
var nwoFac = Factions["NWO"];
|
var nwoFac = Factions["NWO"];
|
||||||
if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited &&
|
if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited &&
|
||||||
this.companyName == Locations.VolhavenNWO && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.VolhavenNWO) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(nwoFac);
|
invitedFactions.push(nwoFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clarke Incorporated
|
//Clarke Incorporated
|
||||||
var clarkeincorporatedFac = Factions["Clarke Incorporated"];
|
var clarkeincorporatedFac = Factions["Clarke Incorporated"];
|
||||||
if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited &&
|
if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited &&
|
||||||
this.companyName == Locations.AevumClarkeIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.AevumClarkeIncorporated) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(clarkeincorporatedFac);
|
invitedFactions.push(clarkeincorporatedFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//OmniTek Incorporated
|
//OmniTek Incorporated
|
||||||
var omnitekincorporatedFac = Factions["OmniTek Incorporated"];
|
var omnitekincorporatedFac = Factions["OmniTek Incorporated"];
|
||||||
if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited &&
|
if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited &&
|
||||||
this.companyName == Locations.VolhavenOmniTekIncorporated && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.VolhavenOmniTekIncorporated) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(omnitekincorporatedFac);
|
invitedFactions.push(omnitekincorporatedFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Four Sigma
|
//Four Sigma
|
||||||
var foursigmaFac = Factions["Four Sigma"];
|
var foursigmaFac = Factions["Four Sigma"];
|
||||||
if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited &&
|
if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited &&
|
||||||
this.companyName == Locations.Sector12FourSigma && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.Sector12FourSigma) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(foursigmaFac);
|
invitedFactions.push(foursigmaFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2088,7 +2126,7 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
var kuaigonginternationalFac = Factions["KuaiGong International"];
|
var kuaigonginternationalFac = Factions["KuaiGong International"];
|
||||||
if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember &&
|
if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember &&
|
||||||
!kuaigonginternationalFac.alreadyInvited &&
|
!kuaigonginternationalFac.alreadyInvited &&
|
||||||
this.companyName == Locations.ChongqingKuaiGongInternational && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
allCompanies.includes(Locations.ChongqingKuaiGongInternational) && companyRep >= CONSTANTS.CorpFactionRepRequirement) {
|
||||||
invitedFactions.push(kuaigonginternationalFac);
|
invitedFactions.push(kuaigonginternationalFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2101,7 +2139,7 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
|
if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember &&
|
||||||
!fulcrumsecrettechonologiesFac.alreadyInvited &&
|
!fulcrumsecrettechonologiesFac.alreadyInvited &&
|
||||||
fulcrumSecretServer.manuallyHacked &&
|
fulcrumSecretServer.manuallyHacked &&
|
||||||
this.companyName == Locations.AevumFulcrumTechnologies && companyRep >= 250000) {
|
allCompanies.includes(Locations.AevumFulcrumTechnologies) && companyRep >= 250000) {
|
||||||
invitedFactions.push(fulcrumsecrettechonologiesFac);
|
invitedFactions.push(fulcrumsecrettechonologiesFac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2184,8 +2222,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited &&
|
if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited &&
|
||||||
this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 &&
|
this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 &&
|
||||||
this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 &&
|
this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 &&
|
||||||
this.karma <= -45 && this.companyName != Locations.Sector12CIA &&
|
this.karma <= -45 && !allCompanies.includes(Locations.Sector12CIA) &&
|
||||||
this.companyName != Locations.Sector12NSA) {
|
!allCompanies.includes(Locations.Sector12NSA)) {
|
||||||
invitedFactions.push(speakersforthedeadFac);
|
invitedFactions.push(speakersforthedeadFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2194,8 +2232,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited &&
|
if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited &&
|
||||||
this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 &&
|
this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 &&
|
||||||
this.dexterity >= 300 && this.agility >= 300 && this.city == Locations.Chongqing &&
|
this.dexterity >= 300 && this.agility >= 300 && this.city == Locations.Chongqing &&
|
||||||
this.numPeopleKilled >= 5 && this.karma <= -45 && this.companyName != Locations.Sector12CIA &&
|
this.numPeopleKilled >= 5 && this.karma <= -45 && !allCompanies.includes(Locations.Sector12CIA) &&
|
||||||
this.companyName != Locations.Sector12NSA) {
|
!allCompanies.includes(Locations.Sector12NSA)) {
|
||||||
invitedFactions.push(thedarkarmyFac);
|
invitedFactions.push(thedarkarmyFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2206,18 +2244,16 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
|
|||||||
this.dexterity >= 200 && this.agility >= 200 &&
|
this.dexterity >= 200 && this.agility >= 200 &&
|
||||||
(this.city == Locations.Aevum || this.city == Locations.Sector12) &&
|
(this.city == Locations.Aevum || this.city == Locations.Sector12) &&
|
||||||
this.money.gte(10000000) && this.karma <= -90 &&
|
this.money.gte(10000000) && this.karma <= -90 &&
|
||||||
this.companyName != Locations.Sector12CIA && this.companyName != Locations.Sector12NSA) {
|
!allCompanies.includes(Locations.Sector12CIA) && !allCompanies.includes(Locations.Sector12NSA)) {
|
||||||
invitedFactions.push(thesyndicateFac);
|
invitedFactions.push(thesyndicateFac);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Silhouette
|
//Silhouette
|
||||||
var silhouetteFac = Factions["Silhouette"];
|
var silhouetteFac = Factions["Silhouette"];
|
||||||
const companyPosition = CompanyPositions[this.companyPosition];
|
|
||||||
if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited &&
|
if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited &&
|
||||||
companyPosition != null &&
|
(allPositions.includes("Chief Technology Officer") ||
|
||||||
(companyPosition.name == "Chief Technology Officer" ||
|
allPositions.includes("Chief Financial Officer") ||
|
||||||
companyPosition.name == "Chief Financial Officer" ||
|
allPositions.includes("Chief Executive Officer")) &&
|
||||||
companyPosition.name == "Chief Executive Officer") &&
|
|
||||||
this.money.gte(15000000) && this.karma <= -22) {
|
this.money.gte(15000000) && this.karma <= -22) {
|
||||||
invitedFactions.push(silhouetteFac);
|
invitedFactions.push(silhouetteFac);
|
||||||
}
|
}
|
||||||
@ -2289,6 +2325,18 @@ PlayerObject.prototype.startGang = function(factionName, hacking) {
|
|||||||
this.gang = new Gang(factionName, hacking);
|
this.gang = new Gang(factionName, hacking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************** Corporation ****************/
|
||||||
|
PlayerObject.prototype.hasCorporation = function() {
|
||||||
|
if (this.corporation == null) { return false; }
|
||||||
|
return (this.corporation instanceof Corporation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************** Bladeburner ****************/
|
||||||
|
PlayerObject.prototype.inBladeburner = function() {
|
||||||
|
if (this.bladeburner == null) { return false; }
|
||||||
|
return (this.bladeburner instanceof Bladeburner);
|
||||||
|
}
|
||||||
|
|
||||||
/************* BitNodes **************/
|
/************* BitNodes **************/
|
||||||
PlayerObject.prototype.setBitNodeNumber = function(n) {
|
PlayerObject.prototype.setBitNodeNumber = function(n) {
|
||||||
this.bitNodeN = n;
|
this.bitNodeN = n;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import {deleteActiveScriptsItem} from "./ActiveScriptsUI";
|
import {deleteActiveScriptsItem} from "./ActiveScriptsUI";
|
||||||
import {Augmentations, augmentationExists,
|
import { Augmentations } from "./Augmentation/Augmentations";
|
||||||
initAugmentations, AugmentationNames} from "./Augmentations";
|
import { augmentationExists,
|
||||||
import {initBitNodeMultipliers} from "./BitNode";
|
initAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||||
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
|
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||||
import {Bladeburner} from "./Bladeburner";
|
import {Bladeburner} from "./Bladeburner";
|
||||||
import {writeCinematicText} from "./CinematicText";
|
import {writeCinematicText} from "./CinematicText";
|
||||||
import {Companies, initCompanies} from "./Company/Companies";
|
import {Companies, initCompanies} from "./Company/Companies";
|
||||||
@ -24,12 +26,13 @@ import {AllServers, AddToAllServers,
|
|||||||
initForeignServers, Server,
|
initForeignServers, Server,
|
||||||
prestigeAllServers,
|
prestigeAllServers,
|
||||||
prestigeHomeComputer} from "./Server";
|
prestigeHomeComputer} from "./Server";
|
||||||
|
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||||
import {SpecialServerIps, SpecialServerIpsMap,
|
import {SpecialServerIps, SpecialServerIpsMap,
|
||||||
prestigeSpecialServerIps,
|
prestigeSpecialServerIps,
|
||||||
SpecialServerNames} from "./SpecialServerIps";
|
SpecialServerNames} from "./SpecialServerIps";
|
||||||
import {initStockMarket, initSymbolToStockMap,
|
import {initStockMarket, initSymbolToStockMap,
|
||||||
stockMarketContentCreated,
|
stockMarketContentCreated,
|
||||||
setStockMarketContentCreated} from "./StockMarket";
|
setStockMarketContentCreated} from "./StockMarket/StockMarket";
|
||||||
import {Terminal, postNetburnerText} from "./Terminal";
|
import {Terminal, postNetburnerText} from "./Terminal";
|
||||||
import Decimal from "decimal.js";
|
import Decimal from "decimal.js";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||||
@ -169,6 +172,7 @@ function prestigeAugmentation() {
|
|||||||
//Prestige by destroying Bit Node and gaining a Source File
|
//Prestige by destroying Bit Node and gaining a Source File
|
||||||
function prestigeSourceFile() {
|
function prestigeSourceFile() {
|
||||||
initBitNodeMultipliers();
|
initBitNodeMultipliers();
|
||||||
|
updateSourceFileFlags(Player);
|
||||||
|
|
||||||
Player.prestigeSourceFile();
|
Player.prestigeSourceFile();
|
||||||
prestigeWorkerScripts(); //Delete all Worker Scripts objects
|
prestigeWorkerScripts(); //Delete all Worker Scripts objects
|
||||||
@ -307,6 +311,11 @@ function prestigeSourceFile() {
|
|||||||
Player.hasTixApiAccess = true;
|
Player.hasTixApiAccess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bit Node 10: Digital Carbon
|
||||||
|
if (Player.bitNodeN === 10) {
|
||||||
|
dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!");
|
||||||
|
}
|
||||||
|
|
||||||
//Reset Stock market, gang, and corporation
|
//Reset Stock market, gang, and corporation
|
||||||
if (Player.hasWseAccount) {
|
if (Player.hasWseAccount) {
|
||||||
initStockMarket();
|
initStockMarket();
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import {BitNodes} from "./BitNode";
|
import { BitNodes } from "./BitNode/BitNode";
|
||||||
import {Engine} from "./engine";
|
import { Engine } from "./engine";
|
||||||
import {Player} from "./Player";
|
import { Player } from "./Player";
|
||||||
import {prestigeSourceFile} from "./Prestige";
|
import { prestigeSourceFile } from "./Prestige";
|
||||||
import {SourceFiles, SourceFile,
|
import { SourceFiles,
|
||||||
PlayerOwnedSourceFile} from "./SourceFile";
|
SourceFile } from "./SourceFile";
|
||||||
import {Terminal} from "./Terminal";
|
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||||
|
import { Terminal } from "./Terminal";
|
||||||
|
|
||||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||||
@ -212,7 +213,8 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
|
|||||||
var elem = clearEventListeners(elemId);
|
var elem = clearEventListeners(elemId);
|
||||||
if (elem == null) {return;}
|
if (elem == null) {return;}
|
||||||
if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 ||
|
if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 ||
|
||||||
i === 6 || i === 7 || i === 8 || i === 11 || i === 12) {
|
i === 6 || i === 7 || i === 8 || i === 10 || i === 11 ||
|
||||||
|
i === 12) {
|
||||||
elem.addEventListener("click", function() {
|
elem.addEventListener("click", function() {
|
||||||
var bitNodeKey = "BitNode" + i;
|
var bitNodeKey = "BitNode" + i;
|
||||||
var bitNode = BitNodes[bitNodeKey];
|
var bitNode = BitNodes[bitNodeKey];
|
||||||
|
@ -14,9 +14,9 @@ import {loadMessages, initMessages, Messages} from "./Message";
|
|||||||
import {Player, loadPlayer} from "./Player";
|
import {Player, loadPlayer} from "./Player";
|
||||||
import {loadAllRunningScripts} from "./Script";
|
import {loadAllRunningScripts} from "./Script";
|
||||||
import {AllServers, loadAllServers} from "./Server";
|
import {AllServers, loadAllServers} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import {Settings} from "./Settings/Settings";
|
||||||
import {loadSpecialServerIps, SpecialServerIps} from "./SpecialServerIps";
|
import {loadSpecialServerIps, SpecialServerIps} from "./SpecialServerIps";
|
||||||
import {loadStockMarket, StockMarket} from "./StockMarket";
|
import {loadStockMarket, StockMarket} from "./StockMarket/StockMarket";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||||
import {gameOptionsBoxClose} from "../utils/GameOptions";
|
import {gameOptionsBoxClose} from "../utils/GameOptions";
|
||||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
||||||
@ -151,6 +151,16 @@ function evaluateVersionCompatibility(ver) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This version allowed players to hold multiple jobs
|
||||||
|
if (ver < "0.43.0") {
|
||||||
|
if (Player.companyName !== "" && Player.companyPosition != null && Player.companyPosition !== "") {
|
||||||
|
console.log("Copied player's companyName and companyPosition properties to the Player.jobs map for v0.43.0");
|
||||||
|
Player.jobs[Player.companyName] = Player.companyPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete Player.companyPosition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadGame(saveString) {
|
function loadGame(saveString) {
|
||||||
|
299
src/Script.js
299
src/Script.js
@ -1,19 +1,3 @@
|
|||||||
var ace = require('brace');
|
|
||||||
var beautify = require('js-beautify').js_beautify;
|
|
||||||
require('brace/mode/javascript');
|
|
||||||
require('../netscript');
|
|
||||||
require('brace/theme/chaos');
|
|
||||||
require('brace/theme/chrome');
|
|
||||||
require('brace/theme/monokai');
|
|
||||||
require('brace/theme/solarized_dark');
|
|
||||||
require('brace/theme/solarized_light');
|
|
||||||
require('brace/theme/terminal');
|
|
||||||
require('brace/theme/twilight');
|
|
||||||
require('brace/theme/xcode');
|
|
||||||
require("brace/keybinding/vim");
|
|
||||||
require("brace/keybinding/emacs");
|
|
||||||
require("brace/ext/language_tools");
|
|
||||||
|
|
||||||
// Importing this doesn't work for some reason.
|
// Importing this doesn't work for some reason.
|
||||||
const walk = require("acorn/dist/walk");
|
const walk = require("acorn/dist/walk");
|
||||||
|
|
||||||
@ -26,8 +10,11 @@ import {evaluateImport} from "./NetscriptEvaluator";
|
|||||||
import {NetscriptFunctions} from "./NetscriptFunctions";
|
import {NetscriptFunctions} from "./NetscriptFunctions";
|
||||||
import {addWorkerScript, WorkerScript} from "./NetscriptWorker";
|
import {addWorkerScript, WorkerScript} from "./NetscriptWorker";
|
||||||
import {Player} from "./Player";
|
import {Player} from "./Player";
|
||||||
|
import { AceEditor } from "./ScriptEditor/Ace";
|
||||||
|
import { CodeMirrorEditor } from "./ScriptEditor/CodeMirror";
|
||||||
import {AllServers, processSingleServerGrowth} from "./Server";
|
import {AllServers, processSingleServerGrowth} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import { Settings } from "./Settings/Settings";
|
||||||
|
import { EditorSetting } from "./Settings/SettingEnums";
|
||||||
import {post} from "./ui/postToTerminal";
|
import {post} from "./ui/postToTerminal";
|
||||||
import {TextFile} from "./TextFile";
|
import {TextFile} from "./TextFile";
|
||||||
import {parse, Node} from "../utils/acorn";
|
import {parse, Node} from "../utils/acorn";
|
||||||
@ -41,47 +28,40 @@ import {createElement} from "../utils/uiHelpers/createE
|
|||||||
import {getTimestamp} from "../utils/helpers/getTimestamp";
|
import {getTimestamp} from "../utils/helpers/getTimestamp";
|
||||||
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
||||||
|
|
||||||
var keybindings = {
|
|
||||||
ace: null,
|
|
||||||
vim: "ace/keyboard/vim",
|
|
||||||
emacs: "ace/keyboard/emacs",
|
|
||||||
};
|
|
||||||
|
|
||||||
function isScriptFilename(f) {
|
function isScriptFilename(f) {
|
||||||
return f.endsWith(".js") || f.endsWith(".script") || f.endsWith(".ns");
|
return f.endsWith(".js") || f.endsWith(".script") || f.endsWith(".ns");
|
||||||
}
|
}
|
||||||
|
|
||||||
var scriptEditorRamCheck = null, scriptEditorRamText = null;
|
var scriptEditorRamCheck = null, scriptEditorRamText = null;
|
||||||
function scriptEditorInit() {
|
function scriptEditorInit() {
|
||||||
//Create buttons at the bottom of script editor
|
// Wrapper container that holds all the buttons below the script editor
|
||||||
var wrapper = document.getElementById("script-editor-buttons-wrapper");
|
const wrapper = document.getElementById("script-editor-buttons-wrapper");
|
||||||
if (wrapper == null) {
|
if (wrapper == null) {
|
||||||
console.log("Error finding 'script-editor-buttons-wrapper'");
|
console.error("Could not find 'script-editor-buttons-wrapper'");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
var beautifyButton = createElement("a", {
|
|
||||||
class:"a-link-button", display:"inline-block",
|
// Beautify button
|
||||||
innerText:"Beautify",
|
const beautifyButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
display: "inline-block",
|
||||||
|
innerText: "Beautify",
|
||||||
clickListener:()=>{
|
clickListener:()=>{
|
||||||
beautifyScript();
|
let editor = getCurrentEditor();
|
||||||
return false;
|
if (editor != null) {
|
||||||
}
|
editor.beautifyScript();
|
||||||
});
|
}
|
||||||
|
|
||||||
var closeButton = createElement("a", {
|
|
||||||
class:"a-link-button", display:"inline-block",
|
|
||||||
innerText:"Save & Close (Ctrl/Cmd + b)",
|
|
||||||
clickListener:()=>{
|
|
||||||
saveAndCloseScriptEditor();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Text that displays RAM calculation
|
||||||
scriptEditorRamText = createElement("p", {
|
scriptEditorRamText = createElement("p", {
|
||||||
display:"inline-block", margin:"10px", id:"script-editor-status-text"
|
display:"inline-block", margin:"10px", id:"script-editor-status-text"
|
||||||
});
|
});
|
||||||
|
|
||||||
var checkboxLabel = createElement("label", {
|
// Label for checkbox (defined below)
|
||||||
|
const checkboxLabel = createElement("label", {
|
||||||
for:"script-editor-ram-check", margin:"4px", marginTop: "8px",
|
for:"script-editor-ram-check", margin:"4px", marginTop: "8px",
|
||||||
innerText:"Dynamic RAM Usage Checker", color:"white",
|
innerText:"Dynamic RAM Usage Checker", color:"white",
|
||||||
tooltip:"Enable/Disable the dynamic RAM Usage display. You may " +
|
tooltip:"Enable/Disable the dynamic RAM Usage display. You may " +
|
||||||
@ -89,18 +69,34 @@ function scriptEditorInit() {
|
|||||||
"performance issues"
|
"performance issues"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Checkbox for enabling/disabling dynamic RAM calculation
|
||||||
scriptEditorRamCheck = createElement("input", {
|
scriptEditorRamCheck = createElement("input", {
|
||||||
type:"checkbox", name:"script-editor-ram-check", id:"script-editor-ram-check",
|
type:"checkbox", name:"script-editor-ram-check", id:"script-editor-ram-check",
|
||||||
margin:"4px", marginTop: "8px",
|
margin:"4px", marginTop: "8px",
|
||||||
});
|
});
|
||||||
scriptEditorRamCheck.checked = true;
|
scriptEditorRamCheck.checked = true;
|
||||||
|
|
||||||
var documentationButton = createElement("a", {
|
// Link to Netscript documentation
|
||||||
display:"inline-block", class:"a-link-button", innerText:"Netscript Documentation",
|
const documentationButton = createElement("a", {
|
||||||
|
class: "std-button",
|
||||||
|
display: "inline-block",
|
||||||
href:"https://bitburner.readthedocs.io/en/latest/index.html",
|
href:"https://bitburner.readthedocs.io/en/latest/index.html",
|
||||||
target:"_blank"
|
innerText:"Netscript Documentation",
|
||||||
|
target:"_blank",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save and Close button
|
||||||
|
const closeButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
display: "inline-block",
|
||||||
|
innerText: "Save & Close (Ctrl/Cmd + b)",
|
||||||
|
clickListener:()=>{
|
||||||
|
saveAndCloseScriptEditor();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add all buttons to the UI
|
||||||
wrapper.appendChild(beautifyButton);
|
wrapper.appendChild(beautifyButton);
|
||||||
wrapper.appendChild(closeButton);
|
wrapper.appendChild(closeButton);
|
||||||
wrapper.appendChild(scriptEditorRamText);
|
wrapper.appendChild(scriptEditorRamText);
|
||||||
@ -108,146 +104,86 @@ function scriptEditorInit() {
|
|||||||
wrapper.appendChild(checkboxLabel);
|
wrapper.appendChild(checkboxLabel);
|
||||||
wrapper.appendChild(documentationButton);
|
wrapper.appendChild(documentationButton);
|
||||||
|
|
||||||
//Initialize ACE Script editor
|
// Initialize editors
|
||||||
var editor = ace.edit('javascript-editor');
|
const initParams = {
|
||||||
editor.getSession().setMode('ace/mode/netscript');
|
saveAndCloseFn: saveAndCloseScriptEditor,
|
||||||
editor.setTheme('ace/theme/monokai');
|
quitFn: Engine.loadTerminalContent,
|
||||||
document.getElementById('javascript-editor').style.fontSize='16px';
|
}
|
||||||
editor.setOption("showPrintMargin", false);
|
|
||||||
|
|
||||||
/* Script editor options */
|
AceEditor.init(initParams);
|
||||||
//Theme
|
CodeMirrorEditor.init(initParams);
|
||||||
var themeDropdown = document.getElementById("script-editor-option-theme");
|
|
||||||
if (Settings.EditorTheme) {
|
// Setup the selector for which Editor to use
|
||||||
var initialIndex = 2;
|
const editorSelector = document.getElementById("script-editor-option-editor");
|
||||||
for (var i = 0; i < themeDropdown.options.length; ++i) {
|
if (editorSelector == null) {
|
||||||
if (themeDropdown.options[i].value === Settings.EditorTheme) {
|
console.error(`Could not find DOM Element for editor selector (id=script-editor-option-editor)`);
|
||||||
initialIndex = i;
|
return false;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
for (let i = 0; i < editorSelector.options.length; ++i) {
|
||||||
|
if (editorSelector.options[i].value === Settings.Editor) {
|
||||||
|
editorSelector.selectedIndex = i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
themeDropdown.selectedIndex = initialIndex;
|
|
||||||
} else {
|
|
||||||
themeDropdown.selectedIndex = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
themeDropdown.onchange = function() {
|
editorSelector.onchange = () => {
|
||||||
var val = themeDropdown.value;
|
const opt = editorSelector.value;
|
||||||
Settings.EditorTheme = val;
|
switch (opt) {
|
||||||
var themePath = "ace/theme/" + val.toLowerCase();
|
case EditorSetting.Ace:
|
||||||
editor.setTheme(themePath);
|
const codeMirrorCode = CodeMirrorEditor.getCode();
|
||||||
};
|
const codeMirrorFn = CodeMirrorEditor.getFilename();
|
||||||
themeDropdown.onchange();
|
AceEditor.create();
|
||||||
|
CodeMirrorEditor.setInvisible();
|
||||||
//Keybinding
|
AceEditor.openScript(codeMirrorFn, codeMirrorCode);
|
||||||
var keybindingDropdown = document.getElementById("script-editor-option-keybinding");
|
|
||||||
if (Settings.EditorKeybinding) {
|
|
||||||
var initialIndex = 0;
|
|
||||||
for (var i = 0; i < keybindingDropdown.options.length; ++i) {
|
|
||||||
if (keybindingDropdown.options[i].value === Settings.EditorKeybinding) {
|
|
||||||
initialIndex = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
case EditorSetting.CodeMirror:
|
||||||
|
const aceCode = AceEditor.getCode();
|
||||||
|
const aceFn = AceEditor.getFilename();
|
||||||
|
CodeMirrorEditor.create();
|
||||||
|
AceEditor.setInvisible();
|
||||||
|
CodeMirrorEditor.openScript(aceFn, aceCode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error(`Unrecognized Editor Setting: ${opt}`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
keybindingDropdown.selectedIndex = initialIndex;
|
|
||||||
} else {
|
|
||||||
keybindingDropdown.selectedIndex = 0;
|
|
||||||
}
|
|
||||||
keybindingDropdown.onchange = function() {
|
|
||||||
var val = keybindingDropdown.value;
|
|
||||||
Settings.EditorKeybinding = val;
|
|
||||||
editor.setKeyboardHandler(keybindings[val.toLowerCase()]);
|
|
||||||
};
|
|
||||||
keybindingDropdown.onchange();
|
|
||||||
|
|
||||||
//Highlight Active line
|
Settings.Editor = opt;
|
||||||
var highlightActiveChkBox = document.getElementById("script-editor-option-highlightactiveline");
|
|
||||||
highlightActiveChkBox.onchange = function() {
|
|
||||||
editor.setHighlightActiveLine(highlightActiveChkBox.checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Show Invisibles
|
|
||||||
var showInvisiblesChkBox = document.getElementById("script-editor-option-showinvisibles");
|
|
||||||
showInvisiblesChkBox.onchange = function() {
|
|
||||||
editor.setShowInvisibles(showInvisiblesChkBox.checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Use Soft Tab
|
|
||||||
var softTabChkBox = document.getElementById("script-editor-option-usesofttab");
|
|
||||||
softTabChkBox.onchange = function() {
|
|
||||||
editor.getSession().setUseSoftTabs(softTabChkBox.checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Jshint Maxerr
|
|
||||||
var maxerr = document.getElementById("script-editor-option-maxerr");
|
|
||||||
var maxerrLabel = document.getElementById("script-editor-option-maxerror-value-label");
|
|
||||||
maxerrLabel.innerHTML = maxerr.value;
|
|
||||||
maxerr.onchange = function() {
|
|
||||||
editor.getSession().$worker.send("changeOptions", [{maxerr:maxerr.value}]);
|
|
||||||
maxerrLabel.innerHTML = maxerr.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Configure some of the VIM keybindings
|
editorSelector.onchange(); // Trigger the onchange event handler
|
||||||
ace.config.loadModule('ace/keyboard/vim', function(module) {
|
}
|
||||||
var VimApi = module.CodeMirror.Vim;
|
|
||||||
VimApi.defineEx('write', 'w', function(cm, input) {
|
|
||||||
saveAndCloseScriptEditor();
|
|
||||||
});
|
|
||||||
VimApi.defineEx('quit', 'q', function(cm, input) {
|
|
||||||
Engine.loadTerminalContent();
|
|
||||||
});
|
|
||||||
VimApi.defineEx('xwritequit', 'x', function(cm, input) {
|
|
||||||
saveAndCloseScriptEditor();
|
|
||||||
});
|
|
||||||
VimApi.defineEx('wqwritequit', 'wq', function(cm, input) {
|
|
||||||
saveAndCloseScriptEditor();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
//Function autocompleter
|
export function getCurrentEditor() {
|
||||||
editor.setOption("enableBasicAutocompletion", true);
|
switch (Settings.Editor) {
|
||||||
var autocompleter = {
|
case EditorSetting.Ace:
|
||||||
getCompletions: function(editor, session, pos, prefix, callback) {
|
return AceEditor;
|
||||||
if (prefix.length === 0) {callback(null, []); return;}
|
case EditorSetting.CodeMirror:
|
||||||
var words = [];
|
return CodeMirrorEditor;
|
||||||
var fns = NetscriptFunctions(null);
|
default:
|
||||||
for (let name in fns) {
|
console.log(`Invalid Editor Setting: ${Settings.Editor}`);
|
||||||
if (fns.hasOwnProperty(name)) {
|
throw new Error(`Invalid Editor Setting: ${Settings.Editor}`);
|
||||||
words.push({
|
return null;
|
||||||
name: name,
|
|
||||||
value: name,
|
|
||||||
});
|
|
||||||
|
|
||||||
//Get functions from namespaces
|
|
||||||
const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang"];
|
|
||||||
if (namespaces.includes(name)) {
|
|
||||||
let namespace = fns[name];
|
|
||||||
if (typeof namespace !== "object") {continue;}
|
|
||||||
let namespaceFns = Object.keys(namespace);
|
|
||||||
for (let i = 0; i < namespaceFns.length; ++i) {
|
|
||||||
words.push({
|
|
||||||
name: namespaceFns[i],
|
|
||||||
value: namespaceFns[i],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback(null, words);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
editor.completers = [autocompleter];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Updates RAM usage in script
|
//Updates RAM usage in script
|
||||||
async function updateScriptEditorContent() {
|
export async function updateScriptEditorContent() {
|
||||||
var filename = document.getElementById("script-editor-filename").value;
|
var filename = document.getElementById("script-editor-filename").value;
|
||||||
if (scriptEditorRamCheck == null || !scriptEditorRamCheck.checked || !isScriptFilename(filename)) {
|
if (scriptEditorRamCheck == null || !scriptEditorRamCheck.checked || !isScriptFilename(filename)) {
|
||||||
scriptEditorRamText.innerText = "N/A";
|
scriptEditorRamText.innerText = "N/A";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var editor = ace.edit('javascript-editor');
|
|
||||||
var code = editor.getValue();
|
let code;
|
||||||
|
try {
|
||||||
|
code = getCurrentEditor().getCode();
|
||||||
|
} catch(e) {
|
||||||
|
scriptEditorRamText.innerText = "RAM: ERROR";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var codeCopy = code.repeat(1);
|
var codeCopy = code.repeat(1);
|
||||||
var ramUsage = await calculateRamUsage(codeCopy);
|
var ramUsage = await calculateRamUsage(codeCopy);
|
||||||
if (ramUsage !== -1) {
|
if (ramUsage !== -1) {
|
||||||
@ -269,20 +205,17 @@ $(document).keydown(function(e) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function beautifyScript() {
|
|
||||||
var editor = ace.edit('javascript-editor');
|
|
||||||
var code = editor.getValue();
|
|
||||||
code = beautify(code, {
|
|
||||||
indent_size: 4,
|
|
||||||
brace_style: "preserve-inline",
|
|
||||||
});
|
|
||||||
editor.setValue(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveAndCloseScriptEditor() {
|
function saveAndCloseScriptEditor() {
|
||||||
var filename = document.getElementById("script-editor-filename").value;
|
var filename = document.getElementById("script-editor-filename").value;
|
||||||
var editor = ace.edit('javascript-editor');
|
|
||||||
var code = editor.getValue();
|
let code;
|
||||||
|
try {
|
||||||
|
code = getCurrentEditor().getCode();
|
||||||
|
} catch(e) {
|
||||||
|
dialogBoxCreate("Something went wrong when trying to save (getCurrentEditor().getCode()). Please report to game developer with details");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) {
|
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) {
|
||||||
//Make sure filename + code properly follow tutorial
|
//Make sure filename + code properly follow tutorial
|
||||||
if (filename !== "foodnstuff.script") {
|
if (filename !== "foodnstuff.script") {
|
||||||
@ -387,8 +320,7 @@ function Script(fn = "", code = "", server = "") {
|
|||||||
Script.prototype.saveScript = function() {
|
Script.prototype.saveScript = function() {
|
||||||
if (routing.isOn(Page.ScriptEditor)) {
|
if (routing.isOn(Page.ScriptEditor)) {
|
||||||
//Update code and filename
|
//Update code and filename
|
||||||
var editor = ace.edit('javascript-editor');
|
const code = getCurrentEditor().getCode();
|
||||||
var code = editor.getValue();
|
|
||||||
this.code = code.replace(/^\s+|\s+$/g, '');
|
this.code = code.replace(/^\s+|\s+$/g, '');
|
||||||
|
|
||||||
var filename = document.getElementById("script-editor-filename").value;
|
var filename = document.getElementById("script-editor-filename").value;
|
||||||
@ -483,8 +415,11 @@ async function parseOnlyRamCalculate(server, code, workerScript) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const script = server.getScript(nextModule);
|
const script = server.getScript(nextModule.startsWith("./") ? nextModule.slice(2) : nextModule);
|
||||||
if (!script) return -1; // No such script on the server.
|
if (!script) {
|
||||||
|
console.warn("Invalid script");
|
||||||
|
return -1; // No such script on the server.
|
||||||
|
}
|
||||||
code = script.code;
|
code = script.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,5 +1031,5 @@ AllServersMap.fromJSON = function(value) {
|
|||||||
|
|
||||||
Reviver.constructors.AllServersMap = AllServersMap;
|
Reviver.constructors.AllServersMap = AllServersMap;
|
||||||
|
|
||||||
export {updateScriptEditorContent, loadAllRunningScripts, findRunningScript,
|
export {loadAllRunningScripts, findRunningScript,
|
||||||
RunningScript, Script, AllServersMap, scriptEditorInit, isScriptFilename};
|
RunningScript, Script, AllServersMap, scriptEditorInit, isScriptFilename};
|
||||||
|
319
src/ScriptEditor/Ace.js
Normal file
319
src/ScriptEditor/Ace.js
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
import { ScriptEditor } from "./ScriptEditor";
|
||||||
|
|
||||||
|
const ace = require('brace');
|
||||||
|
|
||||||
|
require('brace/mode/javascript');
|
||||||
|
require('./AceNetscriptMode');
|
||||||
|
require('brace/theme/chaos');
|
||||||
|
require('brace/theme/chrome');
|
||||||
|
require('brace/theme/monokai');
|
||||||
|
require('brace/theme/solarized_dark');
|
||||||
|
require('brace/theme/solarized_light');
|
||||||
|
require('brace/theme/terminal');
|
||||||
|
require('brace/theme/twilight');
|
||||||
|
require('brace/theme/xcode');
|
||||||
|
require("brace/keybinding/vim");
|
||||||
|
require("brace/keybinding/emacs");
|
||||||
|
require("brace/ext/language_tools");
|
||||||
|
|
||||||
|
import { NetscriptFunctions } from "../NetscriptFunctions";
|
||||||
|
import { Settings } from "../Settings/Settings";
|
||||||
|
import { AceKeybindingSetting } from "../Settings/SettingEnums";
|
||||||
|
|
||||||
|
import { clearEventListeners } from "../../utils/uiHelpers/clearEventListeners";
|
||||||
|
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||||
|
import { createOptionElement } from "../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../utils/uiHelpers/getSelectData";
|
||||||
|
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
|
|
||||||
|
// Wrapper for Ace editor
|
||||||
|
const Keybindings = {
|
||||||
|
ace: null,
|
||||||
|
vim: "ace/keyboard/vim",
|
||||||
|
emacs: "ace/keyboard/emacs",
|
||||||
|
};
|
||||||
|
|
||||||
|
function validateInitializationParamters(params) {
|
||||||
|
if (params.saveAndCloseFn == null) { return false; } // Save & close button function
|
||||||
|
if (params.quitFn == null) { return false; } // Quitting editor, aka Engine.loadTerminalContent
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AceEditorWrapper extends ScriptEditor {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.vimCommandDisplayWrapper = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
init(params) {
|
||||||
|
if (this.editor != null) {
|
||||||
|
console.error(`AceEditor.init() called when it's already initialized`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate/Sanitize input
|
||||||
|
if (!validateInitializationParamters(params)) {
|
||||||
|
console.error(`'params' argument passed into initAceEditor() does not have proper properties`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the filename input
|
||||||
|
this.filenameInput = document.getElementById("script-editor-filename");
|
||||||
|
if (this.filenameInput == null) {
|
||||||
|
console.error(`Could not get Script Editor filename element (id=script-editor-filename)`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize ACE Script editor
|
||||||
|
this.editor = ace.edit('ace-editor');
|
||||||
|
this.editor.getSession().setMode('ace/mode/netscript');
|
||||||
|
this.editor.setTheme('ace/theme/monokai');
|
||||||
|
const editorElement = document.getElementById('ace-editor');
|
||||||
|
if (editorElement == null) { return false; }
|
||||||
|
editorElement.style.fontSize = '16px';
|
||||||
|
this.editor.setOption("showPrintMargin", false);
|
||||||
|
|
||||||
|
// Configure some of the VIM keybindings
|
||||||
|
ace.config.loadModule('ace/keyboard/vim', function(module) {
|
||||||
|
var VimApi = module.CodeMirror.Vim;
|
||||||
|
VimApi.defineEx('write', 'w', function(cm, input) {
|
||||||
|
params.saveAndCloseFn();
|
||||||
|
});
|
||||||
|
VimApi.defineEx('quit', 'q', function(cm, input) {
|
||||||
|
params.quitFn();
|
||||||
|
});
|
||||||
|
VimApi.defineEx('xwritequit', 'x', function(cm, input) {
|
||||||
|
params.saveAndCloseFn();
|
||||||
|
});
|
||||||
|
VimApi.defineEx('wqwritequit', 'wq', function(cm, input) {
|
||||||
|
params.saveAndCloseFn();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store a reference to the VIM command display
|
||||||
|
this.vimCommandDisplayWrapper = document.getElementById("codemirror-vim-command-display-wrapper");
|
||||||
|
if (this.vimCommandDisplayWrapper == null) {
|
||||||
|
console.error(`Could not get Vim Command Display element (id=codemirror-vim-command-display-wrapper)`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Function autocompleter
|
||||||
|
this.editor.setOption("enableBasicAutocompletion", true);
|
||||||
|
var autocompleter = {
|
||||||
|
getCompletions: function(editor, session, pos, prefix, callback) {
|
||||||
|
if (prefix.length === 0) {callback(null, []); return;}
|
||||||
|
var words = [];
|
||||||
|
var fns = NetscriptFunctions(null);
|
||||||
|
for (let name in fns) {
|
||||||
|
if (fns.hasOwnProperty(name)) {
|
||||||
|
words.push({
|
||||||
|
name: name,
|
||||||
|
value: name,
|
||||||
|
});
|
||||||
|
|
||||||
|
//Get functions from namespaces
|
||||||
|
const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang"];
|
||||||
|
if (namespaces.includes(name)) {
|
||||||
|
let namespace = fns[name];
|
||||||
|
if (typeof namespace !== "object") {continue;}
|
||||||
|
let namespaceFns = Object.keys(namespace);
|
||||||
|
for (let i = 0; i < namespaceFns.length; ++i) {
|
||||||
|
words.push({
|
||||||
|
name: namespaceFns[i],
|
||||||
|
value: namespaceFns[i],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback(null, words);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
this.editor.completers = [autocompleter];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized() {
|
||||||
|
return (this.editor != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the configurable Options for this Editor
|
||||||
|
create() {
|
||||||
|
function safeGetElementById(id, whatFor="") {
|
||||||
|
const elem = document.getElementById(id);
|
||||||
|
if (elem == null) {
|
||||||
|
throw new Error(`Could not find ${whatFor} DOM element(id=${id})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeClearEventListeners(id, whatFor="") {
|
||||||
|
const elem = clearEventListeners(id);
|
||||||
|
if (elem == null) {
|
||||||
|
throw new Error(`Could not find ${whatFor} DOM element(id=${id})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const optionsPanel = safeGetElementById("script-editor-options-panel", "Script Editor Options Panel");
|
||||||
|
|
||||||
|
// Set editor to visible
|
||||||
|
const elem = document.getElementById("ace-editor");
|
||||||
|
if (elem instanceof HTMLElement) {
|
||||||
|
elem.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the Vim command display from CodeMirror is invisible
|
||||||
|
if (this.vimCommandDisplayWrapper instanceof HTMLElement) {
|
||||||
|
this.vimCommandDisplayWrapper.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Theme
|
||||||
|
const themeDropdown = safeClearEventListeners("script-editor-option-theme", "Theme Selector");
|
||||||
|
removeChildrenFromElement(themeDropdown);
|
||||||
|
themeDropdown.add(createOptionElement("Chaos"));
|
||||||
|
themeDropdown.add(createOptionElement("Chrome"));
|
||||||
|
themeDropdown.add(createOptionElement("Monokai"));
|
||||||
|
themeDropdown.add(createOptionElement("Solarized Dark", "Solarized_Dark"));
|
||||||
|
themeDropdown.add(createOptionElement("Solarized Light", "Solarized_Light"));
|
||||||
|
themeDropdown.add(createOptionElement("Terminal"));
|
||||||
|
themeDropdown.add(createOptionElement("Twilight"));
|
||||||
|
themeDropdown.add(createOptionElement("XCode"));
|
||||||
|
if (Settings.EditorTheme) {
|
||||||
|
var initialIndex = 2;
|
||||||
|
for (var i = 0; i < themeDropdown.options.length; ++i) {
|
||||||
|
if (themeDropdown.options[i].value === Settings.EditorTheme) {
|
||||||
|
initialIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
themeDropdown.selectedIndex = initialIndex;
|
||||||
|
} else {
|
||||||
|
themeDropdown.selectedIndex = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
themeDropdown.onchange = () => {
|
||||||
|
const val = themeDropdown.value;
|
||||||
|
Settings.EditorTheme = val;
|
||||||
|
const themePath = "ace/theme/" + val.toLowerCase();
|
||||||
|
this.editor.setTheme(themePath);
|
||||||
|
};
|
||||||
|
themeDropdown.onchange();
|
||||||
|
|
||||||
|
// Keybinding
|
||||||
|
const keybindingDropdown = safeClearEventListeners("script-editor-option-keybinding", "Keybinding Selector");
|
||||||
|
removeChildrenFromElement(keybindingDropdown);
|
||||||
|
keybindingDropdown.add(createOptionElement("Ace", AceKeybindingSetting.Ace));
|
||||||
|
keybindingDropdown.add(createOptionElement("Vim", AceKeybindingSetting.Vim));
|
||||||
|
keybindingDropdown.add(createOptionElement("Emacs", AceKeybindingSetting.Emacs));
|
||||||
|
if (Settings.EditorKeybinding) {
|
||||||
|
// Sanitize the Keybinding setting
|
||||||
|
if (!(Object.values(AceKeybindingSetting).includes(Settings.EditorKeybinding))) {
|
||||||
|
Settings.EditorKeybinding = AceKeybindingSetting.Ace;
|
||||||
|
}
|
||||||
|
var initialIndex = 0;
|
||||||
|
for (var i = 0; i < keybindingDropdown.options.length; ++i) {
|
||||||
|
if (keybindingDropdown.options[i].value === Settings.EditorKeybinding) {
|
||||||
|
initialIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keybindingDropdown.selectedIndex = initialIndex;
|
||||||
|
} else {
|
||||||
|
keybindingDropdown.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
keybindingDropdown.onchange = () => {
|
||||||
|
var val = keybindingDropdown.value;
|
||||||
|
Settings.EditorKeybinding = val;
|
||||||
|
this.editor.setKeyboardHandler(Keybindings[val.toLowerCase()]);
|
||||||
|
};
|
||||||
|
keybindingDropdown.onchange();
|
||||||
|
|
||||||
|
// Highlight Active line
|
||||||
|
const highlightActiveChkBox = safeClearEventListeners("script-editor-option-highlightactiveline", "Active Line Checkbox");
|
||||||
|
highlightActiveChkBox.onchange = () => {
|
||||||
|
this.editor.setHighlightActiveLine(highlightActiveChkBox.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show Invisibles
|
||||||
|
const showInvisiblesChkBox = safeClearEventListeners("script-editor-option-showinvisibles", "Show Invisible Checkbox");
|
||||||
|
showInvisiblesChkBox.onchange = () => {
|
||||||
|
this.editor.setShowInvisibles(showInvisiblesChkBox.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use Soft Tab
|
||||||
|
const softTabChkBox = safeClearEventListeners("script-editor-option-usesofttab", "Soft Tab Checkbox");
|
||||||
|
softTabChkBox.onchange = () => {
|
||||||
|
this.editor.getSession().setUseSoftTabs(softTabChkBox.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Some helper functions for dealing with flexible options
|
||||||
|
function resetFlexibleOption(id) {
|
||||||
|
const fieldset = safeGetElementById(id);
|
||||||
|
removeChildrenFromElement(fieldset);
|
||||||
|
fieldset.style.display = "block";
|
||||||
|
return fieldset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFlexibleOption(id) {
|
||||||
|
// This doesn't really remove it, just sets it to invisible
|
||||||
|
const fieldset = resetFlexibleOption(id);
|
||||||
|
fieldset.style.display = "none";
|
||||||
|
return fieldset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jshint Maxerr (Flex 1)
|
||||||
|
const flex1Fieldset = resetFlexibleOption("script-editor-option-flex1-fieldset");
|
||||||
|
const flex1Id = "script-editor-option-maxerr";
|
||||||
|
const flex1ValueLabel = createElement("em", { innerText: "200" });
|
||||||
|
flex1Fieldset.appendChild(createElement("label", {
|
||||||
|
for: flex1Id,
|
||||||
|
innerText: "Max Error Count",
|
||||||
|
}));
|
||||||
|
const flex1Input = createElement("input", {
|
||||||
|
id: flex1Id,
|
||||||
|
max: "1000",
|
||||||
|
min: "50",
|
||||||
|
name: flex1Id,
|
||||||
|
step: "1",
|
||||||
|
type: "range",
|
||||||
|
value: "200",
|
||||||
|
changeListener: () => {
|
||||||
|
this.editor.getSession().$worker.send("changeOptions", [{maxerr:flex1Input.value}]);
|
||||||
|
flex1ValueLabel.innerText = flex1Input.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
flex1Fieldset.appendChild(flex1Input);
|
||||||
|
flex1Fieldset.appendChild(flex1ValueLabel);
|
||||||
|
|
||||||
|
// Nothing for Flex Options 2-4
|
||||||
|
removeFlexibleOption("script-editor-option-flex2-fieldset");
|
||||||
|
removeFlexibleOption("script-editor-option-flex3-fieldset");
|
||||||
|
removeFlexibleOption("script-editor-option-flex4-fieldset");
|
||||||
|
} catch(e) {
|
||||||
|
console.error(`Exception caught: ${e}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isFocused() {
|
||||||
|
if (this.editor == null) { return false; }
|
||||||
|
return this.editor.isFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the editor to be invisible. Does not require this class to be initialized
|
||||||
|
setInvisible() {
|
||||||
|
const elem = document.getElementById("ace-editor");
|
||||||
|
if (elem instanceof HTMLElement) {
|
||||||
|
elem.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AceEditor = new AceEditorWrapper();
|
@ -94,8 +94,8 @@ let NetscriptFunctions =
|
|||||||
"installAugmentations|" +
|
"installAugmentations|" +
|
||||||
|
|
||||||
// TIX API
|
// TIX API
|
||||||
"getStockPrice|getStockPosition|getStockSymbols|buyStock|sellStock|" +
|
"getStockPrice|getStockPosition|getStockSymbols|getStockMaxShares|" +
|
||||||
"shortStock|sellShort|" +
|
"buyStock|sellStock|shortStock|sellShort|" +
|
||||||
"placeOrder|cancelOrder|getOrders|getStockVolatility|getStockForecast|" +
|
"placeOrder|cancelOrder|getOrders|getStockVolatility|getStockForecast|" +
|
||||||
"purchase4SMarketData|purchase4SMarketDataTixApi|" +
|
"purchase4SMarketData|purchase4SMarketDataTixApi|" +
|
||||||
|
|
577
src/ScriptEditor/CodeMirror.js
Normal file
577
src/ScriptEditor/CodeMirror.js
Normal file
@ -0,0 +1,577 @@
|
|||||||
|
// Wrapper for CodeMirror editor
|
||||||
|
// https://github.com/codemirror/codemirror
|
||||||
|
import { ScriptEditor } from "./ScriptEditor";
|
||||||
|
|
||||||
|
import 'codemirror/lib/codemirror.css';
|
||||||
|
|
||||||
|
import 'codemirror/theme/monokai.css';
|
||||||
|
import 'codemirror/theme/3024-day.css';
|
||||||
|
import 'codemirror/theme/3024-night.css';
|
||||||
|
import 'codemirror/theme/abcdef.css';
|
||||||
|
import 'codemirror/theme/ambiance-mobile.css';
|
||||||
|
import 'codemirror/theme/ambiance.css';
|
||||||
|
import 'codemirror/theme/base16-dark.css';
|
||||||
|
import 'codemirror/theme/base16-light.css';
|
||||||
|
import 'codemirror/theme/bespin.css';
|
||||||
|
import 'codemirror/theme/blackboard.css';
|
||||||
|
import 'codemirror/theme/cobalt.css';
|
||||||
|
import 'codemirror/theme/colorforth.css';
|
||||||
|
import 'codemirror/theme/darcula.css';
|
||||||
|
import 'codemirror/theme/dracula.css';
|
||||||
|
import 'codemirror/theme/duotone-dark.css';
|
||||||
|
import 'codemirror/theme/duotone-light.css';
|
||||||
|
import 'codemirror/theme/eclipse.css';
|
||||||
|
import 'codemirror/theme/elegant.css';
|
||||||
|
import 'codemirror/theme/erlang-dark.css';
|
||||||
|
import 'codemirror/theme/gruvbox-dark.css';
|
||||||
|
import 'codemirror/theme/hopscotch.css';
|
||||||
|
import 'codemirror/theme/icecoder.css';
|
||||||
|
import 'codemirror/theme/idea.css';
|
||||||
|
import 'codemirror/theme/isotope.css';
|
||||||
|
import 'codemirror/theme/lesser-dark.css';
|
||||||
|
import 'codemirror/theme/liquibyte.css';
|
||||||
|
import 'codemirror/theme/lucario.css';
|
||||||
|
import 'codemirror/theme/material.css';
|
||||||
|
import 'codemirror/theme/mbo.css';
|
||||||
|
import 'codemirror/theme/mdn-like.css';
|
||||||
|
import 'codemirror/theme/midnight.css';
|
||||||
|
import 'codemirror/theme/neat.css';
|
||||||
|
import 'codemirror/theme/neo.css';
|
||||||
|
import 'codemirror/theme/night.css';
|
||||||
|
import 'codemirror/theme/oceanic-next.css';
|
||||||
|
import 'codemirror/theme/panda-syntax.css';
|
||||||
|
import 'codemirror/theme/paraiso-dark.css';
|
||||||
|
import 'codemirror/theme/paraiso-light.css';
|
||||||
|
import 'codemirror/theme/pastel-on-dark.css';
|
||||||
|
import 'codemirror/theme/railscasts.css';
|
||||||
|
import 'codemirror/theme/rubyblue.css';
|
||||||
|
import 'codemirror/theme/seti.css';
|
||||||
|
import 'codemirror/theme/shadowfox.css';
|
||||||
|
import 'codemirror/theme/solarized.css';
|
||||||
|
import 'codemirror/theme/ssms.css';
|
||||||
|
import 'codemirror/theme/the-matrix.css';
|
||||||
|
import 'codemirror/theme/tomorrow-night-bright.css';
|
||||||
|
import 'codemirror/theme/tomorrow-night-eighties.css';
|
||||||
|
import 'codemirror/theme/ttcn.css';
|
||||||
|
import 'codemirror/theme/twilight.css';
|
||||||
|
import 'codemirror/theme/vibrant-ink.css';
|
||||||
|
import 'codemirror/theme/xq-dark.css';
|
||||||
|
import 'codemirror/theme/xq-light.css';
|
||||||
|
import 'codemirror/theme/yeti.css';
|
||||||
|
import 'codemirror/theme/zenburn.css';
|
||||||
|
|
||||||
|
import "../../css/codemirror-overrides.scss";
|
||||||
|
|
||||||
|
import CodeMirror from "codemirror/lib/codemirror.js";
|
||||||
|
import "codemirror/mode/javascript/javascript.js";
|
||||||
|
import "./CodeMirrorNetscriptMode";
|
||||||
|
|
||||||
|
import 'codemirror/keymap/sublime.js';
|
||||||
|
import 'codemirror/keymap/vim.js';
|
||||||
|
import 'codemirror/keymap/emacs.js';
|
||||||
|
|
||||||
|
import 'codemirror/addon/comment/continuecomment.js';
|
||||||
|
import 'codemirror/addon/dialog/dialog.css';
|
||||||
|
import 'codemirror/addon/dialog/dialog.js';
|
||||||
|
import 'codemirror/addon/edit/closebrackets.js';
|
||||||
|
import 'codemirror/addon/edit/matchbrackets.js';
|
||||||
|
import 'codemirror/addon/fold/foldcode.js';
|
||||||
|
import 'codemirror/addon/fold/foldgutter.js';
|
||||||
|
import 'codemirror/addon/fold/foldgutter.css';
|
||||||
|
import 'codemirror/addon/fold/brace-fold.js';
|
||||||
|
import 'codemirror/addon/fold/indent-fold.js';
|
||||||
|
import 'codemirror/addon/fold/comment-fold.js';
|
||||||
|
import 'codemirror/addon/hint/javascript-hint.js';
|
||||||
|
import 'codemirror/addon/hint/show-hint.js';
|
||||||
|
import 'codemirror/addon/hint/show-hint.css';
|
||||||
|
import 'codemirror/addon/lint/lint.js';
|
||||||
|
import 'codemirror/addon/lint/lint.css';
|
||||||
|
import 'codemirror/addon/search/match-highlighter.js';
|
||||||
|
import 'codemirror/addon/selection/active-line.js';
|
||||||
|
|
||||||
|
window.JSHINT = require('jshint').JSHINT;
|
||||||
|
import './CodeMirrorNetscriptLint.js';
|
||||||
|
|
||||||
|
import { NetscriptFunctions } from "../NetscriptFunctions";
|
||||||
|
import { CodeMirrorKeybindingSetting,
|
||||||
|
CodeMirrorThemeSetting } from "../Settings/SettingEnums";
|
||||||
|
import { Settings } from "../Settings/Settings";
|
||||||
|
|
||||||
|
import { clearEventListeners } from "../../utils/uiHelpers/clearEventListeners";
|
||||||
|
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||||
|
import { createOptionElement } from "../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../utils/uiHelpers/getSelectData";
|
||||||
|
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
|
|
||||||
|
// Max number of invisibles to be shown in a group if the "Show Invisibles" option
|
||||||
|
// is marked
|
||||||
|
const MaxInvisibles = 20;
|
||||||
|
|
||||||
|
function validateInitializationParamters(params) {
|
||||||
|
if (params.saveAndCloseFn == null) { return false; } // Save & close button function
|
||||||
|
if (params.quitFn == null) { return false; } // Quitting editor, aka Engine.loadTerminalContent
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CodeMirrorEditorWrapper extends ScriptEditor {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.vimCommandDisplay = null;
|
||||||
|
this.vimCommandDisplayWrapper = null;
|
||||||
|
this.tabsStyleElement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
init(params) {
|
||||||
|
if (this.editor != null) {
|
||||||
|
console.error(`CodeMirrorEditor.init() called when it's already initialized`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate/Sanitize input
|
||||||
|
if (!validateInitializationParamters(params)) {
|
||||||
|
console.error(`'params' argument passed into CodeMirrorEditor.init() does not have proper properties`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the filename input
|
||||||
|
this.filenameInput = document.getElementById("script-editor-filename");
|
||||||
|
if (this.filenameInput == null) {
|
||||||
|
console.error(`Could not get Script Editor filename element (id=script-editor-filename)`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add styling for the "Show Invisibles" option for spaces
|
||||||
|
const classBase = '.CodeMirror .cm-whitespace-';
|
||||||
|
const spaceChar = '·';
|
||||||
|
const style = document.createElement('style');
|
||||||
|
|
||||||
|
style.setAttribute('data-name', 'js-show-invisibles');
|
||||||
|
|
||||||
|
let rules = '';
|
||||||
|
let spaceChars = '';
|
||||||
|
|
||||||
|
for (let i = 1; i <= MaxInvisibles; ++i) {
|
||||||
|
spaceChars += spaceChar;
|
||||||
|
|
||||||
|
const rule = classBase + i + '::before { content: "' + spaceChars + '";}\n';
|
||||||
|
rules += rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
style.textContent = rules;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
// Add an element for the "Show Invisible" option for tabs
|
||||||
|
this.tabsStyleElement = document.createElement('style');
|
||||||
|
document.head.appendChild(this.tabsStyleElement);
|
||||||
|
|
||||||
|
// Store a reference to the VIM command display
|
||||||
|
this.vimCommandDisplay = document.getElementById("codemirror-vim-command-display");
|
||||||
|
this.vimCommandDisplayWrapper = document.getElementById("codemirror-vim-command-display-wrapper");
|
||||||
|
|
||||||
|
// Define a "Save" command for CodeMirror so shortcuts like Ctrl + s
|
||||||
|
// will save in-game
|
||||||
|
CodeMirror.commands.save = function() { params.saveAndCloseFn(); }
|
||||||
|
|
||||||
|
// Add Netscript Functions to the autocompleter
|
||||||
|
const netscriptFns = [];
|
||||||
|
var fnsObj = NetscriptFunctions(null);
|
||||||
|
for (let name in fnsObj) {
|
||||||
|
if (fnsObj.hasOwnProperty(name)) {
|
||||||
|
netscriptFns.push(name);
|
||||||
|
|
||||||
|
//Get functions from namespaces
|
||||||
|
const namespaces = ["bladeburner", "hacknet", "codingcontract", "gang"];
|
||||||
|
if (namespaces.includes(name)) {
|
||||||
|
let namespace = fnsObj[name];
|
||||||
|
if (typeof namespace !== "object") {continue;}
|
||||||
|
let namespaceFns = Object.keys(namespace);
|
||||||
|
for (let i = 0; i < namespaceFns.length; ++i) {
|
||||||
|
netscriptFns.push(namespaceFns[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeMirror.hint.netscript = function(editor) {
|
||||||
|
const origList = CodeMirror.hint.javascript(editor) || {from: editor.getCursor(), to: editor.getCursor(), list: []};
|
||||||
|
origList.list.push(...netscriptFns);
|
||||||
|
let list = origList.list || [];
|
||||||
|
let cursor = editor.getCursor();
|
||||||
|
let currentLine = editor.getLine(cursor.line);
|
||||||
|
let start = cursor.ch;
|
||||||
|
let end = start;
|
||||||
|
while (end < currentLine.length && /[\w$]+/.test(currentLine.charAt(end))) ++end;
|
||||||
|
while (start && /[\w$]+/.test(currentLine.charAt(start - 1))) --start;
|
||||||
|
let curWord = start != end && currentLine.slice(start, end);
|
||||||
|
let regex = new RegExp('^' + curWord, 'i');
|
||||||
|
let result = {
|
||||||
|
list: (!curWord ? list : list.filter(function (item) {
|
||||||
|
return item.match(regex);
|
||||||
|
})).sort(),
|
||||||
|
from: CodeMirror.Pos(cursor.line, start),
|
||||||
|
to: CodeMirror.Pos(cursor.line, end)
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure VIM keybindings
|
||||||
|
var VimApi = CodeMirror.Vim;
|
||||||
|
VimApi.defineEx('write', 'w', function(cm, input) {
|
||||||
|
params.saveAndCloseFn();
|
||||||
|
});
|
||||||
|
VimApi.defineEx('quit', 'q', function(cm, input) {
|
||||||
|
params.quitFn();
|
||||||
|
});
|
||||||
|
VimApi.defineEx('xwritequit', 'x', function(cm, input) {
|
||||||
|
params.saveAndCloseFn();
|
||||||
|
});
|
||||||
|
VimApi.defineEx('wqwritequit', 'wq', function(cm, input) {
|
||||||
|
params.saveAndCloseFn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized() {
|
||||||
|
return (this.filenameInput != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
function safeGetElementById(id, whatFor="") {
|
||||||
|
const elem = document.getElementById(id);
|
||||||
|
if (elem == null) {
|
||||||
|
throw new Error(`Could not find ${whatFor} DOM element(id=${id})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeClearEventListeners(id, whatFor="") {
|
||||||
|
const elem = clearEventListeners(id);
|
||||||
|
if (elem == null) {
|
||||||
|
throw new Error(`Could not find ${whatFor} DOM element(id=${id})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!this.initialized()) {
|
||||||
|
console.warn(`CodeMirrorEditor.create() called when editor was not initialized`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and sanitize the keybinding (keymap) setting
|
||||||
|
if (!(Object.values(CodeMirrorKeybindingSetting).includes(Settings.EditorKeybinding))) {
|
||||||
|
Settings.EditorKeybinding = CodeMirrorKeybindingSetting.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize CodeMirror Editor
|
||||||
|
const textAreaElement = safeGetElementById("codemirror-editor", "CodeMirror Textarea");
|
||||||
|
const formElement = safeGetElementById("codemirror-form-wrapper", "CodeMirror Form Wrapper");
|
||||||
|
formElement.style.display = "block";
|
||||||
|
|
||||||
|
this.editor = CodeMirror.fromTextArea(textAreaElement, {
|
||||||
|
autofocus: true,
|
||||||
|
extraKeys: { "Ctrl-Space": "autocomplete" },
|
||||||
|
foldGutter: true,
|
||||||
|
gutters: ["CodeMirror-lint-markers", "CodeMirror-linenumbers", "CodeMirror-foldgutter"],
|
||||||
|
highlightSelectionMatches: true,
|
||||||
|
hintOptions: { hint: CodeMirror.hint.netscript },
|
||||||
|
indentUnit: 4,
|
||||||
|
keyMap: "default",
|
||||||
|
lineNumbers: true,
|
||||||
|
matchBrackets: true,
|
||||||
|
maxInvisibles: 32,
|
||||||
|
mode: "netscript",
|
||||||
|
theme: Settings.EditorTheme,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup Theme Option
|
||||||
|
const themeDropdown = safeClearEventListeners("script-editor-option-theme", "Theme Selector");
|
||||||
|
removeChildrenFromElement(themeDropdown);
|
||||||
|
const themeOptions = Object.keys(CodeMirrorThemeSetting);
|
||||||
|
for (let i = 0; i < themeOptions.length; ++i) {
|
||||||
|
const themeKey = themeOptions[i];
|
||||||
|
const themeValue = CodeMirrorThemeSetting[themeKey];
|
||||||
|
themeDropdown.add(createOptionElement(themeKey, themeValue));
|
||||||
|
}
|
||||||
|
if (Settings.EditorTheme) {
|
||||||
|
var initialIndex = 0;
|
||||||
|
for (var i = 0; i < themeDropdown.options.length; ++i) {
|
||||||
|
if (themeDropdown.options[i].value === Settings.EditorTheme) {
|
||||||
|
initialIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
themeDropdown.selectedIndex = initialIndex;
|
||||||
|
} else {
|
||||||
|
themeDropdown.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
themeDropdown.onchange = () => {
|
||||||
|
const val = themeDropdown.value;
|
||||||
|
Settings.EditorTheme = val;
|
||||||
|
this.editor.setOption("theme", val);
|
||||||
|
};
|
||||||
|
themeDropdown.onchange();
|
||||||
|
|
||||||
|
// Setup Keymap Option
|
||||||
|
const keybindingDropdown = safeClearEventListeners("script-editor-option-keybinding", "Keymap Selector");
|
||||||
|
if (keybindingDropdown == null) {
|
||||||
|
console.error(`Could not find Script Editor's keybinding selector element (id="script-editor-option-keybinding")`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
removeChildrenFromElement(keybindingDropdown);
|
||||||
|
keybindingDropdown.add(createOptionElement("Default", CodeMirrorKeybindingSetting.Default));
|
||||||
|
keybindingDropdown.add(createOptionElement("Sublime", CodeMirrorKeybindingSetting.Sublime));
|
||||||
|
keybindingDropdown.add(createOptionElement("Vim", CodeMirrorKeybindingSetting.Vim));
|
||||||
|
keybindingDropdown.add(createOptionElement("Emacs", CodeMirrorKeybindingSetting.Emacs));
|
||||||
|
if (Settings.EditorKeybinding) {
|
||||||
|
var initialIndex = 0;
|
||||||
|
for (var i = 0; i < keybindingDropdown.options.length; ++i) {
|
||||||
|
if (keybindingDropdown.options[i].value === Settings.EditorKeybinding) {
|
||||||
|
initialIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keybindingDropdown.selectedIndex = initialIndex;
|
||||||
|
} else {
|
||||||
|
keybindingDropdown.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
keybindingDropdown.onchange = () => {
|
||||||
|
// Set Vim command display to be invisible initially
|
||||||
|
this.vimCommandDisplayWrapper.style.display = "none";
|
||||||
|
|
||||||
|
const val = keybindingDropdown.value;
|
||||||
|
Settings.EditorKeybinding = val;
|
||||||
|
this.editor.removeKeyMap(CodeMirror.keyMap.default);
|
||||||
|
this.editor.removeKeyMap(CodeMirror.keyMap.sublime);
|
||||||
|
this.editor.removeKeyMap(CodeMirror.keyMap.emacs);
|
||||||
|
this.editor.removeKeyMap(CodeMirror.keyMap.vim);
|
||||||
|
|
||||||
|
// Setup the VIM command display
|
||||||
|
let keys = '';
|
||||||
|
const handleVimKeyPress = (key) => {
|
||||||
|
keys = keys + key;
|
||||||
|
this.vimCommandDisplay.innerHTML = keys;
|
||||||
|
}
|
||||||
|
const handleVimCommandDone = (e) => {
|
||||||
|
keys = '';
|
||||||
|
this.vimCommandDisplay.innerHTML = keys;
|
||||||
|
}
|
||||||
|
if (val === CodeMirrorKeybindingSetting.Vim) {
|
||||||
|
this.vimCommandDisplayWrapper.style.display = "block";
|
||||||
|
this.editor.on('vim-keypress', handleVimKeyPress);
|
||||||
|
this.editor.on('vim-command-done', handleVimCommandDone);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.vimCommandDisplayWrapper.style.display = "none";
|
||||||
|
this.editor.off('vim-keypress', handleVimKeyPress);
|
||||||
|
this.editor.off('vim-command-done', handleVimCommandDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editor.addKeyMap(val);
|
||||||
|
this.editor.setOption("keyMap", val);
|
||||||
|
};
|
||||||
|
keybindingDropdown.onchange();
|
||||||
|
|
||||||
|
// Highlight Active line
|
||||||
|
const highlightActiveChkBox = safeClearEventListeners("script-editor-option-highlightactiveline", "Active Line Checkbox");
|
||||||
|
highlightActiveChkBox.onchange = () => {
|
||||||
|
this.editor.setOption("styleActiveLine", highlightActiveChkBox.checked);
|
||||||
|
};
|
||||||
|
highlightActiveChkBox.onchange();
|
||||||
|
|
||||||
|
// Show Invisibles
|
||||||
|
const showInvisiblesChkBox = safeClearEventListeners("script-editor-option-showinvisibles", "Show Invisible Checkbox");
|
||||||
|
showInvisiblesChkBox.onchange = () => {
|
||||||
|
const overlayMode = {
|
||||||
|
name: 'invisibles',
|
||||||
|
token: function nextToken(stream) {
|
||||||
|
var ret,
|
||||||
|
spaces = 0,
|
||||||
|
space = stream.peek() === ' ';
|
||||||
|
|
||||||
|
if (space) {
|
||||||
|
while (space && spaces < MaxInvisibles) {
|
||||||
|
++spaces;
|
||||||
|
|
||||||
|
stream.next();
|
||||||
|
space = stream.peek() === ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 'whitespace whitespace-' + spaces;
|
||||||
|
} else {
|
||||||
|
while (!stream.eol() && !space) {
|
||||||
|
stream.next();
|
||||||
|
|
||||||
|
space = stream.peek() === ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 'cm-eol';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (showInvisiblesChkBox.checked) {
|
||||||
|
// Spaces
|
||||||
|
this.editor.addOverlay(overlayMode);
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
this.tabsStyleElement.innerHTML = ".cm-tab {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABDSURBVEhLYxgFo2BkAGYH/9r/QFoAxIGyhx6AORzZA4xD1TcHNjYzQplDB2CLgaECYHkADIZqqgGBoZdsRsHgBgwMAB8iFHF42AERAAAAAElFTkSuQmCC);background-position: right;background-repeat: no-repeat;}";
|
||||||
|
} else {
|
||||||
|
this.editor.removeOverlay("invisibles");
|
||||||
|
this.tabsStyleElement.innerHTML = "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
showInvisiblesChkBox.onchange();
|
||||||
|
|
||||||
|
//Use Soft Tab
|
||||||
|
const softTabChkBox = safeClearEventListeners("script-editor-option-usesofttab", "Soft Tab Checkbox");
|
||||||
|
softTabChkBox.onchange = () => {
|
||||||
|
this.editor.setOption("indentWithTabs", !softTabChkBox.checked);
|
||||||
|
if (softTabChkBox.checked) {
|
||||||
|
this.editor.addKeyMap({
|
||||||
|
name: "soft-tabs-keymap",
|
||||||
|
"Tab": function (cm) {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
var sel = cm.getSelection("\n");
|
||||||
|
// Indent only if there are multiple lines selected, or if the selection spans a full line
|
||||||
|
if (sel.length > 0 && (sel.indexOf("\n") > -1 || sel.length === cm.getLine(cm.getCursor().line).length)) {
|
||||||
|
cm.indentSelection("add");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cm.options.indentWithTabs)
|
||||||
|
cm.execCommand("insertTab");
|
||||||
|
else
|
||||||
|
cm.execCommand("insertSoftTab");
|
||||||
|
},
|
||||||
|
"Shift-Tab": function (cm) {
|
||||||
|
cm.indentSelection("subtract");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.editor.removeKeyMap("soft-tabs-keymap");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
softTabChkBox.onchange();
|
||||||
|
|
||||||
|
// Some helper functions for dealing with flexible options
|
||||||
|
function resetFlexibleOption(id) {
|
||||||
|
const fieldset = safeGetElementById(id);
|
||||||
|
removeChildrenFromElement(fieldset);
|
||||||
|
fieldset.style.display = "block";
|
||||||
|
return fieldset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFlexibleOption(id) {
|
||||||
|
// This doesn't really remove it, just sets it to invisible
|
||||||
|
const fieldset = resetFlexibleOption(id);
|
||||||
|
fieldset.style.display = "none";
|
||||||
|
return fieldset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex 1: Automatically Close Brackets and Quotes
|
||||||
|
const flex1Fieldset = resetFlexibleOption("script-editor-option-flex1-fieldset");
|
||||||
|
const flex1Id = "script-editor-option-flex1";
|
||||||
|
flex1Fieldset.appendChild(createElement("label", {
|
||||||
|
for: flex1Id,
|
||||||
|
innerText: "Auto-Close Brackets/Quotes",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const flex1Checkbox = createElement("input", {
|
||||||
|
checked: true,
|
||||||
|
id: flex1Id,
|
||||||
|
name: flex1Id,
|
||||||
|
type: "checkbox",
|
||||||
|
});
|
||||||
|
flex1Fieldset.appendChild(flex1Checkbox);
|
||||||
|
flex1Checkbox.onchange = () => {
|
||||||
|
this.editor.setOption("autoCloseBrackets", flex1Checkbox.checked);
|
||||||
|
};
|
||||||
|
flex1Checkbox.onchange();
|
||||||
|
|
||||||
|
// Flex 2: Disable/Enable Linting
|
||||||
|
const flex2Fieldset = resetFlexibleOption("script-editor-option-flex2-fieldset");
|
||||||
|
const flex2Id = "script-editor-option-flex2";
|
||||||
|
flex2Fieldset.appendChild(createElement("label", {
|
||||||
|
for: flex2Id,
|
||||||
|
innerText: "Enable Linting",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const flex2Checkbox = createElement("input", {
|
||||||
|
checked: true,
|
||||||
|
id: flex2Id,
|
||||||
|
name: flex2Id,
|
||||||
|
type: "checkbox",
|
||||||
|
});
|
||||||
|
flex2Fieldset.appendChild(flex2Checkbox);
|
||||||
|
flex2Checkbox.onchange = () => {
|
||||||
|
if (flex2Checkbox.checked) {
|
||||||
|
this.editor.setOption("lint", CodeMirror.lint.netscript);
|
||||||
|
} else {
|
||||||
|
this.editor.setOption("lint", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flex2Checkbox.onchange();
|
||||||
|
|
||||||
|
// Flex 3: Continue Comments
|
||||||
|
const flex3Fieldset = resetFlexibleOption("script-editor-option-flex3-fieldset");
|
||||||
|
const flex3Id = "script-editor-option-flex3";
|
||||||
|
flex3Fieldset.appendChild(createElement("label", {
|
||||||
|
for: flex3Id,
|
||||||
|
innerText: "Continue Comments",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const flex3Checkbox = createElement("input", {
|
||||||
|
checked: true,
|
||||||
|
id: flex3Id,
|
||||||
|
name: flex3Id,
|
||||||
|
type: "checkbox",
|
||||||
|
});
|
||||||
|
flex3Fieldset.appendChild(flex3Checkbox);
|
||||||
|
flex3Checkbox.onchange = () => {
|
||||||
|
this.editor.setOption("continueComments", flex3Checkbox.checked);
|
||||||
|
}
|
||||||
|
flex3Checkbox.onchange();
|
||||||
|
|
||||||
|
removeFlexibleOption("script-editor-option-flex4-fieldset");
|
||||||
|
|
||||||
|
this.editor.refresh();
|
||||||
|
} catch(e) {
|
||||||
|
console.error(`Exception caught: ${e}. ${e.stack}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isFocused() {
|
||||||
|
if (this.editor == null) { return false; }
|
||||||
|
return this.editor.hasFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the editor to be invisible
|
||||||
|
setInvisible() {
|
||||||
|
if (!this.initialized()) {
|
||||||
|
console.warn(`CodeMirrorEditor.setInvisible() called when editor was not initialized`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.editor != null) {
|
||||||
|
this.editor.toTextArea();
|
||||||
|
this.editor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elem = document.getElementById("codemirror-form-wrapper");
|
||||||
|
if (elem instanceof HTMLElement) {
|
||||||
|
elem.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CodeMirrorEditor = new CodeMirrorEditorWrapper();
|
82
src/ScriptEditor/CodeMirrorNetscriptLint.js
Normal file
82
src/ScriptEditor/CodeMirrorNetscriptLint.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||||
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||||
|
|
||||||
|
(function(mod) {
|
||||||
|
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||||
|
mod(require("codemirror/lib/codemirror"));
|
||||||
|
else if (typeof define == "function" && define.amd) // AMD
|
||||||
|
define(["codemirror/lib/codemirror"], mod);
|
||||||
|
else // Plain browser env
|
||||||
|
mod(CodeMirror);
|
||||||
|
})(function(CodeMirror) {
|
||||||
|
"use strict";
|
||||||
|
// declare global: JSHINT
|
||||||
|
|
||||||
|
function validator(text, options) {
|
||||||
|
if (!window.JSHINT) {
|
||||||
|
if (window.console) {
|
||||||
|
window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run.");
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// To ignore the 'async/await' errors, we'll manually edit the code ('text')
|
||||||
|
// that gets processed by JSHINT to include the ignore directory
|
||||||
|
const splitText = text.split("\n");
|
||||||
|
const ignoreDirective = " // jshint ignore:line";
|
||||||
|
for (let i = 0; i < splitText.length; ++i) {
|
||||||
|
if (splitText[i].match(/.*async function.+{/g)) {
|
||||||
|
splitText[i] += ignoreDirective;
|
||||||
|
} else if (splitText[i].match(/.*await.+;/g)) {
|
||||||
|
splitText[i] += ignoreDirective;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sanitizedText = splitText.join("\n");
|
||||||
|
|
||||||
|
// Configure JSHINT options
|
||||||
|
if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation
|
||||||
|
options.indent = 1; // JSHint default value is 4
|
||||||
|
|
||||||
|
options.esversion = 6;
|
||||||
|
|
||||||
|
JSHINT(sanitizedText, options, options.globals);
|
||||||
|
var errors = JSHINT.data().errors, result = [];
|
||||||
|
if (errors) parseErrors(errors, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeMirror.registerHelper("lint", "netscript", validator);
|
||||||
|
|
||||||
|
function parseErrors(errors, output) {
|
||||||
|
for ( var i = 0; i < errors.length; i++) {
|
||||||
|
var error = errors[i];
|
||||||
|
if (error) {
|
||||||
|
if (error.line == 0) { continue; }
|
||||||
|
if (error.line < 0) {
|
||||||
|
if (window.console) {
|
||||||
|
window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var start = error.character - 1, end = start + 1;
|
||||||
|
if (error.evidence) {
|
||||||
|
var index = error.evidence.substring(start).search(/.\b/);
|
||||||
|
if (index > -1) {
|
||||||
|
end += index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to format expected by validation service
|
||||||
|
var hint = {
|
||||||
|
message: error.reason,
|
||||||
|
severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error",
|
||||||
|
from: CodeMirror.Pos(error.line - 1, start),
|
||||||
|
to: CodeMirror.Pos(error.line - 1, end)
|
||||||
|
};
|
||||||
|
|
||||||
|
output.push(hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
1128
src/ScriptEditor/CodeMirrorNetscriptMode.js
Normal file
1128
src/ScriptEditor/CodeMirrorNetscriptMode.js
Normal file
File diff suppressed because it is too large
Load Diff
58
src/ScriptEditor/ScriptEditor.js
Normal file
58
src/ScriptEditor/ScriptEditor.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Base Script Editor class for the Ace/CodeMirror/etc. wrappers
|
||||||
|
const beautify = require('js-beautify').js_beautify;
|
||||||
|
|
||||||
|
export class ScriptEditor {
|
||||||
|
constructor() {
|
||||||
|
this.editor = null; // Stores the CodeMirror editor reference
|
||||||
|
this.filenameInput = null; // Stores the filename input DOM element
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
throw new Error(`Tried to initialize base ScriptEditor class`);
|
||||||
|
}
|
||||||
|
|
||||||
|
beautifyScript() {
|
||||||
|
if (this.editor == null) {
|
||||||
|
console.warn(`ScriptEditor.beautifyScript() called when editor was not initialized`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let code = this.editor.getValue();
|
||||||
|
code = beautify(code, {
|
||||||
|
indent_size: 4,
|
||||||
|
brace_style: "preserve-inline",
|
||||||
|
});
|
||||||
|
this.editor.setValue(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
openScript(filename="", code="") {
|
||||||
|
if (this.editor == null || this.filenameInput == null) {
|
||||||
|
console.warn(`ScriptEditor.openScript() called when editor was not initialized`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename != "") {
|
||||||
|
this.filenameInput.value = filename;
|
||||||
|
this.editor.setValue(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editor.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getCode() {
|
||||||
|
if (this.editor == null) {
|
||||||
|
console.warn(`ScriptEditor.getCode() called when editor was not initialized`);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.editor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilename() {
|
||||||
|
if (this.filenameInput == null) {
|
||||||
|
console.warn(`ScriptEditor.getFilename() called when editor was not initialized`);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.filenameInput.value;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { BitNodeMultipliers } from "./BitNodeMultipliers";
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
import { CodingContract,
|
import { CodingContract,
|
||||||
ContractTypes } from "./CodingContracts";
|
ContractTypes } from "./CodingContracts";
|
||||||
import { CONSTANTS } from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
|
@ -1,16 +1,46 @@
|
|||||||
import {CONSTANTS} from "./Constants";
|
/**
|
||||||
import {Player} from "./Player";
|
* Implements functions for purchasing servers or purchasing more RAM for
|
||||||
import {Server, AllServers, AddToAllServers} from "./Server";
|
* the home computer
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
|
||||||
import {createRandomIp} from "../utils/IPAddress";
|
|
||||||
import {yesNoTxtInpBoxGetInput} from "../utils/YesNoBox";
|
|
||||||
|
|
||||||
|
|
||||||
/* Functions to handle any server-related purchasing:
|
|
||||||
* Purchasing new servers
|
|
||||||
* Purchasing more RAM for home computer
|
|
||||||
*/
|
*/
|
||||||
function purchaseServer(ram, cost) {
|
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||||
|
import { CONSTANTS } from "./Constants";
|
||||||
|
import { Player } from "./Player";
|
||||||
|
import { Server,
|
||||||
|
AllServers,
|
||||||
|
AddToAllServers} from "./Server";
|
||||||
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
|
import { createRandomIp } from "../utils/IPAddress";
|
||||||
|
import { yesNoTxtInpBoxGetInput } from "../utils/YesNoBox";
|
||||||
|
import { isPowerOfTwo } from "../utils/helpers/isPowerOfTwo";
|
||||||
|
|
||||||
|
// Returns the cost of purchasing a server with the given RAM
|
||||||
|
// Returns Infinity for invalid 'ram' arguments
|
||||||
|
export function getPurchaseServerCost(ram) {
|
||||||
|
const sanitizedRam = Math.round(ram);
|
||||||
|
if (isNaN(sanitizedRam) || !isPowerOfTwo(sanitizedRam)) {
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sanitizedRam > getPurchaseServerMaxRam()) {
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitizedRam * CONSTANTS.BaseCostFor1GBOfRamServer * BitNodeMultipliers.PurchasedServerCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPurchaseServerLimit() {
|
||||||
|
return Math.round(CONSTANTS.PurchasedServerLimit * BitNodeMultipliers.PurchasedServerLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPurchaseServerMaxRam() {
|
||||||
|
// TODO ensure this is a power of 2?
|
||||||
|
return Math.round(CONSTANTS.PurchasedServerMaxRam * BitNodeMultipliers.PurchasedServerMaxRam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually purchase a server (NOT through Netscript)
|
||||||
|
export function purchaseServer(ram) {
|
||||||
|
const cost = getPurchaseServerCost(ram);
|
||||||
|
|
||||||
//Check if player has enough money
|
//Check if player has enough money
|
||||||
if (Player.money.lt(cost)) {
|
if (Player.money.lt(cost)) {
|
||||||
dialogBoxCreate("You don't have enough money to purchase this server!");
|
dialogBoxCreate("You don't have enough money to purchase this server!");
|
||||||
@ -18,8 +48,8 @@ function purchaseServer(ram, cost) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Maximum server limit
|
//Maximum server limit
|
||||||
if (Player.purchasedServers.length >= CONSTANTS.PurchasedServerLimit) {
|
if (Player.purchasedServers.length >= getPurchaseServerLimit()) {
|
||||||
dialogBoxCreate("You have reached the maximum limit of " + CONSTANTS.PurchasedServerLimit + " servers. " +
|
dialogBoxCreate("You have reached the maximum limit of " + getPurchaseServerLimit() + " servers. " +
|
||||||
"You cannot purchase any more. You can " +
|
"You cannot purchase any more. You can " +
|
||||||
"delete some of your purchased servers using the deleteServer() Netscript function in a script");
|
"delete some of your purchased servers using the deleteServer() Netscript function in a script");
|
||||||
return;
|
return;
|
||||||
@ -51,19 +81,22 @@ function purchaseServer(ram, cost) {
|
|||||||
dialogBoxCreate("Server successfully purchased with hostname " + hostname);
|
dialogBoxCreate("Server successfully purchased with hostname " + hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manually upgrade RAM on home computer (NOT through Netscript)
|
||||||
function purchaseRamForHomeComputer(cost) {
|
export function purchaseRamForHomeComputer(cost) {
|
||||||
if (Player.money.lt(cost)) {
|
if (Player.money.lt(cost)) {
|
||||||
dialogBoxCreate("You do not have enough money to purchase additional RAM for your home computer");
|
dialogBoxCreate("You do not have enough money to purchase additional RAM for your home computer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var homeComputer = Player.getHomeComputer();
|
const homeComputer = Player.getHomeComputer();
|
||||||
homeComputer.maxRam *= 2;
|
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
|
||||||
|
dialogBoxCreate(`You cannot upgrade your home computer RAM because it is at its maximum possible value`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
homeComputer.maxRam *= 2;
|
||||||
Player.loseMoney(cost);
|
Player.loseMoney(cost);
|
||||||
|
|
||||||
dialogBoxCreate("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM.");
|
dialogBoxCreate("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM.");
|
||||||
}
|
}
|
||||||
|
|
||||||
export {purchaseServer, purchaseRamForHomeComputer};
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Enum Of allowed values for the 'OwnedAugmentationsOrder' setting
|
|
||||||
*/
|
|
||||||
export enum OwnedAugmentationsOrderSetting {
|
|
||||||
Alphabetically,
|
|
||||||
AcquirementTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum Of allowed values for the 'OwnedAugmentationsOrder' setting
|
|
||||||
*/
|
|
||||||
export enum PurchaseAugmentationsOrderSetting {
|
|
||||||
Cost,
|
|
||||||
Default,
|
|
||||||
Reputation,
|
|
||||||
}
|
|
106
src/Settings/SettingEnums.ts
Normal file
106
src/Settings/SettingEnums.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Enums that defined allowed values for setting configuration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed values for 'Keybinding/Keymap' setting in Ace editor
|
||||||
|
*/
|
||||||
|
export enum AceKeybindingSetting {
|
||||||
|
Ace = "ace",
|
||||||
|
Emacs = "emacs",
|
||||||
|
Vim = "vim",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed values for 'Keybinding/Keymap' setting in Code Mirror editor
|
||||||
|
*/
|
||||||
|
export enum CodeMirrorKeybindingSetting {
|
||||||
|
Default = "default",
|
||||||
|
Emacs = "emacs",
|
||||||
|
Sublime = "sublime",
|
||||||
|
Vim = "vim",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed values for 'Theme' setting in Code Mirror editor
|
||||||
|
*/
|
||||||
|
export enum CodeMirrorThemeSetting {
|
||||||
|
Monokai = "monokai",
|
||||||
|
Day_3024 = "3024-day",
|
||||||
|
Night_3024 = "3024-night",
|
||||||
|
abcdef = "abcdef",
|
||||||
|
Ambiance_mobile = "ambiance-mobile",
|
||||||
|
Ambiance = "ambiance",
|
||||||
|
Base16_dark = "base16-dark",
|
||||||
|
Base16_light = "base16-light",
|
||||||
|
Bespin = "bespin",
|
||||||
|
Blackboard = "blackboard",
|
||||||
|
Cobalt = "cobalt",
|
||||||
|
Colorforth = "colorforth",
|
||||||
|
Darcula = "darcula",
|
||||||
|
Dracula = "dracula",
|
||||||
|
Duotone_dark = "duotone-dark",
|
||||||
|
Duotone_light = "duotone-light",
|
||||||
|
Eclipse = "eclipse",
|
||||||
|
Elegant = "elegant",
|
||||||
|
Erlang_dark = "erlang-dark",
|
||||||
|
Gruvbox_dark = "gruvbox-dark",
|
||||||
|
Hopscotch = "hopscotch",
|
||||||
|
Icecoder = "icecoder",
|
||||||
|
Idea = "idea",
|
||||||
|
Isotope = "isotope",
|
||||||
|
Lesser_dark = "lesser-dark",
|
||||||
|
Liquibyte = "liquibyte",
|
||||||
|
Lucario = "lucario",
|
||||||
|
Material = "material",
|
||||||
|
Mbo = "mbo",
|
||||||
|
Mdn_like = "mdn-like",
|
||||||
|
Midnight = "midnight",
|
||||||
|
Neat = "neat",
|
||||||
|
Neo = "neo",
|
||||||
|
Night = "night",
|
||||||
|
Oceanic_next = "oceanic-next",
|
||||||
|
Panda_syntax = "panda-syntax",
|
||||||
|
Paraiso_dark = "paraiso-dark",
|
||||||
|
Paraiso_light = "paraiso-light",
|
||||||
|
Pastel_on_dark = "pastel-on-dark",
|
||||||
|
Railscasts = "railscasts",
|
||||||
|
Rubyblue = "rubyblue",
|
||||||
|
Seti = "seti",
|
||||||
|
Shadowfox = "shadowfox",
|
||||||
|
Solarized = "solarized",
|
||||||
|
ssms = "ssms",
|
||||||
|
The_matrix = "the-matrix",
|
||||||
|
Tomorrow_night_bright = "tomorrow-night-bright",
|
||||||
|
Tomorrow_night_eighties = "tomorrow-night-eighties",
|
||||||
|
Ttcn = "ttcn",
|
||||||
|
Twilight = "twilight",
|
||||||
|
Vibrant_ink = "vibrant-ink",
|
||||||
|
xq_dark = "xq-dark",
|
||||||
|
xq_light = "xq-light",
|
||||||
|
Yeti = "yeti",
|
||||||
|
Zenburn = "zenburn",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed values for the "Editor" setting
|
||||||
|
*/
|
||||||
|
export enum EditorSetting {
|
||||||
|
Ace = "Ace",
|
||||||
|
CodeMirror = "CodeMirror",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed values for the 'OwnedAugmentationsOrder' setting
|
||||||
|
*/
|
||||||
|
export enum PurchaseAugmentationsOrderSetting {
|
||||||
|
Cost,
|
||||||
|
Default,
|
||||||
|
Reputation,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed values for the 'OwnedAugmentationsOrder' setting
|
||||||
|
*/
|
||||||
|
export enum OwnedAugmentationsOrderSetting {
|
||||||
|
Alphabetically,
|
||||||
|
AcquirementTime,
|
||||||
|
}
|
@ -1,5 +1,10 @@
|
|||||||
import { ISelfInitializer, ISelfLoading } from "./types";
|
import { ISelfInitializer, ISelfLoading } from "../types";
|
||||||
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
|
import { AceKeybindingSetting,
|
||||||
|
CodeMirrorKeybindingSetting,
|
||||||
|
CodeMirrorThemeSetting,
|
||||||
|
EditorSetting,
|
||||||
|
OwnedAugmentationsOrderSetting,
|
||||||
|
PurchaseAugmentationsOrderSetting } from "./SettingEnums";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the default settings the player could customize.
|
* Represents the default settings the player could customize.
|
||||||
@ -65,17 +70,22 @@ interface IDefaultSettings {
|
|||||||
* Represents all possible settings the player wants to customize to their play style.
|
* Represents all possible settings the player wants to customize to their play style.
|
||||||
*/
|
*/
|
||||||
interface ISettings extends IDefaultSettings {
|
interface ISettings extends IDefaultSettings {
|
||||||
|
/**
|
||||||
|
* Which editor should be used (CodeMirror or Ace)?
|
||||||
|
*/
|
||||||
|
Editor: EditorSetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The keybinding to use in the script editor.
|
* The keybinding to use in the script editor.
|
||||||
* TODO: This should really be an enum of allowed values.
|
* TODO: This should really be an enum of allowed values.
|
||||||
*/
|
*/
|
||||||
EditorKeybinding: string;
|
EditorKeybinding: AceKeybindingSetting | CodeMirrorKeybindingSetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The theme used in the script editor.
|
* The theme used in the script editor.
|
||||||
* TODO: This should really be an enum of allowed values.
|
* TODO: This should really be an enum of allowed values.
|
||||||
*/
|
*/
|
||||||
EditorTheme: string;
|
EditorTheme: string | CodeMirrorThemeSetting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What order the player's owned Augmentations/Source Files should be displayed in
|
* What order the player's owned Augmentations/Source Files should be displayed in
|
||||||
@ -110,7 +120,8 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
|||||||
AutosaveInterval: defaultSettings.AutosaveInterval,
|
AutosaveInterval: defaultSettings.AutosaveInterval,
|
||||||
CodeInstructionRunTime: 25,
|
CodeInstructionRunTime: 25,
|
||||||
DisableHotkeys: defaultSettings.DisableHotkeys,
|
DisableHotkeys: defaultSettings.DisableHotkeys,
|
||||||
EditorKeybinding: "ace",
|
Editor: EditorSetting.Ace,
|
||||||
|
EditorKeybinding: AceKeybindingSetting.Ace,
|
||||||
EditorTheme: "Monokai",
|
EditorTheme: "Monokai",
|
||||||
Locale: "en",
|
Locale: "en",
|
||||||
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
@ -1,5 +1,5 @@
|
|||||||
import {Player} from "./Player";
|
import { Player } from "./Player";
|
||||||
import {BitNodes} from "./BitNode";
|
import { BitNodes } from "./BitNode/BitNode";
|
||||||
|
|
||||||
/* SourceFile.js */
|
/* SourceFile.js */
|
||||||
//Each SourceFile corresponds to a BitNode with the same number
|
//Each SourceFile corresponds to a BitNode with the same number
|
||||||
@ -63,7 +63,8 @@ function initSourceFiles() {
|
|||||||
"This Source-File also increases your hacking growth multipliers by: " +
|
"This Source-File also increases your hacking growth multipliers by: " +
|
||||||
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
||||||
SourceFiles["SourceFile9"] = new SourceFile(9);
|
SourceFiles["SourceFile9"] = new SourceFile(9);
|
||||||
SourceFiles["SourceFile10"] = new SourceFile(10);
|
SourceFiles["SourceFile10"] = new SourceFile(10, "This Source-File unlocks Sleeve technology in other BitNodes. Each level of this " +
|
||||||
|
"Source-File also grants you a Duplicate Sleeve");
|
||||||
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " +
|
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " +
|
||||||
"at that company by 1% per favor (rather than just the reputation gain). This Source-File also " +
|
"at that company by 1% per favor (rather than just the reputation gain). This Source-File also " +
|
||||||
" increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
" increases the player's company salary and reputation gain multipliers by:<br><br>" +
|
||||||
@ -74,11 +75,6 @@ function initSourceFiles() {
|
|||||||
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
|
||||||
}
|
}
|
||||||
|
|
||||||
function PlayerOwnedSourceFile(number, level) {
|
|
||||||
this.n = number;
|
|
||||||
this.lvl = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Takes in a PlayerOwnedSourceFile as the "srcFile" argument
|
//Takes in a PlayerOwnedSourceFile as the "srcFile" argument
|
||||||
function applySourceFile(srcFile) {
|
function applySourceFile(srcFile) {
|
||||||
var srcFileKey = "SourceFile" + srcFile.n;
|
var srcFileKey = "SourceFile" + srcFile.n;
|
||||||
@ -192,6 +188,9 @@ function applySourceFile(srcFile) {
|
|||||||
var incMult = 1 + (mult / 100);
|
var incMult = 1 + (mult / 100);
|
||||||
Player.hacking_grow_mult *= incMult;
|
Player.hacking_grow_mult *= incMult;
|
||||||
break;
|
break;
|
||||||
|
case 10: // Digital Carbon
|
||||||
|
// No effects, just grants sleeves
|
||||||
|
break;
|
||||||
case 11: //The Big Crash
|
case 11: //The Big Crash
|
||||||
var mult = 0;
|
var mult = 0;
|
||||||
for (var i = 0; i < srcFile.lvl; ++i) {
|
for (var i = 0; i < srcFile.lvl; ++i) {
|
||||||
@ -246,4 +245,4 @@ function applySourceFile(srcFile) {
|
|||||||
sourceFileObject.owned = true;
|
sourceFileObject.owned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {SourceFiles, PlayerOwnedSourceFile, applySourceFile, initSourceFiles};
|
export {SourceFiles, applySourceFile, initSourceFiles};
|
||||||
|
17
src/SourceFile/PlayerOwnedSourceFile.ts
Normal file
17
src/SourceFile/PlayerOwnedSourceFile.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export class PlayerOwnedSourceFile {
|
||||||
|
// Source-File level
|
||||||
|
lvl: number = 1;
|
||||||
|
|
||||||
|
// Source-File number
|
||||||
|
n: number = 1;
|
||||||
|
|
||||||
|
constructor(n: number, level: number) {
|
||||||
|
this.n = n;
|
||||||
|
this.lvl = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPlayerOwnedSourceFile {
|
||||||
|
lvl: number;
|
||||||
|
n: number;
|
||||||
|
}
|
18
src/SourceFile/SourceFileFlags.ts
Normal file
18
src/SourceFile/SourceFileFlags.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Contains an array containing information about the player's source files
|
||||||
|
// Array[n] returns what level the player has of Source-File N.
|
||||||
|
|
||||||
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
export const SourceFileFlags: number[] = Array(CONSTANTS.TotalNumBitNodes + 1); // Skip 0
|
||||||
|
|
||||||
|
export function updateSourceFileFlags(p: IPlayer) {
|
||||||
|
for (let i = 0; i < SourceFileFlags.length; ++i) {
|
||||||
|
SourceFileFlags[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < p.sourceFiles.length; ++i) {
|
||||||
|
const sf = p.sourceFiles[i];
|
||||||
|
SourceFileFlags[sf.n] = sf.lvl;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the valuation of a company in the World Stock Exchange.
|
* Represents the valuation of a company in the World Stock Exchange.
|
||||||
@ -22,6 +22,11 @@ export class Stock {
|
|||||||
*/
|
*/
|
||||||
readonly cap: number;
|
readonly cap: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of shares that player can own (both long and short combined)
|
||||||
|
*/
|
||||||
|
readonly maxShares: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum volatility
|
* Maximum volatility
|
||||||
*/
|
*/
|
||||||
@ -73,12 +78,20 @@ export class Stock {
|
|||||||
*/
|
*/
|
||||||
readonly symbol: string;
|
readonly symbol: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total number of shares of this stock
|
||||||
|
* This is different than maxShares, as this is like authorized stock while
|
||||||
|
* maxShares is outstanding stock.
|
||||||
|
*/
|
||||||
|
readonly totalShares: number;
|
||||||
|
|
||||||
constructor(name: string = "",
|
constructor(name: string = "",
|
||||||
symbol: string = "",
|
symbol: string = "",
|
||||||
mv: number = 1,
|
mv: number = 1,
|
||||||
b: boolean = true,
|
b: boolean = true,
|
||||||
otlkMag: number = 0,
|
otlkMag: number = 0,
|
||||||
initPrice: number = 10e3) {
|
initPrice: number = 10e3,
|
||||||
|
marketCap: number = 1e12) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.symbol = symbol;
|
this.symbol = symbol;
|
||||||
this.price = initPrice;
|
this.price = initPrice;
|
||||||
@ -91,6 +104,14 @@ export class Stock {
|
|||||||
this.otlkMag = otlkMag;
|
this.otlkMag = otlkMag;
|
||||||
this.cap = getRandomInt(initPrice * 1e3, initPrice * 25e3);
|
this.cap = getRandomInt(initPrice * 1e3, initPrice * 25e3);
|
||||||
|
|
||||||
|
// Total shares is determined by market cap, and is rounded to nearest 100k
|
||||||
|
let totalSharesUnrounded: number = (marketCap / initPrice);
|
||||||
|
this.totalShares = Math.round(totalSharesUnrounded / 1e5) * 1e5;
|
||||||
|
|
||||||
|
// Max Shares (Outstanding shares) is a percentage of total shares
|
||||||
|
const outstandingSharePercentage: number = 0.2;
|
||||||
|
this.maxShares = Math.round((this.totalShares * outstandingSharePercentage) / 1e5) * 1e5;
|
||||||
|
|
||||||
this.posTxtEl = null;
|
this.posTxtEl = null;
|
||||||
}
|
}
|
||||||
|
|
145
src/StockMarket.js → src/StockMarket/StockMarket.js
Executable file → Normal file
145
src/StockMarket.js → src/StockMarket/StockMarket.js
Executable file → Normal file
@ -1,27 +1,29 @@
|
|||||||
import {CONSTANTS} from "./Constants";
|
|
||||||
import {Locations} from "./Locations";
|
|
||||||
import {hasWallStreetSF, wallStreetSFLvl} from "./NetscriptFunctions";
|
|
||||||
import {WorkerScript} from "./NetscriptWorker";
|
|
||||||
import {Player} from "./Player";
|
|
||||||
import {Stock} from "./Stock";
|
import {Stock} from "./Stock";
|
||||||
|
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {CONSTANTS} from "../Constants";
|
||||||
import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners";
|
import {Locations} from "../Locations";
|
||||||
|
import {hasWallStreetSF, wallStreetSFLvl} from "../NetscriptFunctions";
|
||||||
|
import {WorkerScript} from "../NetscriptWorker";
|
||||||
|
import {Player} from "../Player";
|
||||||
|
|
||||||
|
import {Page, routing} from ".././ui/navigationTracking";
|
||||||
|
import {numeralWrapper} from ".././ui/numeralFormat";
|
||||||
|
|
||||||
|
import {dialogBoxCreate} from "../../utils/DialogBox";
|
||||||
|
import {clearEventListeners} from "../../utils/uiHelpers/clearEventListeners";
|
||||||
import {Reviver, Generic_toJSON,
|
import {Reviver, Generic_toJSON,
|
||||||
Generic_fromJSON} from "../utils/JSONReviver";
|
Generic_fromJSON} from "../../utils/JSONReviver";
|
||||||
import {Page, routing} from "./ui/navigationTracking";
|
import {exceptionAlert} from "../../utils/helpers/exceptionAlert";
|
||||||
import {numeralWrapper} from "./ui/numeralFormat";
|
import {getRandomInt} from "../../utils/helpers/getRandomInt";
|
||||||
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
|
import {KEY} from "../../utils/helpers/keyCodes";
|
||||||
import {getRandomInt} from "../utils/helpers/getRandomInt";
|
import {createElement} from "../../utils/uiHelpers/createElement";
|
||||||
import {KEY} from "../utils/helpers/keyCodes";
|
import {removeChildrenFromElement} from "../../utils/uiHelpers/removeChildrenFromElement";
|
||||||
import {createElement} from "../utils/uiHelpers/createElement";
|
import {removeElementById} from "../../utils/uiHelpers/removeElementById";
|
||||||
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
|
||||||
import {removeElementById} from "../utils/uiHelpers/removeElementById";
|
|
||||||
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
|
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
|
||||||
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
|
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
|
||||||
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
|
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
|
||||||
yesNoTxtInpBoxGetInput, yesNoBoxClose,
|
yesNoTxtInpBoxGetInput, yesNoBoxClose,
|
||||||
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox";
|
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../../utils/YesNoBox";
|
||||||
|
|
||||||
var OrderTypes = {
|
var OrderTypes = {
|
||||||
LimitBuy: "Limit Buy Order",
|
LimitBuy: "Limit Buy Order",
|
||||||
@ -228,135 +230,135 @@ function initStockMarket() {
|
|||||||
const randInt = getRandomInt;
|
const randInt = getRandomInt;
|
||||||
|
|
||||||
var ecorp = Locations.AevumECorp;
|
var ecorp = Locations.AevumECorp;
|
||||||
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], randInt(40, 50) / 100, true, 19, randInt(17e3, 28e3));
|
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], randInt(40, 50) / 100, true, 19, randInt(17e3, 28e3), 2.4e12);
|
||||||
StockMarket[ecorp] = ecorpStk;
|
StockMarket[ecorp] = ecorpStk;
|
||||||
|
|
||||||
var megacorp = Locations.Sector12MegaCorp;
|
var megacorp = Locations.Sector12MegaCorp;
|
||||||
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], randInt(40,50)/100, true, 19, randInt(24e3, 34e3));
|
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], randInt(40,50)/100, true, 19, randInt(24e3, 34e3), 2.4e12);
|
||||||
StockMarket[megacorp] = megacorpStk;
|
StockMarket[megacorp] = megacorpStk;
|
||||||
|
|
||||||
var blade = Locations.Sector12BladeIndustries;
|
var blade = Locations.Sector12BladeIndustries;
|
||||||
var bladeStk = new Stock(blade, StockSymbols[blade], randInt(70, 80)/100, true, 13, randInt(12e3, 25e3));
|
var bladeStk = new Stock(blade, StockSymbols[blade], randInt(70, 80)/100, true, 13, randInt(12e3, 25e3), 1.6e12);
|
||||||
StockMarket[blade] = bladeStk;
|
StockMarket[blade] = bladeStk;
|
||||||
|
|
||||||
var clarke = Locations.AevumClarkeIncorporated;
|
var clarke = Locations.AevumClarkeIncorporated;
|
||||||
var clarkeStk = new Stock(clarke, StockSymbols[clarke], randInt(65, 75)/100, true, 12, randInt(10e3, 25e3));
|
var clarkeStk = new Stock(clarke, StockSymbols[clarke], randInt(65, 75)/100, true, 12, randInt(10e3, 25e3), 1.5e12);
|
||||||
StockMarket[clarke] = clarkeStk;
|
StockMarket[clarke] = clarkeStk;
|
||||||
|
|
||||||
var omnitek = Locations.VolhavenOmniTekIncorporated;
|
var omnitek = Locations.VolhavenOmniTekIncorporated;
|
||||||
var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], randInt(60, 70)/100, true, 12, randInt(32e3, 43e3));
|
var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], randInt(60, 70)/100, true, 12, randInt(32e3, 43e3), 1.8e12);
|
||||||
StockMarket[omnitek] = omnitekStk;
|
StockMarket[omnitek] = omnitekStk;
|
||||||
|
|
||||||
var foursigma = Locations.Sector12FourSigma;
|
var foursigma = Locations.Sector12FourSigma;
|
||||||
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], randInt(100, 110)/100, true, 17, randInt(50e3, 80e3));
|
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], randInt(100, 110)/100, true, 17, randInt(50e3, 80e3), 2e12);
|
||||||
StockMarket[foursigma] = foursigmaStk;
|
StockMarket[foursigma] = foursigmaStk;
|
||||||
|
|
||||||
var kuaigong = Locations.ChongqingKuaiGongInternational;
|
var kuaigong = Locations.ChongqingKuaiGongInternational;
|
||||||
var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], randInt(75, 85)/100, true, 10, randInt(16e3, 28e3));
|
var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], randInt(75, 85)/100, true, 10, randInt(16e3, 28e3), 1.9e12);
|
||||||
StockMarket[kuaigong] = kuaigongStk;
|
StockMarket[kuaigong] = kuaigongStk;
|
||||||
|
|
||||||
var fulcrum = Locations.AevumFulcrumTechnologies;
|
var fulcrum = Locations.AevumFulcrumTechnologies;
|
||||||
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3));
|
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3), 2e12);
|
||||||
StockMarket[fulcrum] = fulcrumStk;
|
StockMarket[fulcrum] = fulcrumStk;
|
||||||
|
|
||||||
var storm = Locations.IshimaStormTechnologies;
|
var storm = Locations.IshimaStormTechnologies;
|
||||||
var stormStk = new Stock(storm, StockSymbols[storm], randInt(80, 90)/100, true, 7, randInt(20e3, 25e3));
|
var stormStk = new Stock(storm, StockSymbols[storm], randInt(80, 90)/100, true, 7, randInt(20e3, 25e3), 1.2e12);
|
||||||
StockMarket[storm] = stormStk;
|
StockMarket[storm] = stormStk;
|
||||||
|
|
||||||
var defcomm = Locations.NewTokyoDefComm;
|
var defcomm = Locations.NewTokyoDefComm;
|
||||||
var defcommStk = new Stock(defcomm, StockSymbols[defcomm], randInt(60, 70)/100, true, 10, randInt(6e3, 19e3));
|
var defcommStk = new Stock(defcomm, StockSymbols[defcomm], randInt(60, 70)/100, true, 10, randInt(6e3, 19e3), 900e9);
|
||||||
StockMarket[defcomm] = defcommStk;
|
StockMarket[defcomm] = defcommStk;
|
||||||
|
|
||||||
var helios = Locations.VolhavenHeliosLabs;
|
var helios = Locations.VolhavenHeliosLabs;
|
||||||
var heliosStk = new Stock(helios, StockSymbols[helios], randInt(55, 65)/100, true, 9, randInt(10e3, 18e3));
|
var heliosStk = new Stock(helios, StockSymbols[helios], randInt(55, 65)/100, true, 9, randInt(10e3, 18e3), 825e9);
|
||||||
StockMarket[helios] = heliosStk;
|
StockMarket[helios] = heliosStk;
|
||||||
|
|
||||||
var vitalife = Locations.NewTokyoVitaLife;
|
var vitalife = Locations.NewTokyoVitaLife;
|
||||||
var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], randInt(70, 80)/100, true, 7, randInt(8e3, 14e3));
|
var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], randInt(70, 80)/100, true, 7, randInt(8e3, 14e3), 1e12);
|
||||||
StockMarket[vitalife] = vitalifeStk;
|
StockMarket[vitalife] = vitalifeStk;
|
||||||
|
|
||||||
var icarus = Locations.Sector12IcarusMicrosystems;
|
var icarus = Locations.Sector12IcarusMicrosystems;
|
||||||
var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3));
|
var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3), 800e9);
|
||||||
StockMarket[icarus] = icarusStk;
|
StockMarket[icarus] = icarusStk;
|
||||||
|
|
||||||
var universalenergy = Locations.Sector12UniversalEnergy;
|
var universalenergy = Locations.Sector12UniversalEnergy;
|
||||||
var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], randInt(50, 60)/100, true, 10, randInt(16e3, 29e3));
|
var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], randInt(50, 60)/100, true, 10, randInt(16e3, 29e3), 900e9);
|
||||||
StockMarket[universalenergy] = universalenergyStk;
|
StockMarket[universalenergy] = universalenergyStk;
|
||||||
|
|
||||||
var aerocorp = Locations.AevumAeroCorp;
|
var aerocorp = Locations.AevumAeroCorp;
|
||||||
var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], randInt(55, 65)/100, true, 6, randInt(8e3, 17e3));
|
var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], randInt(55, 65)/100, true, 6, randInt(8e3, 17e3), 640e9);
|
||||||
StockMarket[aerocorp] = aerocorpStk;
|
StockMarket[aerocorp] = aerocorpStk;
|
||||||
|
|
||||||
var omnia = Locations.VolhavenOmniaCybersystems;
|
var omnia = Locations.VolhavenOmniaCybersystems;
|
||||||
var omniaStk = new Stock(omnia, StockSymbols[omnia], randInt(65, 75)/100, true, 4.5, randInt(6e3, 15e3));
|
var omniaStk = new Stock(omnia, StockSymbols[omnia], randInt(65, 75)/100, true, 4.5, randInt(6e3, 15e3), 600e9);
|
||||||
StockMarket[omnia] = omniaStk;
|
StockMarket[omnia] = omniaStk;
|
||||||
|
|
||||||
var solaris = Locations.ChongqingSolarisSpaceSystems;
|
var solaris = Locations.ChongqingSolarisSpaceSystems;
|
||||||
var solarisStk = new Stock(solaris, StockSymbols[solaris], randInt(70, 80)/100, true, 8.5, randInt(14e3, 28e3));
|
var solarisStk = new Stock(solaris, StockSymbols[solaris], randInt(70, 80)/100, true, 8.5, randInt(14e3, 28e3), 705e9);
|
||||||
StockMarket[solaris] = solarisStk;
|
StockMarket[solaris] = solarisStk;
|
||||||
|
|
||||||
var globalpharm = Locations.NewTokyoGlobalPharmaceuticals;
|
var globalpharm = Locations.NewTokyoGlobalPharmaceuticals;
|
||||||
var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], randInt(55, 65)/100, true, 10.5, randInt(12e3, 30e3));
|
var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], randInt(55, 65)/100, true, 10.5, randInt(12e3, 30e3), 695e9);
|
||||||
StockMarket[globalpharm] = globalpharmStk;
|
StockMarket[globalpharm] = globalpharmStk;
|
||||||
|
|
||||||
var nova = Locations.IshimaNovaMedical;
|
var nova = Locations.IshimaNovaMedical;
|
||||||
var novaStk = new Stock(nova, StockSymbols[nova], randInt(70, 80)/100, true, 5, randInt(15e3, 27e3));
|
var novaStk = new Stock(nova, StockSymbols[nova], randInt(70, 80)/100, true, 5, randInt(15e3, 27e3), 600e9);
|
||||||
StockMarket[nova] = novaStk;
|
StockMarket[nova] = novaStk;
|
||||||
|
|
||||||
var watchdog = Locations.AevumWatchdogSecurity;
|
var watchdog = Locations.AevumWatchdogSecurity;
|
||||||
var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], randInt(240, 260)/100, true, 1.5, randInt(4e3, 8.5e3));
|
var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], randInt(240, 260)/100, true, 1.5, randInt(4e3, 8.5e3), 450e9);
|
||||||
StockMarket[watchdog] = watchdogStk;
|
StockMarket[watchdog] = watchdogStk;
|
||||||
|
|
||||||
var lexocorp = Locations.VolhavenLexoCorp;
|
var lexocorp = Locations.VolhavenLexoCorp;
|
||||||
var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], randInt(115, 135)/100, true, 6, randInt(4.5e3, 8e3));
|
var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], randInt(115, 135)/100, true, 6, randInt(4.5e3, 8e3), 300e9);
|
||||||
StockMarket[lexocorp] = lexocorpStk;
|
StockMarket[lexocorp] = lexocorpStk;
|
||||||
|
|
||||||
var rho = Locations.AevumRhoConstruction;
|
var rho = Locations.AevumRhoConstruction;
|
||||||
var rhoStk = new Stock(rho, StockSymbols[rho], randInt(50, 70)/100, true, 1, randInt(2e3, 7e3));
|
var rhoStk = new Stock(rho, StockSymbols[rho], randInt(50, 70)/100, true, 1, randInt(2e3, 7e3), 180e9);
|
||||||
StockMarket[rho] = rhoStk;
|
StockMarket[rho] = rhoStk;
|
||||||
|
|
||||||
var alpha = Locations.Sector12AlphaEnterprises;
|
var alpha = Locations.Sector12AlphaEnterprises;
|
||||||
var alphaStk = new Stock(alpha, StockSymbols[alpha], randInt(175, 205)/100, true, 10, randInt(4e3, 8.5e3));
|
var alphaStk = new Stock(alpha, StockSymbols[alpha], randInt(175, 205)/100, true, 10, randInt(4e3, 8.5e3), 240e9);
|
||||||
StockMarket[alpha] = alphaStk;
|
StockMarket[alpha] = alphaStk;
|
||||||
|
|
||||||
var syscore = Locations.VolhavenSysCoreSecurities;
|
var syscore = Locations.VolhavenSysCoreSecurities;
|
||||||
var syscoreStk = new Stock(syscore, StockSymbols[syscore], randInt(150, 170)/100, true, 3, randInt(3e3, 8e3));
|
var syscoreStk = new Stock(syscore, StockSymbols[syscore], randInt(150, 170)/100, true, 3, randInt(3e3, 8e3), 200e9);
|
||||||
StockMarket[syscore] = syscoreStk;
|
StockMarket[syscore] = syscoreStk;
|
||||||
|
|
||||||
var computek = Locations.VolhavenCompuTek;
|
var computek = Locations.VolhavenCompuTek;
|
||||||
var computekStk = new Stock(computek, StockSymbols[computek], randInt(80, 100)/100, true, 4, randInt(1e3, 6e3));
|
var computekStk = new Stock(computek, StockSymbols[computek], randInt(80, 100)/100, true, 4, randInt(1e3, 6e3), 185e9);
|
||||||
StockMarket[computek] = computekStk;
|
StockMarket[computek] = computekStk;
|
||||||
|
|
||||||
var netlink = Locations.AevumNetLinkTechnologies;
|
var netlink = Locations.AevumNetLinkTechnologies;
|
||||||
var netlinkStk = new Stock(netlink, StockSymbols[netlink], randInt(400, 430)/100, true, 1, randInt(1e3, 5e3));
|
var netlinkStk = new Stock(netlink, StockSymbols[netlink], randInt(400, 430)/100, true, 1, randInt(1e3, 5e3), 58e9);
|
||||||
StockMarket[netlink] = netlinkStk;
|
StockMarket[netlink] = netlinkStk;
|
||||||
|
|
||||||
var omega = Locations.IshimaOmegaSoftware;
|
var omega = Locations.IshimaOmegaSoftware;
|
||||||
var omegaStk = new Stock(omega, StockSymbols[omega], randInt(90, 110)/100, true, 0.5, randInt(1e3, 8e3));
|
var omegaStk = new Stock(omega, StockSymbols[omega], randInt(90, 110)/100, true, 0.5, randInt(1e3, 8e3), 60e9);
|
||||||
StockMarket[omega] = omegaStk;
|
StockMarket[omega] = omegaStk;
|
||||||
|
|
||||||
var fns = Locations.Sector12FoodNStuff;
|
var fns = Locations.Sector12FoodNStuff;
|
||||||
var fnsStk = new Stock(fns, StockSymbols[fns], randInt(70, 80)/100, false, 1, randInt(500, 4.5e3));
|
var fnsStk = new Stock(fns, StockSymbols[fns], randInt(70, 80)/100, false, 1, randInt(500, 4.5e3), 45e9);
|
||||||
StockMarket[fns] = fnsStk;
|
StockMarket[fns] = fnsStk;
|
||||||
|
|
||||||
var sigmacosm = "Sigma Cosmetics";
|
var sigmacosm = "Sigma Cosmetics";
|
||||||
var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], randInt(260, 300)/100, true, 0, randInt(1.5e3, 3.5e3));
|
var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], randInt(260, 300)/100, true, 0, randInt(1.5e3, 3.5e3), 30e9);
|
||||||
StockMarket[sigmacosm] = sigmacosmStk;
|
StockMarket[sigmacosm] = sigmacosmStk;
|
||||||
|
|
||||||
var joesguns = "Joes Guns";
|
var joesguns = "Joes Guns";
|
||||||
var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], randInt(360, 400)/100, true, 1, randInt(250, 1.5e3));
|
var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], randInt(360, 400)/100, true, 1, randInt(250, 1.5e3), 42e9);
|
||||||
StockMarket[joesguns] = joesgunsStk;
|
StockMarket[joesguns] = joesgunsStk;
|
||||||
|
|
||||||
var catalyst = "Catalyst Ventures";
|
var catalyst = "Catalyst Ventures";
|
||||||
var catalystStk = new Stock(catalyst, StockSymbols[catalyst], randInt(120, 175)/100, true, 13.5, randInt(250, 1.5e3));
|
var catalystStk = new Stock(catalyst, StockSymbols[catalyst], randInt(120, 175)/100, true, 13.5, randInt(250, 1.5e3), 100e9);
|
||||||
StockMarket[catalyst] = catalystStk;
|
StockMarket[catalyst] = catalystStk;
|
||||||
|
|
||||||
var microdyne = "Microdyne Technologies";
|
var microdyne = "Microdyne Technologies";
|
||||||
var microdyneStk = new Stock(microdyne, StockSymbols[microdyne], randInt(70, 80)/100, true, 8, randInt(15e3, 30e3));
|
var microdyneStk = new Stock(microdyne, StockSymbols[microdyne], randInt(70, 80)/100, true, 8, randInt(15e3, 30e3), 360e9);
|
||||||
StockMarket[microdyne] = microdyneStk;
|
StockMarket[microdyne] = microdyneStk;
|
||||||
|
|
||||||
var titanlabs = "Titan Laboratories";
|
var titanlabs = "Titan Laboratories";
|
||||||
var titanlabsStk = new Stock(titanlabs, StockSymbols[titanlabs], randInt(50, 70)/100, true, 11, randInt(12e3, 24e3));
|
var titanlabsStk = new Stock(titanlabs, StockSymbols[titanlabs], randInt(50, 70)/100, true, 11, randInt(12e3, 24e3), 420e9);
|
||||||
StockMarket[titanlabs] = titanlabsStk;
|
StockMarket[titanlabs] = titanlabsStk;
|
||||||
|
|
||||||
var orders = {};
|
var orders = {};
|
||||||
@ -411,6 +413,7 @@ function buyStock(stock, shares) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Does player have enough money?
|
||||||
var totalPrice = stock.price * shares;
|
var totalPrice = stock.price * shares;
|
||||||
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
|
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
|
||||||
dialogBoxCreate("You do not have enough money to purchase this. You need " +
|
dialogBoxCreate("You do not have enough money to purchase this. You need " +
|
||||||
@ -418,6 +421,13 @@ function buyStock(stock, shares) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Would this purchase exceed the maximum number of shares?
|
||||||
|
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
|
||||||
|
dialogBoxCreate(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ` +
|
||||||
|
`${numeralWrapper.formatBigNumber(stock.maxShares)} shares.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var origTotal = stock.playerShares * stock.playerAvgPx;
|
var origTotal = stock.playerShares * stock.playerAvgPx;
|
||||||
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
|
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
|
||||||
var newTotal = origTotal + totalPrice;
|
var newTotal = origTotal + totalPrice;
|
||||||
@ -470,6 +480,7 @@ function shortStock(stock, shares, workerScript=null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Does the player have enough money?
|
||||||
var totalPrice = stock.price * shares;
|
var totalPrice = stock.price * shares;
|
||||||
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
|
if (Player.money.lt(totalPrice + CONSTANTS.StockMarketCommission)) {
|
||||||
if (tixApi) {
|
if (tixApi) {
|
||||||
@ -484,6 +495,19 @@ function shortStock(stock, shares, workerScript=null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Would this purchase exceed the maximum number of shares?
|
||||||
|
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
|
||||||
|
if (tixApi) {
|
||||||
|
workerScript.scriptRef.log("ERROR: shortStock() failed because purchasing this many short shares would exceed " +
|
||||||
|
`${stock.symbol}'s maximum number of shares.`);
|
||||||
|
} else {
|
||||||
|
dialogBoxCreate(`You cannot purchase this many shares. ${stock.symbol} has a maximum of ` +
|
||||||
|
`${stock.maxShares} shares.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var origTotal = stock.playerShortShares * stock.playerAvgShortPx;
|
var origTotal = stock.playerShortShares * stock.playerAvgShortPx;
|
||||||
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
|
Player.loseMoney(totalPrice + CONSTANTS.StockMarketCommission);
|
||||||
var newTotal = origTotal + totalPrice;
|
var newTotal = origTotal + totalPrice;
|
||||||
@ -1190,6 +1214,7 @@ function createStockTicker(stock) {
|
|||||||
switch (ordType) {
|
switch (ordType) {
|
||||||
case "Market Order":
|
case "Market Order":
|
||||||
var shares = Math.floor((money - COMM) / stock.price);
|
var shares = Math.floor((money - COMM) / stock.price);
|
||||||
|
shares = Math.min(shares, Math.round(stock.maxShares - stock.playerShares - stock.playerShortShares));
|
||||||
pos === PositionTypes.Long ? buyStock(stock, shares) : shortStock(stock, shares, null);
|
pos === PositionTypes.Long ? buyStock(stock, shares) : shortStock(stock, shares, null);
|
||||||
break;
|
break;
|
||||||
case "Limit Order":
|
case "Limit Order":
|
||||||
@ -1206,6 +1231,7 @@ function createStockTicker(stock) {
|
|||||||
type = OrderTypes.StopBuy;
|
type = OrderTypes.StopBuy;
|
||||||
}
|
}
|
||||||
var shares = Math.floor((money-COMM) / price);
|
var shares = Math.floor((money-COMM) / price);
|
||||||
|
shares = Math.min(shares, Math.round(stock.maxShares - stock.playerShares - stock.playerShortShares));
|
||||||
placeOrder(stock, shares, price, type, pos);
|
placeOrder(stock, shares, price, type, pos);
|
||||||
yesNoTxtInpBoxClose();
|
yesNoTxtInpBoxClose();
|
||||||
});
|
});
|
||||||
@ -1384,25 +1410,26 @@ function updateStockPlayerPosition(stock) {
|
|||||||
if (isNaN(shortPercentageGains)) { shortPercentageGains = 0; }
|
if (isNaN(shortPercentageGains)) { shortPercentageGains = 0; }
|
||||||
|
|
||||||
stock.posTxtEl.innerHTML =
|
stock.posTxtEl.innerHTML =
|
||||||
"<h1 class='tooltip stock-market-position-text'>Long Position: " +
|
`Max Shares: ${numeralWrapper.format(stock.maxShares, "0.000a")}<br>` +
|
||||||
|
"<h3 class='tooltip stock-market-position-text'>Long Position: " +
|
||||||
"<span class='tooltiptext'>Shares in the long position will increase " +
|
"<span class='tooltiptext'>Shares in the long position will increase " +
|
||||||
"in value if the price of the corresponding stock increases</span></h1>" +
|
"in value if the price of the corresponding stock increases</span></h3>" +
|
||||||
"<br>Shares: " + numeralWrapper.format(stock.playerShares, '0,0') +
|
"<br>Shares: " + numeralWrapper.format(stock.playerShares, '0,0') +
|
||||||
"<br>Average Price: " + numeralWrapper.format(stock.playerAvgPx, '$0.000a') +
|
"<br>Average Price: " + numeralWrapper.format(stock.playerAvgPx, '$0.000a') +
|
||||||
" (Total Cost: " + numeralWrapper.format(totalCost, '$0.000a') + ")" +
|
" (Total Cost: " + numeralWrapper.format(totalCost, '$0.000a') + ")" +
|
||||||
"<br>Profit: " + numeralWrapper.format(gains, '$0.000a') +
|
"<br>Profit: " + numeralWrapper.format(gains, '$0.000a') +
|
||||||
" (" + numeralWrapper.format(percentageGains, '0.00%') + ")<br><br>";
|
" (" + numeralWrapper.format(percentageGains, '0.00%') + ")<br>";
|
||||||
if (Player.bitNodeN === 8 || (hasWallStreetSF && wallStreetSFLvl >= 2)) {
|
if (Player.bitNodeN === 8 || (hasWallStreetSF && wallStreetSFLvl >= 2)) {
|
||||||
stock.posTxtEl.innerHTML +=
|
stock.posTxtEl.innerHTML +=
|
||||||
"<h1 class='tooltip stock-market-position-text'>Short Position: " +
|
"<br><h3 class='tooltip stock-market-position-text'>Short Position: " +
|
||||||
"<span class='tooltiptext'>Shares in short position will increase " +
|
"<span class='tooltiptext'>Shares in short position will increase " +
|
||||||
"in value if the price of the corresponding stock decreases</span></h1>" +
|
"in value if the price of the corresponding stock decreases</span></h3>" +
|
||||||
"<br>Shares: " + numeralWrapper.format(stock.playerShortShares, '0,0') +
|
"<br>Shares: " + numeralWrapper.format(stock.playerShortShares, '0,0') +
|
||||||
"<br>Average Price: " + numeralWrapper.format(stock.playerAvgShortPx, '$0.000a') +
|
"<br>Average Price: " + numeralWrapper.formatMoney(stock.playerAvgShortPx) +
|
||||||
" (Total Cost: " + numeralWrapper.format(shortTotalCost, '$0.000a') + ")" +
|
" (Total Cost: " + numeralWrapper.formatMoney(shortTotalCost) + ")" +
|
||||||
"<br>Profit: " + numeralWrapper.format(shortGains, '$0.000a') +
|
"<br>Profit: " + numeralWrapper.formatMoney(shortGains) +
|
||||||
" (" + numeralWrapper.format(shortPercentageGains, '0.00%') + ")" +
|
" (" + numeralWrapper.format(shortPercentageGains, '0.00%') + ")" +
|
||||||
"<br><br><h1 class='stock-market-position-text'>Orders: </h1>";
|
"<br><br><h3 class='stock-market-position-text'>Orders:</h3>";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -30,7 +30,7 @@ import {findRunningScript, RunningScript,
|
|||||||
AllServersMap, isScriptFilename} from "./Script";
|
AllServersMap, isScriptFilename} from "./Script";
|
||||||
import {AllServers, GetServerByHostname,
|
import {AllServers, GetServerByHostname,
|
||||||
getServer, Server} from "./Server";
|
getServer, Server} from "./Server";
|
||||||
import {Settings} from "./Settings";
|
import {Settings} from "./Settings/Settings";
|
||||||
import {SpecialServerIps,
|
import {SpecialServerIps,
|
||||||
SpecialServerNames} from "./SpecialServerIps";
|
SpecialServerNames} from "./SpecialServerIps";
|
||||||
import {getTextFile} from "./TextFile";
|
import {getTextFile} from "./TextFile";
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user