mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
Fixed bugs with Sleeve mechanics. Updated documentation to use RTD theme
This commit is contained in:
parent
17bfbfeb80
commit
5573e778bb
@ -63,7 +63,7 @@
|
||||
z-index: 10;
|
||||
width: 50%;
|
||||
height: auto;
|
||||
max-height: 40%;
|
||||
max-height: 50%;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
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;
|
||||
}
|
||||
}
|
@ -6,4 +6,24 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
@ -46,18 +46,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#red-pill-container,
|
||||
#cinematic-text-container {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.bitnode {
|
||||
color: #00f;
|
||||
}
|
||||
.bitnode-destroyed {
|
||||
color: #f00;
|
||||
}
|
||||
.bitnode:hover,
|
||||
.bitnode-destroyed:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
4287
dist/engine.bundle.js
vendored
4287
dist/engine.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
76
dist/engine.css
vendored
76
dist/engine.css
vendored
@ -1222,6 +1222,24 @@ button {
|
||||
display: inline;
|
||||
width: 25%; }
|
||||
|
||||
/* 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 {
|
||||
@ -1318,20 +1336,9 @@ button {
|
||||
text-decoration: none;
|
||||
cursor: pointer; }
|
||||
|
||||
#red-pill-container,
|
||||
#cinematic-text-container {
|
||||
position: fixed; }
|
||||
|
||||
.bitnode {
|
||||
color: #00f; }
|
||||
|
||||
.bitnode-destroyed {
|
||||
color: #f00; }
|
||||
|
||||
.bitnode:hover,
|
||||
.bitnode-destroyed:hover {
|
||||
color: #fff; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/* Pop-up boxes */
|
||||
@ -1393,7 +1400,7 @@ button {
|
||||
z-index: 10;
|
||||
width: 50%;
|
||||
height: auto;
|
||||
max-height: 40%;
|
||||
max-height: 50%;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
margin: -10% 0 0 -25%;
|
||||
@ -2136,6 +2143,51 @@ button {
|
||||
margin: 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 */
|
||||
/* .Treant se automatski dodaje na svaki chart conatiner */
|
||||
.Treant {
|
||||
|
1164
dist/vendor.bundle.js
vendored
1164
dist/vendor.bundle.js
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
|
54
doc/source/advancedgameplay/sleeves.rst
Normal file
54
doc/source/advancedgameplay/sleeves.rst
Normal file
@ -0,0 +1,54 @@
|
||||
.. _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
|
||||
^^^^^^^^^^^
|
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
|
||||
=========
|
||||
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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
|
@ -110,7 +110,7 @@ List of Factions and their Requirements
|
||||
| | Clarke | * Have 200k reputation with | |
|
||||
| | Incorporated | the Corporation | |
|
||||
+ +----------------+-----------------------------------------+-------------------------------+
|
||||
| | Fulcrum Secret | * Have 200k reputation with | |
|
||||
| | Fulcrum Secret | * Have 250k reputation with | |
|
||||
| | Technologies | the Corporation | |
|
||||
| | | * Hack fulcrumassets manually | |
|
||||
+---------------------+----------------+-----------------------------------------+-------------------------------+
|
||||
|
@ -92,7 +92,8 @@ todo_include_todos = True
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'agogo'
|
||||
#html_theme = 'agogo'
|
||||
html_theme = "sphinx_rtd_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
|
||||
|
@ -21,6 +21,7 @@ secrets that you've been searching for.
|
||||
|
||||
Netscript <netscript>
|
||||
Basic Gameplay <basicgameplay>
|
||||
Advanced Gameplay <advancedgameplay>
|
||||
Keyboard Shortcuts <shortcuts>
|
||||
Game Frozen or Stuck? <gamefrozen>
|
||||
Changelog <changelog>
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _netscript_bladeburnerapi:
|
||||
|
||||
Netscript Bladeburner API
|
||||
=========================
|
||||
Netscript provides the following API for interacting with the game's Bladeburner mechanic.
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _netscript_tixapi:
|
||||
|
||||
Netscript Trade Information eXchange (TIX) API
|
||||
==============================================
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _netscript_singularityfunctions:
|
||||
|
||||
Netscript Singularity Functions
|
||||
===============================
|
||||
|
||||
|
@ -18,7 +18,7 @@ These shortcuts are almost always available. Exceptions include:
|
||||
========== ===========================================================================
|
||||
Shortcut Action
|
||||
========== ===========================================================================
|
||||
Alt + t Switch to :doc:`terminal`
|
||||
Alt + t Switch to :ref:`terminal`
|
||||
Alt + c Switch to 'Stats' page
|
||||
Alt + e Switch to Script Editor. Will open up the last-edited file or a new file
|
||||
Alt + s Switch to 'Active Scripts' page
|
||||
@ -40,7 +40,7 @@ These shortcuts are available only in the Script Editor
|
||||
============= ===========================================================================
|
||||
Shortcut Action
|
||||
============= ===========================================================================
|
||||
Ctrl + b Save script and return to :doc:`terminal`
|
||||
Ctrl + b Save script and return to :ref:`terminal`
|
||||
Ctrl + space Function autocompletion
|
||||
============= ===========================================================================
|
||||
|
||||
@ -52,7 +52,7 @@ In the Script Editor you can configure your key binding mode to three preset opt
|
||||
|
||||
Terminal Shortcuts
|
||||
------------------
|
||||
These shortcuts are available only in the :doc:`terminal`
|
||||
These shortcuts are available only in the :ref:`terminal`
|
||||
|
||||
============= ===========================================================================
|
||||
Shortcut Action
|
||||
@ -66,7 +66,7 @@ Tab Autocomplete command
|
||||
Terminal Bash Shortcuts
|
||||
-----------------------
|
||||
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
|
||||
|
||||
|
@ -65,6 +65,9 @@
|
||||
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel">
|
||||
<button id="hacknet-nodes-menu-link"> Hacknet Nodes </button>
|
||||
</li>
|
||||
<li id="sleeves-tab" class="mainmenu-accordion-panel">
|
||||
<button id="sleeves-menu-link"> Sleeves </button>
|
||||
</li>
|
||||
|
||||
<!-- World dropdown -->
|
||||
<li id="world-menu-header-li">
|
||||
|
@ -158,7 +158,7 @@ function initBitNodes() {
|
||||
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
||||
BitNodes["BitNode9"] = new BitNode(9, "Do Androids Dream?", "COMING SOON");
|
||||
BitNodes["BitNode10"] = new BitNode(10, "Digital Carbon", "Your body is not who you are",
|
||||
"In 2084, VitaLife unveiled to the world the Persona Core, an Augmentation that allowed people " +
|
||||
"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>" +
|
||||
@ -170,7 +170,8 @@ function initBitNodes() {
|
||||
"All methods of gaining money are half as profitable (except Stock Market)<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. Each level of this Source-File grants you a Duplicate Sleeve.");
|
||||
"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.",
|
||||
"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 " +
|
||||
|
@ -511,6 +511,8 @@ export let CONSTANTS: IMap<any> = {
|
||||
LatestUpdate:
|
||||
`
|
||||
v0.43.0
|
||||
* 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
|
||||
@ -518,7 +520,9 @@ export let CONSTANTS: IMap<any> = {
|
||||
* 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
|
||||
|
||||
* Home Computer RAM is now capped at 2 ^ 30 GB (1073741824 GB)
|
||||
* Pop-up dialog boxes are a little bit bigger
|
||||
`
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { Crimes } from "./Crimes";
|
||||
|
||||
import { Player } from "../Player";
|
||||
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
|
||||
export function determineCrimeSuccess(type, moneyGained) {
|
||||
|
@ -47,6 +47,7 @@ export interface IPlayer {
|
||||
crime_success_mult: number;
|
||||
|
||||
// Methods
|
||||
canAfford(cost: number): boolean;
|
||||
gainHackingExp(exp: number): void;
|
||||
gainStrengthExp(exp: number): void;
|
||||
gainDefenseExp(exp: number): void;
|
||||
@ -59,6 +60,7 @@ export interface IPlayer {
|
||||
inGang(): boolean;
|
||||
loseMoney(money: number): void;
|
||||
reapplyAllAugmentations(resetMultipliers: boolean): void;
|
||||
reapplyAllSourceFiles(): void;
|
||||
startCrime(crimeType: string,
|
||||
hackExp: number,
|
||||
strExp: number,
|
||||
|
@ -85,6 +85,17 @@ export abstract class Person {
|
||||
|
||||
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
|
||||
*/
|
||||
@ -101,7 +112,7 @@ export abstract class Person {
|
||||
/**
|
||||
* Updates this object's multipliers for the given augmentation
|
||||
*/
|
||||
applyAugmentation(aug: Augmentation, reapply=false) {
|
||||
applyAugmentation(aug: Augmentation) {
|
||||
for (const mult in aug.mults) {
|
||||
if ((<any>this)[mult] == null) {
|
||||
console.warn(`Augmentation has unrecognized multiplier property: ${mult}`);
|
||||
@ -188,11 +199,11 @@ export abstract class Person {
|
||||
*/
|
||||
updateStatLevels(): void {
|
||||
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.defense = Math.max(1, Math.floor(this.calculateStat(this.defense_exp, this.defense_mult)));
|
||||
this.dexterity = Math.max(1, Math.floor(this.calculateStat(this.dexterity_exp, this.dexterity_mult)));
|
||||
this.agility = Math.max(1, Math.floor(this.calculateStat(this.agility_exp, this.agility_mult)));
|
||||
this.charisma = Math.max(1, Math.floor(this.calculateStat(this.charisma_exp, this.charisma_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 * BitNodeMultipliers.DefenseLevelMultiplier)));
|
||||
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 * BitNodeMultipliers.AgilityLevelMultiplier)));
|
||||
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;
|
||||
this.max_hp = Math.floor(10 + this.defense / 10);
|
||||
|
@ -24,7 +24,7 @@ export class Resleeve extends Person {
|
||||
|
||||
getCost(): number {
|
||||
// Each experience point adds this to the cost
|
||||
const CostPerExp: number = 5;
|
||||
const CostPerExp: number = 4;
|
||||
|
||||
// Final cost is multiplied by # Augs ^ this constant
|
||||
const NumAugsExponent: number = 1.05;
|
||||
|
@ -23,7 +23,13 @@ import { getRandomInt } from "../../../utils/helpers/getRandomInt";
|
||||
|
||||
|
||||
// Executes the actual re-sleeve when one is purchased
|
||||
export function purchaseResleeve(r: Resleeve, p: IPlayer):void {
|
||||
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;
|
||||
@ -32,16 +38,25 @@ export function purchaseResleeve(r: Resleeve, p: IPlayer):void {
|
||||
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
|
||||
@ -55,6 +70,8 @@ export function purchaseResleeve(r: Resleeve, p: IPlayer):void {
|
||||
}
|
||||
|
||||
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
|
||||
@ -67,23 +84,33 @@ export function generateResleeves(): Resleeve[] {
|
||||
let r: Resleeve = new Resleeve();
|
||||
|
||||
// Generate experience
|
||||
const expMult: number = i + 1;
|
||||
r.hacking_exp = expMult * getRandomInt(500, 1500);
|
||||
r.strength_exp = expMult * getRandomInt(500, 1500);
|
||||
r.defense_exp = expMult * getRandomInt(500, 1500);
|
||||
r.dexterity_exp = expMult * getRandomInt(500, 1500);
|
||||
r.agility_exp = expMult * getRandomInt(500, 1500);
|
||||
r.charisma_exp = expMult * getRandomInt(500, 1500);
|
||||
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
|
||||
const baseNumAugs: number = Math.ceil((i + 1) / 2);
|
||||
// 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) {
|
||||
// We'll ignore Aug prerequisites for this
|
||||
const augKeys: string[] = Object.keys(Augmentations);
|
||||
const randKey: string = augKeys[getRandomInt(0, augKeys.length - 1)];
|
||||
// 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);
|
||||
|
@ -7,8 +7,6 @@ import { generateResleeves,
|
||||
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
import { IMap } from "../../types";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
|
||||
@ -23,9 +21,7 @@ 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";
|
||||
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
||||
|
||||
interface IResleeveUIElems {
|
||||
container: HTMLElement | null;
|
||||
@ -70,7 +66,19 @@ export function createResleevesPage(p: IPlayer) {
|
||||
|
||||
UIElems.info = createElement("p", {
|
||||
display: "inline-block",
|
||||
innerText: "TOODOOO",
|
||||
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 chance 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%",
|
||||
});
|
||||
|
||||
UIElems.resleeveList = createElement("ul");
|
||||
@ -96,7 +104,10 @@ export function createResleevesPage(p: IPlayer) {
|
||||
}
|
||||
|
||||
export function clearResleevesPage() {
|
||||
removeElement(UIElems.container);
|
||||
if (UIElems.container instanceof HTMLElement) {
|
||||
removeElement(UIElems.container);
|
||||
}
|
||||
|
||||
for (const prop in UIElems) {
|
||||
(<any>UIElems)[prop] = null;
|
||||
}
|
||||
@ -125,8 +136,17 @@ function createResleeveUi(resleeve: Resleeve): IResleeveUIElems {
|
||||
display: "block",
|
||||
});
|
||||
|
||||
elems.statsPanel = createElement("div", { class: "resleeve-panel" });
|
||||
elems.stats = createElement("p", { class: "resleeve-stats-text" });
|
||||
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)`,
|
||||
});
|
||||
elems.multipliersButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Multipliers",
|
||||
@ -155,33 +175,58 @@ function createResleeveUi(resleeve: Resleeve): IResleeveUIElems {
|
||||
`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" });
|
||||
elems.augSelector = createElement("select") as HTMLSelectElement;
|
||||
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.augDescription = createElement("p");
|
||||
elems.augSelector.dispatchEvent(new Event('change')); // Set inital description by manually triggering change event
|
||||
elems.augPanel.appendChild(elems.augSelector);
|
||||
elems.augPanel.appendChild(elems.augDescription);
|
||||
|
||||
elems.costPanel = createElement("div", { class: "resleeve-panel" });
|
||||
const cost: number = resleeve.getCost();
|
||||
elems.costPanel = createElement("div", { class: "resleeve-panel", width: "20%" });
|
||||
elems.costText = createElement("p", {
|
||||
innerText: `It costs ${numeralWrapper.formatMoney(resleeve.getCost())} ` +
|
||||
innerText: `It costs ${numeralWrapper.formatMoney(cost)} ` +
|
||||
`to purchase this Sleeve.`,
|
||||
});
|
||||
elems.buyButton = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Purchase",
|
||||
clickListener: () => {
|
||||
purchaseResleeve(resleeve, playerRef!);
|
||||
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;
|
||||
}
|
||||
|
@ -47,17 +47,13 @@ export class Sleeve extends Person {
|
||||
*/
|
||||
currentTask: SleeveTaskType = SleeveTaskType.Idle;
|
||||
|
||||
/**
|
||||
* Description of current task. Used only for logging purposes
|
||||
*/
|
||||
currentTaskDescription: string = "";
|
||||
|
||||
/**
|
||||
* Contains details about the sleeve's current task. The info stored
|
||||
* in this depends on the task type
|
||||
*
|
||||
* Faction/Company Work: Name of Faction/Company
|
||||
* Crime: Success rate of current crime, in decimal form
|
||||
* Crime: Money earned if successful
|
||||
* Class/Gym: Name of university/gym
|
||||
*/
|
||||
currentTaskLocation: string = "";
|
||||
|
||||
@ -135,7 +131,8 @@ export class Sleeve extends Person {
|
||||
/**
|
||||
* Commit crimes
|
||||
*/
|
||||
commitCrime(p: IPlayer, crime: Crime): void {
|
||||
commitCrime(p: IPlayer, crime: Crime): boolean {
|
||||
if (!(crime instanceof Crime)) { return false; }
|
||||
if (this.currentTask !== SleeveTaskType.Idle) {
|
||||
this.finishTask(p);
|
||||
} else {
|
||||
@ -150,6 +147,8 @@ export class Sleeve extends Person {
|
||||
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);
|
||||
|
||||
// We'll determine success now and adjust the earnings accordingly
|
||||
if (Math.random() < crime.successRate(p)) {
|
||||
this.gainRatesForTask.hack *= 2;
|
||||
@ -162,27 +161,35 @@ export class Sleeve extends Person {
|
||||
this.gainRatesForTask.money = 0;
|
||||
}
|
||||
|
||||
|
||||
this.currentTaskMaxTime = crime.time;
|
||||
this.currentTask = SleeveTaskType.Crime;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to stop the current task
|
||||
*/
|
||||
finishTask(p: IPlayer): void {
|
||||
finishTask(p: IPlayer): ITaskTracker {
|
||||
let retValue: ITaskTracker = createTaskTracker(); // Amount of exp to be gained by other sleeves
|
||||
|
||||
if (this.currentTask === SleeveTaskType.Crime) {
|
||||
// For crimes, all experience and money is gained at the end
|
||||
if (this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||
let retValue: ITaskTracker = createTaskTracker(); // Amount of exp to be gained by other sleeves
|
||||
|
||||
retValue = this.gainExperience(p, this.gainRatesForTask);
|
||||
this.gainMoney(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();
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -267,15 +274,17 @@ export class Sleeve extends Person {
|
||||
* Earn money for player
|
||||
*/
|
||||
gainMoney(p: IPlayer, task: ITaskTracker, numCycles: number=1): void {
|
||||
this.earningsForPlayer.money += (task.money * numCycles);
|
||||
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
|
||||
* Only applicable when working for company or faction
|
||||
*/
|
||||
getRepGain(): number {
|
||||
getRepGain(p: IPlayer): number {
|
||||
if (this.currentTask === SleeveTaskType.Faction) {
|
||||
switch (this.factionWorkType) {
|
||||
case FactionWorkType.Hacking:
|
||||
@ -289,7 +298,25 @@ export class Sleeve extends Person {
|
||||
return 0;
|
||||
}
|
||||
} else if (this.currentTask === SleeveTaskType.Company) {
|
||||
return 0; // TODO
|
||||
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 {
|
||||
console.warn(`Sleeve.getRepGain() called for invalid task type: ${this.currentTask}`);
|
||||
return 0;
|
||||
@ -315,14 +342,9 @@ export class Sleeve extends Person {
|
||||
this.storedCycles += numCycles;
|
||||
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 cyclesUsed = this.storedCycles;
|
||||
if (this.currentTaskTime + time > this.currentTaskMaxTime) {
|
||||
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime + time > this.currentTaskMaxTime) {
|
||||
time = this.currentTaskMaxTime - this.currentTaskTime;
|
||||
cyclesUsed = Math.floor(time / CONSTANTS.MilliPerCycle);
|
||||
|
||||
@ -334,9 +356,15 @@ export class Sleeve extends Person {
|
||||
}
|
||||
this.currentTaskTime += time;
|
||||
|
||||
// Shock gradually goes towards 100
|
||||
this.shock = Math.min(100, this.shock + (0.0001 * this.storedCycles));
|
||||
|
||||
let retValue: ITaskTracker = createTaskTracker();
|
||||
switch (this.currentTask) {
|
||||
case SleeveTaskType.Idle:
|
||||
break;
|
||||
case SleeveTaskType.Class:
|
||||
case SleeveTaskType.Gym:
|
||||
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||
this.gainMoney(p, this.gainRatesForTask, cyclesUsed);
|
||||
break;
|
||||
@ -351,7 +379,7 @@ export class Sleeve extends Person {
|
||||
break;
|
||||
}
|
||||
|
||||
fac.playerReputation += (this.getRepGain() * cyclesUsed);
|
||||
fac.playerReputation += (this.getRepGain(p) * cyclesUsed);
|
||||
break;
|
||||
case SleeveTaskType.Company:
|
||||
retValue = this.gainExperience(p, this.gainRatesForTask, cyclesUsed);
|
||||
@ -363,27 +391,31 @@ export class Sleeve extends Person {
|
||||
break;
|
||||
}
|
||||
|
||||
company.playerReputation *= (this.getRepGain() * cyclesUsed);
|
||||
company!.playerReputation += (this.getRepGain(p) * cyclesUsed);
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.currentTaskMaxTime !== 0 && this.currentTaskTime >= this.currentTaskMaxTime) {
|
||||
this.finishTask(p);
|
||||
if (this.currentTask === SleeveTaskType.Crime) {
|
||||
retValue = this.finishTask(p);
|
||||
} else {
|
||||
this.finishTask(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.updateStatLevels();
|
||||
|
||||
this.storedCycles -= cyclesUsed;
|
||||
|
||||
// TODO Finish this
|
||||
return retValue;
|
||||
}
|
||||
|
||||
@ -416,16 +448,19 @@ export class Sleeve extends Person {
|
||||
switch (universityName.toLowerCase()) {
|
||||
case Locations.AevumSummitUniversity.toLowerCase():
|
||||
if (this.city !== Cities.Aevum) { return false; }
|
||||
this.currentTaskLocation = Locations.AevumSummitUniversity;
|
||||
costMult = 4;
|
||||
expMult = 3;
|
||||
break;
|
||||
case Locations.Sector12RothmanUniversity.toLowerCase():
|
||||
if (this.city !== Cities.Sector12) { return false; }
|
||||
this.currentTaskLocation = Locations.Sector12RothmanUniversity;
|
||||
costMult = 3;
|
||||
expMult = 2;
|
||||
break;
|
||||
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
|
||||
if (this.city !== Cities.Volhaven) { return false; }
|
||||
this.currentTaskLocation = Locations.VolhavenZBInstituteOfTechnology;
|
||||
costMult = 5;
|
||||
expMult = 4;
|
||||
break;
|
||||
@ -433,9 +468,6 @@ export class Sleeve extends Person {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Number of game cycles in a second
|
||||
const cps: number = 1000 / CONSTANTS.MilliPerCycle;
|
||||
|
||||
// Set experience/money gains based on class
|
||||
// TODO Refactor University Courses into its own class or something
|
||||
const baseStudyComputerScienceExp: number = 0.5;
|
||||
@ -511,7 +543,10 @@ export class Sleeve extends Person {
|
||||
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 *
|
||||
@ -539,6 +574,7 @@ export class Sleeve extends Person {
|
||||
|
||||
this.currentTaskLocation = companyName;
|
||||
this.currentTask = SleeveTaskType.Company;
|
||||
this.currentTaskMaxTime = CONSTANTS.MillisecondsPer8Hours;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -585,6 +621,7 @@ export class Sleeve extends Person {
|
||||
|
||||
this.currentTaskLocation = factionName;
|
||||
this.currentTask = SleeveTaskType.Faction;
|
||||
this.currentTaskMaxTime = CONSTANTS.MillisecondsPer20Hours;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -606,26 +643,31 @@ export class Sleeve extends Person {
|
||||
switch (gymName.toLowerCase()) {
|
||||
case Locations.AevumCrushFitnessGym.toLowerCase():
|
||||
if (this.city != Cities.Aevum) { return false; }
|
||||
this.currentTaskLocation = Locations.AevumCrushFitnessGym;
|
||||
costMult = 3;
|
||||
expMult = 2;
|
||||
break;
|
||||
case Locations.AevumSnapFitnessGym.toLowerCase():
|
||||
if (this.city != Cities.Aevum) { return false; }
|
||||
this.currentTaskLocation = Locations.AevumSnapFitnessGym;
|
||||
costMult = 10;
|
||||
expMult = 5;
|
||||
break;
|
||||
case Locations.Sector12IronGym.toLowerCase():
|
||||
if (this.city != Cities.Sector12) { return false; }
|
||||
this.currentTaskLocation = Locations.Sector12IronGym;
|
||||
costMult = 1;
|
||||
expMult = 1;
|
||||
break;
|
||||
case Locations.Sector12PowerhouseGym.toLowerCase():
|
||||
if (this.city != Cities.Sector12) { return false; }
|
||||
this.currentTaskLocation = Locations.Sector12PowerhouseGym;
|
||||
costMult = 20;
|
||||
expMult = 10;
|
||||
break;
|
||||
case Locations.VolhavenMilleniumFitnessGym:
|
||||
if (this.city != Cities.Volhaven) { return false; }
|
||||
this.currentTaskLocation = Locations.VolhavenMilleniumFitnessGym;
|
||||
costMult = 7;
|
||||
expMult = 4;
|
||||
break;
|
||||
@ -633,9 +675,6 @@ export class Sleeve extends Person {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Number of game cycles in a second
|
||||
const cps = 1000 / CONSTANTS.MilliPerCycle;
|
||||
|
||||
// Set experience/money gains based on class
|
||||
// TODO Refactor University Courses into its own class or something
|
||||
const baseGymExp: number = 1;
|
||||
@ -657,7 +696,7 @@ export class Sleeve extends Person {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.currentTask = SleeveTaskType.Class;
|
||||
this.currentTask = SleeveTaskType.Gym;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2,11 +2,13 @@
|
||||
* Enum for different types of tasks that a Sleeve can perform
|
||||
*/
|
||||
export enum SleeveTaskType {
|
||||
Class,
|
||||
Company,
|
||||
Crime,
|
||||
Faction,
|
||||
// Same Order as selectable order in UI
|
||||
Idle,
|
||||
Company,
|
||||
Faction,
|
||||
Crime,
|
||||
Class,
|
||||
Gym,
|
||||
Recovery,
|
||||
Sync,
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
*/
|
||||
import { Sleeve } from "./Sleeve";
|
||||
import { SleeveTaskType } from "./SleeveTaskTypesEnum";
|
||||
import { SleeveFaq } from "./data/SleeveFaq";
|
||||
|
||||
import { IPlayer } from "../IPlayer";
|
||||
|
||||
@ -11,14 +12,13 @@ import { Locations } from "../../Locations";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
import { Crimes } from "../../Crime/Crimes";
|
||||
|
||||
import { IMap } from "../../types";
|
||||
|
||||
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 { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
@ -26,35 +26,39 @@ import { createOptionElement } from "../../../utils/uiHelpers/createOptionElemen
|
||||
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,
|
||||
taskPanel: HTMLElement | null,
|
||||
taskSelector: HTMLSelectElement | null,
|
||||
taskDetailsSelector: HTMLSelectElement | null,
|
||||
taskDetailsSelector2: HTMLSelectElement | null,
|
||||
taskDescription: HTMLElement | null,
|
||||
taskSetButton: HTMLElement | null,
|
||||
earningsPanel: HTMLElement | null,
|
||||
currentEarningsInfo: HTMLElement | null,
|
||||
totalEarningsButton: HTMLElement | null,
|
||||
container: HTMLElement | null;
|
||||
statsPanel: HTMLElement | null;
|
||||
stats: HTMLElement | null;
|
||||
moreStatsButton: 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;
|
||||
info: HTMLElement | null,
|
||||
sleeveList: HTMLElement | null,
|
||||
sleeves: ISleeveUIElems[] | 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,
|
||||
@ -75,11 +79,26 @@ export function createSleevesPage(p: IPlayer) {
|
||||
});
|
||||
|
||||
UIElems.info = createElement("p", {
|
||||
display: "inline-block",
|
||||
innerText: "Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your " +
|
||||
"consciousness has copied. In other words, these Synthoids contain " +
|
||||
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.",
|
||||
"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");
|
||||
@ -93,6 +112,7 @@ export function createSleevesPage(p: IPlayer) {
|
||||
}
|
||||
|
||||
UIElems.container.appendChild(UIElems.info);
|
||||
UIElems.container.appendChild(UIElems.faqButton);
|
||||
UIElems.container.appendChild(UIElems.sleeveList);
|
||||
|
||||
document.getElementById("entire-game-container")!.appendChild(UIElems.container);
|
||||
@ -104,10 +124,23 @@ export function createSleevesPage(p: IPlayer) {
|
||||
// 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() {
|
||||
removeElement(UIElems.container);
|
||||
if (UIElems.container instanceof HTMLElement) {
|
||||
removeElement(UIElems.container);
|
||||
}
|
||||
|
||||
for (const prop in UIElems) {
|
||||
(<any>UIElems)[prop] = null;
|
||||
}
|
||||
@ -129,6 +162,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
taskDetailsSelector2: null,
|
||||
taskDescription: null,
|
||||
taskSetButton: null,
|
||||
taskProgressBar: null,
|
||||
earningsPanel: null,
|
||||
currentEarningsInfo: null,
|
||||
totalEarningsButton: null,
|
||||
@ -141,7 +175,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
display: "block",
|
||||
});
|
||||
|
||||
elems.statsPanel = createElement("div", { class: "sleeve-panel" });
|
||||
elems.statsPanel = createElement("div", { class: "sleeve-panel", width: "25%" });
|
||||
elems.stats = createElement("p", { class: "sleeve-stats-text" });
|
||||
elems.moreStatsButton = createElement("button", {
|
||||
class: "std-button",
|
||||
@ -181,7 +215,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
elems.statsPanel.appendChild(elems.stats);
|
||||
elems.statsPanel.appendChild(elems.moreStatsButton);
|
||||
|
||||
elems.taskPanel = createElement("div", { class: "sleeve-panel" });
|
||||
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"));
|
||||
@ -194,10 +228,13 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
elems.taskSelector.addEventListener("change", () => {
|
||||
updateSleeveTaskSelector(sleeve, elems, allSleeves);
|
||||
});
|
||||
// TODO Set initial value for task selector
|
||||
elems.taskDetailsSelector = createElement("select") as HTMLSelectElement;
|
||||
elems.taskDetailsSelector2 = createElement("select") as HTMLSelectElement;
|
||||
elems.taskDescription = createElement("p");
|
||||
elems.taskProgressBar = createElement("p");
|
||||
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",
|
||||
@ -207,10 +244,12 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
});
|
||||
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" });
|
||||
elems.earningsPanel = createElement("div", { class: "sleeve-panel", width: "35%" });
|
||||
elems.currentEarningsInfo = createElement("p");
|
||||
elems.totalEarningsButton = createElement("button", {
|
||||
class: "std-button",
|
||||
@ -218,23 +257,23 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
clickListener: () => {
|
||||
dialogBoxCreate(
|
||||
[
|
||||
"<h2><u>Total Earnings for Current Task:</u></h2>",
|
||||
"<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)}`,
|
||||
"<h2><u>Earnings for Host Consciousness:</u></h2>",
|
||||
`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)}`,
|
||||
"<h2><u>Earnings for Other Sleeves:</u></h2>",
|
||||
`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)}`,
|
||||
@ -247,6 +286,15 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -261,12 +309,19 @@ function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
|
||||
`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")}<br>`,
|
||||
`Shock: ${numeralWrapper.format(100 - sleeve.shock, "0,0")}`,
|
||||
`Synchronization: ${numeralWrapper.format(sleeve.sync, "0,0")}`].join("<br>");
|
||||
`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 = [
|
||||
`Money: ${numeralWrapper.formatMoney(sleeve.gainRatesForTask.money)} if successful`,
|
||||
`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)`,
|
||||
@ -274,16 +329,26 @@ function updateSleeveUi(sleeve: Sleeve, elems: ISleeveUIElems) {
|
||||
`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 {
|
||||
elems.currentEarningsInfo!.innerHTML = [
|
||||
`Money: ${numeralWrapper.formatMoney(sleeve.gainRatesForTask.money)} / s`,
|
||||
`Hacking Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.hack, "0.00")} / s`,
|
||||
`Strength Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.str, "0.00")} / s`,
|
||||
`Defense Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.def, "0.00")} / s`,
|
||||
`Dexterity Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.dex, "0.00")} / s`,
|
||||
`Agility Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.agi, "0.00")} / s`,
|
||||
`Charisma Exp: ${numeralWrapper.format(sleeve.gainRatesForTask.cha, "0.00")} / s`
|
||||
].join("<br>");
|
||||
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 = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,7 +398,9 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
}
|
||||
}
|
||||
|
||||
// Reset Selectors
|
||||
removeChildrenFromElement(elems.taskDetailsSelector);
|
||||
removeChildrenFromElement(elems.taskDetailsSelector2);
|
||||
|
||||
const value: string = getSelectValue(elems.taskSelector);
|
||||
switch(value) {
|
||||
@ -342,7 +409,14 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
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 = i;
|
||||
}
|
||||
}
|
||||
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||
}
|
||||
break;
|
||||
case "Work for Faction":
|
||||
@ -350,6 +424,11 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
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 = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < factionWorkTypeSelectorOptions.length; ++i) {
|
||||
@ -361,6 +440,8 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
const name: string = Crimes[crimeLabel].name;
|
||||
elems.taskDetailsSelector!.add(createOptionElement(name, crimeLabel));
|
||||
}
|
||||
|
||||
elems.taskDetailsSelector2!.add(createOptionElement("------"));
|
||||
break;
|
||||
case "Take University Course":
|
||||
// First selector has class type
|
||||
@ -410,17 +491,18 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
|
||||
|
||||
break;
|
||||
case "Shock Recovery":
|
||||
// No options in "Details" selector
|
||||
return;
|
||||
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): void {
|
||||
function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): boolean {
|
||||
try {
|
||||
if (playerRef == null) {
|
||||
throw new Error("playerRef is null in Sleeve UI's setSleeveTask()");
|
||||
@ -428,32 +510,21 @@ function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): void {
|
||||
|
||||
const taskValue: string = getSelectValue(elems.taskSelector);
|
||||
const detailValue: string = getSelectValue(elems.taskDetailsSelector);
|
||||
const detailValue2: 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);
|
||||
if (res) {
|
||||
elems.taskDescription!.innerText = `This sleeve is currently working your ` +
|
||||
`job at ${sleeve.currentTaskLocation}.`;
|
||||
} else {
|
||||
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
|
||||
}
|
||||
break;
|
||||
case "Work for Faction":
|
||||
res = sleeve.workForFaction(playerRef!, detailValue, detailValue2);
|
||||
if (res) {
|
||||
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ` +
|
||||
`${sleeve.currentTaskLocation}.`;
|
||||
} else {
|
||||
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
|
||||
}
|
||||
break;
|
||||
case "Commit Crime":
|
||||
sleeve.commitCrime(playerRef!, Crimes[detailValue]);
|
||||
elems.taskDescription!.innerText = `This sleeve is currently attempting to ` +
|
||||
`${Crimes[detailValue]}.`;
|
||||
res = sleeve.commitCrime(playerRef!, Crimes[detailValue]);
|
||||
break;
|
||||
case "Take University Course":
|
||||
res = sleeve.takeUniversityCourse(playerRef!, detailValue2, detailValue);
|
||||
@ -463,22 +534,79 @@ function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): void {
|
||||
break;
|
||||
case "Shock Recovery":
|
||||
sleeve.currentTask = SleeveTaskType.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.";
|
||||
res = true;
|
||||
break;
|
||||
case "Synchronize":
|
||||
sleeve.currentTask = SleeveTaskType.Sync;
|
||||
elems.taskDescription!.innerText = "This sleeve is currently set to synchronize with the original consciousness. " +
|
||||
"This causes the Sleeve's synchronization to increase."
|
||||
res = true;
|
||||
break;
|
||||
default:
|
||||
console.error(`Invalid/Unrecognized taskValue in setSleeveTask(): ${taskValue}`);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
updateSleeveTaskDescription(sleeve, elems);
|
||||
} else {
|
||||
elems.taskDescription!.innerText = "Failed to assign sleeve to task. Invalid choice(s).";
|
||||
}
|
||||
|
||||
if (routing.isOn(Page.Sleeves)) {
|
||||
updateSleevesPage();
|
||||
}
|
||||
|
||||
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}.`;
|
||||
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(" ");
|
@ -548,6 +548,14 @@ PlayerObject.prototype.loseMoney = function(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) {
|
||||
if (isNaN(exp)) {
|
||||
console.log("ERR: NaN passed into Player.gainHackingExp()"); return;
|
||||
|
@ -63,7 +63,8 @@ function initSourceFiles() {
|
||||
"This Source-File also increases your hacking growth multipliers by: " +
|
||||
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
|
||||
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 " +
|
||||
"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>" +
|
||||
@ -187,6 +188,9 @@ function applySourceFile(srcFile) {
|
||||
var incMult = 1 + (mult / 100);
|
||||
Player.hacking_grow_mult *= incMult;
|
||||
break;
|
||||
case 10: // Digital Carbon
|
||||
// No effects, just grants sleeves
|
||||
break;
|
||||
case 11: //The Big Crash
|
||||
var mult = 0;
|
||||
for (var i = 0; i < srcFile.lvl; ++i) {
|
||||
|
@ -230,35 +230,35 @@ function initStockMarket() {
|
||||
const randInt = getRandomInt;
|
||||
|
||||
var ecorp = Locations.AevumECorp;
|
||||
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], randInt(40, 50) / 100, true, 19, randInt(17e3, 28e3), 3e12);
|
||||
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], randInt(40, 50) / 100, true, 19, randInt(17e3, 28e3), 2.4e12);
|
||||
StockMarket[ecorp] = ecorpStk;
|
||||
|
||||
var megacorp = Locations.Sector12MegaCorp;
|
||||
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], randInt(40,50)/100, true, 19, randInt(24e3, 34e3), 3e12);
|
||||
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], randInt(40,50)/100, true, 19, randInt(24e3, 34e3), 2.4e12);
|
||||
StockMarket[megacorp] = megacorpStk;
|
||||
|
||||
var blade = Locations.Sector12BladeIndustries;
|
||||
var bladeStk = new Stock(blade, StockSymbols[blade], randInt(70, 80)/100, true, 13, randInt(12e3, 25e3), 1.9e12);
|
||||
var bladeStk = new Stock(blade, StockSymbols[blade], randInt(70, 80)/100, true, 13, randInt(12e3, 25e3), 1.6e12);
|
||||
StockMarket[blade] = bladeStk;
|
||||
|
||||
var clarke = Locations.AevumClarkeIncorporated;
|
||||
var clarkeStk = new Stock(clarke, StockSymbols[clarke], randInt(65, 75)/100, true, 12, randInt(10e3, 25e3), 1.8e12);
|
||||
var clarkeStk = new Stock(clarke, StockSymbols[clarke], randInt(65, 75)/100, true, 12, randInt(10e3, 25e3), 1.5e12);
|
||||
StockMarket[clarke] = clarkeStk;
|
||||
|
||||
var omnitek = Locations.VolhavenOmniTekIncorporated;
|
||||
var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], randInt(60, 70)/100, true, 12, randInt(32e3, 43e3), 2.1e12);
|
||||
var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], randInt(60, 70)/100, true, 12, randInt(32e3, 43e3), 1.8e12);
|
||||
StockMarket[omnitek] = omnitekStk;
|
||||
|
||||
var foursigma = Locations.Sector12FourSigma;
|
||||
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], randInt(100, 110)/100, true, 17, randInt(50e3, 80e3), 2.4e12);
|
||||
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], randInt(100, 110)/100, true, 17, randInt(50e3, 80e3), 2e12);
|
||||
StockMarket[foursigma] = foursigmaStk;
|
||||
|
||||
var kuaigong = Locations.ChongqingKuaiGongInternational;
|
||||
var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], randInt(75, 85)/100, true, 10, randInt(16e3, 28e3), 2.3e12);
|
||||
var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], randInt(75, 85)/100, true, 10, randInt(16e3, 28e3), 1.9e12);
|
||||
StockMarket[kuaigong] = kuaigongStk;
|
||||
|
||||
var fulcrum = Locations.AevumFulcrumTechnologies;
|
||||
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3), 2.4e12);
|
||||
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3), 2e12);
|
||||
StockMarket[fulcrum] = fulcrumStk;
|
||||
|
||||
var storm = Locations.IshimaStormTechnologies;
|
||||
|
@ -66,6 +66,10 @@ import {StockMarket, StockSymbols,
|
||||
displayStockMarketContent} from "./StockMarket/StockMarket";
|
||||
import {Terminal, postNetburnerText} from "./Terminal";
|
||||
|
||||
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
||||
import { clearSleevesPage,
|
||||
createSleevesPage,
|
||||
updateSleevesPage } from "./PersonObjects/Sleeve/SleeveUI";
|
||||
import { clearResleevesPage,
|
||||
createResleevesPage } from "./PersonObjects/Resleeving/ResleevingUI";
|
||||
|
||||
@ -111,6 +115,8 @@ import "../css/missions.scss";
|
||||
import "../css/companymanagement.scss";
|
||||
import "../css/bladeburner.scss";
|
||||
import "../css/gang.scss";
|
||||
import "../css/sleeves.scss";
|
||||
import "../css/resleeving.scss";
|
||||
import "../css/treant.css";
|
||||
|
||||
|
||||
@ -472,6 +478,13 @@ const Engine = {
|
||||
|
||||
loadSleevesContent: function() {
|
||||
// This is for Duplicate Sleeves page, not Re-sleeving @ Vita Life
|
||||
try {
|
||||
Engine.hideAllContent();
|
||||
routing.navigateTo(Page.Sleeves);
|
||||
createSleevesPage(Player);
|
||||
} catch(e) {
|
||||
exceptionAlert(e);
|
||||
}
|
||||
},
|
||||
|
||||
loadResleevingContent: function() {
|
||||
@ -520,6 +533,9 @@ const Engine = {
|
||||
Player.bladeburner.clearContent();
|
||||
}
|
||||
|
||||
clearResleevesPage();
|
||||
clearSleevesPage();
|
||||
|
||||
//Location lists
|
||||
Engine.aevumLocationsList.style.display = "none";
|
||||
Engine.chongqingLocationsList.style.display = "none";
|
||||
@ -944,6 +960,20 @@ const Engine = {
|
||||
Player.bladeburner.storeCycles(numCycles);
|
||||
}
|
||||
|
||||
// Sleeves
|
||||
for (let i = 0; i < Player.sleeves.length; ++i) {
|
||||
if (Player.sleeves[i] instanceof Sleeve) {
|
||||
const expForOtherSleeves = Player.sleeves[i].process(Player, numCycles);
|
||||
|
||||
// This sleeve earns experience for other sleeves
|
||||
if (expForOtherSleeves == null) { continue; }
|
||||
for (let j = 0; j < Player.sleeves.length; ++j) {
|
||||
if (j === i) { continue; }
|
||||
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCycles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Counters
|
||||
Engine.decrementAllCounters(numCycles);
|
||||
Engine.checkCounters();
|
||||
@ -1024,6 +1054,8 @@ const Engine = {
|
||||
updateHacknetNodesContent();
|
||||
} else if (routing.isOn(Page.CreateProgram)) {
|
||||
displayCreateProgramContent();
|
||||
} else if (routing.isOn(Page.Sleeves)) {
|
||||
updateSleevesPage();
|
||||
}
|
||||
|
||||
if (logBoxOpened) {
|
||||
@ -1295,6 +1327,20 @@ const Engine = {
|
||||
Player.bladeburner.storeCycles(numCyclesOffline);
|
||||
}
|
||||
|
||||
// Sleeves offline progress
|
||||
for (let i = 0; i < Player.sleeves.length; ++i) {
|
||||
if (Player.sleeves[i] instanceof Sleeve) {
|
||||
const expForOtherSleeves = Player.sleeves[i].process(Player, numCyclesOffline);
|
||||
|
||||
// This sleeve earns experience for other sleeves
|
||||
if (expForOtherSleeves == null) { continue; }
|
||||
for (let j = 0; j < Player.sleeves.length; ++j) {
|
||||
if (j === i) { continue; }
|
||||
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCyclesOffline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Update total playtime
|
||||
var time = numCyclesOffline * Engine._idleSpeed;
|
||||
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
|
||||
@ -1582,6 +1628,11 @@ const Engine = {
|
||||
return false;
|
||||
});
|
||||
|
||||
MainMenuLinks.Sleeves.addEventListener("click", function() {
|
||||
Engine.loadSleevesContent();
|
||||
return false;
|
||||
});
|
||||
|
||||
MainMenuLinks.City.addEventListener("click", function() {
|
||||
Engine.loadWorldContent();
|
||||
return false;
|
||||
|
@ -67,6 +67,9 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
|
||||
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel">
|
||||
<button id="hacknet-nodes-menu-link"> Hacknet Nodes </button>
|
||||
</li>
|
||||
<li id="sleeves-tab" class="mainmenu-accordion-panel">
|
||||
<button id="sleeves-menu-link"> Sleeves </button>
|
||||
</li>
|
||||
|
||||
<!-- World dropdown -->
|
||||
<li id="world-menu-header-li">
|
||||
|
@ -84,11 +84,14 @@ export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boole
|
||||
const factions: HTMLElement = safeGetElement("factions-tab");
|
||||
const augmentations: HTMLElement = safeGetElement("augmentations-tab");
|
||||
const hacknetnodes: HTMLElement = safeGetElement("hacknet-nodes-tab");
|
||||
const sleeves: HTMLElement = safeGetElement("sleeves-tab");
|
||||
|
||||
sleeves.style.display = p.sleeves.length > 0 ? "list-item" : "none";
|
||||
|
||||
this.classList.toggle("opened");
|
||||
|
||||
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes];
|
||||
const links: HTMLElement[] = [MainMenuLinks.Stats!, MainMenuLinks.Factions!, MainMenuLinks.Augmentations!, MainMenuLinks.HacknetNodes!];
|
||||
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes, sleeves];
|
||||
const links: HTMLElement[] = [MainMenuLinks.Stats!, MainMenuLinks.Factions!, MainMenuLinks.Augmentations!, MainMenuLinks.HacknetNodes!, MainMenuLinks.Sleeves!];
|
||||
if (stats.style.maxHeight) {
|
||||
toggleHeader(false, elems, links);
|
||||
} else {
|
||||
|
@ -11,6 +11,7 @@ interface IMainMenuLinks {
|
||||
Factions: HTMLElement | null;
|
||||
Augmentations: HTMLElement | null;
|
||||
HacknetNodes: HTMLElement | null;
|
||||
Sleeves: HTMLElement | null;
|
||||
City: HTMLElement | null;
|
||||
Travel: HTMLElement | null;
|
||||
Job: HTMLElement | null;
|
||||
@ -32,6 +33,7 @@ export const MainMenuLinks: IMainMenuLinks = {
|
||||
Factions: null,
|
||||
Augmentations: null,
|
||||
HacknetNodes: null,
|
||||
Sleeves: null,
|
||||
City: null,
|
||||
Travel: null,
|
||||
Job: null,
|
||||
@ -63,6 +65,7 @@ export function initializeMainMenuLinks(): boolean {
|
||||
MainMenuLinks.Factions = safeGetLink("factions-menu-link");
|
||||
MainMenuLinks.Augmentations = safeGetLink("augmentations-menu-link");
|
||||
MainMenuLinks.HacknetNodes = safeGetLink("hacknet-nodes-menu-link");
|
||||
MainMenuLinks.Sleeves = safeGetLink("sleeves-menu-link");
|
||||
MainMenuLinks.City = safeGetLink("city-menu-link");
|
||||
MainMenuLinks.Travel = safeGetLink("travel-menu-link");
|
||||
MainMenuLinks.Job = safeGetLink("job-menu-link");
|
||||
|
@ -1,9 +1,11 @@
|
||||
export function getSelectValue(selector: HTMLSelectElement | null): string {
|
||||
if (selector == null) { return ""; }
|
||||
return selector[selector.selectedIndex].value;
|
||||
if (selector.options.length <= 0) { return ""; }
|
||||
return selector.options[selector.selectedIndex].value;
|
||||
}
|
||||
|
||||
export function getSelectText(selector: HTMLSelectElement | null): string {
|
||||
if (selector == null) { return ""; }
|
||||
return selector[selector.selectedIndex].text;
|
||||
if (selector.options.length <= 0) { return ""; }
|
||||
return selector.options[selector.selectedIndex].text;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user