Merge pull request #594 from danielyxie/dev

v0.46.1
This commit is contained in:
danielyxie
2019-04-12 16:53:19 -07:00
committed by GitHub
96 changed files with 7497 additions and 6985 deletions

View File

@ -68,13 +68,14 @@
@include boxShadow($boxShadowArgs);
background-color: #555;
border: 2px solid var(--my-highlight-color);
color: #fff;
display: inline-block;
float: center;
resize: none;
color: #fff;
margin: 4px;
padding: 2px;
border: 2px solid var(--my-highlight-color);
resize: none;
width: 50%;
}
#script-editor-status {

File diff suppressed because one or more lines are too long

7
dist/engine.css vendored
View File

@ -886,13 +886,14 @@ button {
-moz-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
background-color: #555;
border: 2px solid var(--my-highlight-color);
color: #fff;
display: inline-block;
float: center;
resize: none;
color: #fff;
margin: 4px;
padding: 2px;
border: 2px solid var(--my-highlight-color); }
resize: none;
width: 50%; }
#script-editor-status {
float: left;

130
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@ -16,6 +16,85 @@ the terminal and enter::
nano .fconf
.. _terminal_filesystem:
Filesystem (Directories)
------------------------
The Terminal contains a **very** basic filesystem that allows you to store and
organize your files into different directories. Note that this is **not** a true
filesystem implementation. Instead, it is done almost entirely using string manipulation.
For this reason, many of the nice & useful features you'd find in a real
filesystem do not exist.
Here are the Terminal commands you'll commonly use when dealing with the filesystem.
* :ref:`ls_terminal_command`
* :ref:`cd_terminal_command`
* :ref:`mv_terminal_command`
Directories
^^^^^^^^^^^
In order to create a directory, simply name a file using a full absolute Linux-style path::
/scripts/myScript.js
This will automatically create a "directory" called :code:`scripts`. This will also work
for subdirectories::
/scripts/hacking/helpers/myHelperScripts.script
Files in the root directory do not need to begin with a forward slash::
thisIsAFileInTheRootDirectory.txt
Note that there is no way to manually create or remove directories. The creation and
deletion of directories is automatically handled as you name/rename/delete
files.
Absolute vs Relative Paths
^^^^^^^^^^^^^^^^^^^^^^^^^^
Many Terminal commands accept absolute both absolute and relative paths for specifying a
file.
An absolute path specifies the location of the file from the root directory (/).
Any path that begins with the forward slash is an absolute path::
$ nano /scripts/myScript.js
$ cat /serverList.txt
A relative path specifies the location of the file relative to the current working directory.
Any path that does **not** begin with a forward slash is a relative path. Note that the
Linux-style dot symbols will work for relative paths::
. (a single dot) - represents the current directory
.. (two dots) - represents the parent directory
$ cd ..
$ nano ../scripts/myScript.js
$ nano ../../helper.js
Netscript
^^^^^^^^^
Note that in order to reference a file, :ref:`netscript` functions require the
**full** absolute file path. For example
.. code:: javascript
run("/scripts/hacking/helpers.myHelperScripts.script");
rm("/logs/myHackingLogs.txt");
rm("thisIsAFileInTheRootDirectory.txt");
.. note:: A full file path **must** begin with a forward slash (/) if that file
is not in the root directory.
Missing Features
^^^^^^^^^^^^^^^^
These features that are typically in Linux filesystems have not yet been added to the game:
* Tab autocompletion does not work with relative paths
* :code:`mv` only accepts full filepaths for the destination argument. It does not accept directories
Commands
--------
@ -98,6 +177,25 @@ Display a message (.msg), literature (.lit), or text (.txt) file::
$ cat foo.lit
$ cat servers.txt
.. _cd_terminal_command:
cd
^^
$ cd [dir]
Change to the specified directory.
See :ref:`terminal_filesystem` for details on directories.
Note that this command works even for directories that don't exist. If you change
to a directory that doesn't exist, it will not be created. A directory is only created
once there is a file in it::
$ cd scripts/hacking
$ cd /logs
$ cd ..
check
^^^^^
@ -234,27 +332,35 @@ killall
Kills all scripts on the current server.
.. _ls_terminal_command:
ls
^^
$ ls [| grep pattern]
$ ls [dir] [| grep pattern]
Prints files on the current server to the Terminal screen.
Prints files and directories on the current server to the Terminal screen.
If this command is run with no arguments, then it prints all files on the current
server to the Terminal screen. The files will be displayed in alphabetical
order.
If this command is run with no arguments, then it prints all files and directories on the current
server to the Terminal screen. Directories will be printed first in alphabetical order,
followed by the files (also in alphabetical order).
The '| grep pattern' is an optional parameter that can be used to only display files
whose filenames match the specified pattern. For example, if you wanted to only display
files with the .script extension, you could use::
The :code:`dir` optional parameter allows you to specify the directory for which to display
files.
The :code:`| grep pattern` optional parameter allows you to only display files and directories
with a certain pattern in their names.
Examples::
// List files/directories with the '.script' extension in the current directory
$ ls | grep .script
Alternatively, if you wanted to display all files with the word *purchase* in the filename,
you could use::
// List files/directories with the '.js' extension in the root directory
$ ls / | grep .js
$ ls | grep purchase
// List files/directories with the word 'purchase' in the name, in the :code:`scripts` directory
$ ls scripts | grep purchase
lscpu
@ -282,6 +388,28 @@ The first example above will print the amount of RAM needed to run 'foo.script'
with a single thread. The second example above will print the amount of RAM needed
to run 'foo.script' with 50 threads.
.. _mv_terminal_command:
mv
^^
$ mv [source] [destination]
Move the source file to the specified destination in the filesystem.
See :ref:`terminal_filesystem` for more details about the Terminal's filesystem.
This command only works for scripts and text files (.txt). It cannot, however, be used
to convert from script to text file, or vice versa.
This function can also be used to rename files.
.. note:: Unlike the Linux :code:`mv` command, the *destination* argument must be the
full filepath. It cannot be a directory.
Examples::
$ mv hacking.script scripts/hacking.script
$ mv myScript.js myOldScript.js
nano
^^^^

View File

@ -3,6 +3,19 @@
Changelog
=========
v0.46.1 - 4/12/2019
-------------------
* Added a very rudimentary directory system to the Terminal
* Details here: https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#filesystem-directories
* Added numHashes(), hashCost(), and spendHashes() functions to the Netscript Hacknet Node API
* 'Generate Coding Contract' hash upgrade is now more expensive
* 'Generate Coding Contract' hash upgrade now generates the contract randomly on the server, rather than on home computer
* The cost of selling hashes for money no longer increases each time
* Selling hashes for money now costs 4 hashes (in exchange for $1m)
* Bug Fix: Hacknet Node earnings should work properly when game is inactive/offline
* Bug Fix: Duplicate Sleeve augmentations are now properly reset when switching to a new BitNode
v0.46.0 - 4/3/2019
------------------
* Added BitNode-9: Hacktocracy

View File

@ -1,5 +1,5 @@
getScriptRam() Netscript Function
===========================
=================================
.. js:function:: getScriptRam(scriptname[, hostname/ip])

View File

@ -0,0 +1,23 @@
hashCost() Netscript Function
=============================
.. warning:: This page contains spoilers for the game
.. js:function:: hashCost(upgName, upgTarget)
:param string upgName: Name of upgrade to get the cost of. Must be an exact match
.. note:: This function is only applicable for Hacknet Servers (the upgraded version
of a Hacknet Node).
Returns the number of hashes required for the specified upgrade. The name of the
upgrade must be an exact match.
Example:
.. code:: javascript
var upgradeName = "Sell for Corporation Funds";
if (hacknet.numHashes() > hacknet.hashCost(upgradeName)) {
hacknet.spendHashes(upgName);
}

View File

@ -0,0 +1,11 @@
numHashes() Netscript Function
==============================
.. warning:: This page contains spoilers for the game
.. js:function:: numHashes()
.. note:: This function is only applicable for Hacknet Servers (the upgraded version
of a Hacknet Node).
Returns the number of hashes you have

View File

@ -0,0 +1,26 @@
spendHashes() Netscript Function
================================
.. warning:: This page contains spoilers for the game
.. js:function:: spendHashes(upgName, upgTarget)
:param string upgName: Name of upgrade to spend hashes on. Must be an exact match
:param string upgTarget: Object to which upgrade applies. Required for certain upgrades
.. note:: This function is only applicable for Hacknet Servers (the upgraded version
of a Hacknet Node).
Spend the hashes generated by your Hacknet Servers on an upgrade. Returns a boolean value -
true if the upgrade is successfully purchased, and false otherwise.
The name of the upgrade must be an exact match. The :code:`upgTarget` argument is used
for upgrades such as :code:`Reduce Minimum Security`, which applies to a specific server.
In this case, the :code:`upgTarget` argument must be the hostname of the server.
Example:
.. code:: javascript
hacknet.spendHashes("Sell for Corporation Funds");
hacknet.spendHashes("Increase Maximum Money", "foodnstuff");

View File

@ -3,6 +3,10 @@
Netscript Hacknet Node API
==========================
.. warning:: Not all functions in the Hacknet Node API are immediately available.
For this reason, the documentation for this API may contains spoilers
for the game.
Netscript provides the following API for accessing and upgrading your Hacknet Nodes
through scripts.
@ -36,6 +40,9 @@ In :ref:`netscriptjs`::
getRamUpgradeCost() <hacknetnodeapi/getRamUpgradeCost>
getCoreUpgradeCost() <hacknetnodeapi/getCoreUpgradeCost>
getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost>
numHashes() <hacknetnodeapi/numHashes>
hashCost() <hacknetnodeapi/hashCost>
spendHashes() <hacknetnodeapi/spendHashes>
.. _netscript_hacknetnodeapi_referencingahacknetnode:

View File

@ -41,6 +41,9 @@ In :ref:`netscriptjs`::
setToUniversityCourse() <sleeveapi/setToUniversityCourse>
setToGymWorkout() <sleeveapi/setToGymWorkout>
travel() <sleeveapi/travel>
getSleeveAugmentations() <sleeveapi/getSleeveAugmentations>
getSleevePurchasableAugs() <sleeveapi/getSleevePurchasableAugs>
purchaseSleeveAug() <sleeveapi/purchaseSleeveAug>
.. _netscript_sleeveapi_referencingaduplicatesleeve:

View File

@ -1,5 +1,5 @@
getSleevePurchasableAugs() Netscript Function
=======================================
=============================================
.. js:function:: getSleevePurchasableAugs(sleeveNumber)

View File

@ -204,226 +204,6 @@
<!-- React Component -->
</div>
<!-- World -->
<div id="world-container" class="generic-menupage-container">
<h2 id="world-city-name"> </h2>
<p id="world-city-desc"> </p>
<ul id="aevum-locations-list">
<li id="aevum-travelagency-li">
<a id="aevum-travelagency" class="a-link-button"> Travel Agency </a>
</li>
<li id="aevum-hospital-li">
<a id="aevum-hospital" class="a-link-button">Hospital</a>
</li>
<li id="aevum-summituniversity-li">
<a id="aevum-summituniversity" class="a-link-button"> Summit University </a>
</li>
<li id="aevum-ecorp-li">
<a id="aevum-ecorp" class="a-link-button"> ECorp </a>
</li>
<li id="aevum-bachmanandassociates-li">
<a id="aevum-bachmanandassociates" class="a-link-button"> Bachman & Associates</a>
</li>
<li id="aevum-clarkeincorporated-li">
<a id="aevum-clarkeincorporated" class="a-link-button"> Clarke Incorporated </a>
</li>
<li id="aevum-fulcrumtechnologies-li">
<a id="aevum-fulcrumtechnologies" class="a-link-button"> Fulcrum Technologies </a>
</li>
<li id="aevum-aerocorp-li">
<a id="aevum-aerocorp" class="a-link-button"> AeroCorp </a>
</li>
<li id="aevum-galacticcybersystems-li">
<a id="aevum-galacticcybersystems" class="a-link-button"> Galactic Cybersystems </a>
</li>
<li id="aevum-watchdogsecurity-li">
<a id="aevum-watchdogsecurity" class="a-link-button">Watchdog Security </a>
</li>
<li id="aevum-rhoconstruction-li">
<a id="aevum-rhoconstruction" class="a-link-button">Rho Construction </a>
</li>
<li id="aevum-aevumpolice-li">
<a id="aevum-aevumpolice" class="a-link-button">Aevum Police</a>
</li>
<li id="aevum-netlinktechnologies-li">
<a id="aevum-netlinktechnologies" class="a-link-button">NetLink Technologies</a>
</li>
<li id="aevum-crushfitnessgym-li">
<a id="aevum-crushfitnessgym" class="a-link-button">Crush Fitness Gym </a>
</li>
<li id="aevum-snapfitnessgym-li">
<a id="aevum-snapfitnessgym" class="a-link-button">Snap Fitness Gym</a>
</li>
<li id="aevum-slums-li">
<a id="aevum-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="chongqing-locations-list">
<li id="chongqing-travelagency-li">
<a id="chongqing-travelagency" class="a-link-button"> Travel Agency </a>
</li>
<li id="chongqing-hospital-li">
<a id="chongqing-hospital" class="a-link-button">Hospital</a>
</li>
<li id="chonqging-kuaigonginternational-li">
<a id="chongqing-kuaigonginternational" class="a-link-button">KuaiGong International </a>
</li>
<li id="chongqing-solarisspacesystems-li">
<a id="chongqing-solarisspacesystems" class="a-link-button">Solaris Space Systems</a>
</li>
<li id="chongqing-slums-li">
<a id="chongqing-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="sector12-locations-list">
<li id="sector12-travelagency-li">
<a id="sector12-travelagency" class="a-link-button">Travel Agency </a>
</li>
<li id="sector12-hospital-li">
<a id="sector12-hospital" class="a-link-button">Hospital</a>
</li>
<li id="sector12-rothmanuniversity-li">
<a id="sector12-rothmanuniversity" class="a-link-button"> Rothman University</a>
</li>
<li id="sector12-megacorp-li">
<a id="sector12-megacorp" class="a-link-button">MegaCorp</a>
</li>
<li id="sector12-bladeindustries-li">
<a id="sector12-bladeindustries" class="a-link-button"> Blade Industries</a>
</li>
<li id="sector12-foursigma-li">
<a id="sector12-foursigma" class="a-link-button">Four Sigma</a>
</li>
<li id="sector12-icarusmicrosystems-li">
<a id="sector12-icarusmicrosystems" class="a-link-button"> Icarus Microsystems</a>
</li>
<li id="sector12-universalenergy-li">
<a id="sector12-universalenergy" class="a-link-button">Universal Energy </a>
</li>
<li id="sector12-deltaone-li">
<a id="sector12-deltaone" class="a-link-button">DeltaOne </a>
</li>
<li id="sector12-cia-li">
<a id="sector12-cia" class="a-link-button">Central Intelligence Agency </a>
</li>
<li id="sector12-nsa-li">
<a id="sector12-nsa" class="a-link-button">National Security Agency </a>
</li>
<li id="sector12-alphaenterprises-li">
<a id="sector12-alphaenterprises" class="a-link-button">Alpha Enterprises</a>
</li>
<li id="sector12-carmichaelsecurity-li">
<a id="sector12-carmichaelsecurity" class="a-link-button"> Carmichael Security</a>
</li>
<li id="sector12-foodnstuff-li">
<a id="sector12-foodnstuff" class="a-link-button">FoodNStuff</a>
</li>
<li id="sector12-joesguns-li">
<a id="sector12-joesguns" class="a-link-button"> Joe's Guns</a>
</li>
<li id="sector12-irongym-li">
<a id="sector12-irongym" class="a-link-button">Iron Gym </a>
</li>
<li id="sector12-powerhousegym-li">
<a id="sector12-powerhousegym" class="a-link-button">Powerhouse Gym</a>
</li>
<li id="sector12-slums-li">
<a id="sector12-slums" class="a-link-button">The Slums</a>
</li>
<li id="sector12-cityhall-li">
<a id="sector12-cityhall" class="a-link-button">City Hall</a>
</li>
</ul>
<ul id="newtokyo-locations-list">
<li id="newtokyo-travelagency-li">
<a id="newtokyo-travelagency" class="a-link-button"> Travel Agency</a>
</li>
<li id="newtokyo-hospital-li">
<a id="newtokyo-hospital" class="a-link-button">Hospital</a>
</li>
<li id="newtokyo-defcomm-li">
<a id="newtokyo-defcomm" class="a-link-button"> DefComm</a>
</li>
<li id="newtokyo-vitalife-li">
<a id="newtokyo-vitalife" class="a-link-button">VitaLife </a>
</li>
<li id="newtokyo-globalpharmaceuticals-li">
<a id="newtokyo-globalpharmaceuticals" class="a-link-button">Global Pharmaceuticals</a>
</li>
<li id="newtokyo-noodlebar-li">
<a id="newtokyo-noodlebar" class="a-link-button">Noodle Bar </a>
</li>
<li id="newtokyo-slums-li">
<a id="newtokyo-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="ishima-locations-list">
<li id="ishima-travelagency-li">
<a id="ishima-travelagency" class="a-link-button">Travel Agency </a>
</li>
<li id="ishima-hospital-li">
<a id="ishima-hospital" class="a-link-button">Hospital</a>
</li>
<li id="ishima-stormtechnologies-li">
<a id="ishima-stormtechnologies" class="a-link-button">Storm Technologies</a>
</li>
<li id="ishima-novamedical-li">
<a id="ishima-novamedical" class="a-link-button">Nova Medical</a>
</li>
<li id="ishima-omegasoftware-li">
<a id="ishima-omegasoftware" class="a-link-button">Omega Software </a>
</li>
<li id="ishima-slums-li">
<a id="ishima-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="volhaven-locations-list">
<li id="volhaven-travelagency-li">
<a id="volhaven-travelagency" class="a-link-button">Travel Agency </a>
</li>
<li id="volhaven-hospital-li">
<a id="volhaven-hospital" class="a-link-button">Hospital</a>
</li>
<li id="volhaven-zbinstituteoftechnology-li">
<a id="volhaven-zbinstituteoftechnology" class="a-link-button">ZB Insitute of Technology</a>
</li>
<li id="volhaven-omnitekincorporated-li">
<a id="volhaven-omnitekincorporated" class="a-link-button">OmniTek Incorporated </a>
</li>
<li id="volhaven-nwo-li">
<a id="volhaven-nwo" class="a-link-button">NWO</a>
</li>
<li id="volhaven-helislabs-li">
<a id="volhaven-helioslabs" class="a-link-button">Helios Labs</a>
</li>
<li id="volhaven-omniacybersystems-li">
<a id="volhaven-omniacybersystems" class="a-link-button">Omnia Cybersystems</a>
</li>
<li id="volhaven-lexocorp-li">
<a id="volhaven-lexocorp" class="a-link-button">LexoCorp</a>
</li>
<li id="volhaven-syscoresecurities-li">
<a id="volhaven-syscoresecurities" class="a-link-button">SysCore Securities</a>
</li>
<li id="volhaven-computek-li">
<a id="volhaven-computek" class="a-link-button">CompuTek</a>
</li>
<li id="volhaven-milleniumfitnessgym-li">
<a id="volhaven-milleniumfitnessgym" class="a-link-button">Millenium Fitness Gym</a>
</li>
<li id="volhaven-slums-li">
<a id="volhaven-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="generic-locations-list"></ul>
</div>
<!-- Create a program(executable) -->
<div id="create-program-container" class="generic-menupage-container">
<p id="create-program-page-text">
@ -450,150 +230,31 @@
<div id="tutorial-container" class="generic-menupage-container">
<h1> Tutorial (AKA Links to Documentation) </h1>
<a id="tutorial-getting-started-link" class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html">
Getting Started
</a><br><br>
Getting Started</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html">
Servers & Networking
</a><br><br>
Servers & Networking</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html">
Hacking
</a><br><br>
Hacking</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html">
Scripts
</a><br><br>
Scripts</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/netscript.html">
Netscript Programming Language
</a><br><br>
Netscript Programming Language</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html">
Traveling
</a><br><br>
Traveling</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html">
Companies
</a><br><br>
Companies</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html">
Infiltration
</a><br><br>
Infiltration</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html">
Factions
</a><br><br>
Factions</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html">
Augmentations
</a><br><br>
Augmentations</a><br><br>
<a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/shortcuts.html">
Keyboard Shortcuts
</a>
Keyboard Shortcuts</a>
</div>
<!-- Location (visiting a location in World) -->
<div id="location-container" class="generic-menupage-container">
<a id="location-return-to-world-button" class="a-link-button"> Return to World </a>
<h1 id="location-name"></h1>
<p id="location-info"> </p>
<p id="location-job-title"> </p>
<p id="location-text-divider-1"> --------------- </p>
<p id="location-job-reputation" class="tooltip"> </p>
<p id="location-text-divider-2"> --------------- </p>
<p id="location-company-favor" class="tooltip"> </p>
<p id="location-text-divider-3"> --------------- </p>
<!-- Jobs/Work at a company -->
<a id="location-software-job" class="a-link-button tooltip"> Apply for Software Job</a>
<a id="location-software-consultant-job" class="a-link-button tooltip"> Apply for Software Consultant Job</a>
<a id="location-it-job" class="a-link-button tooltip"> Apply for IT Job </a>
<a id="location-security-engineer-job" class="a-link-button tooltip"> Apply for Security Engineer Job</a>
<a id="location-network-engineer-job" class="a-link-button tooltip"> Apply for Network Engineer Job</a>
<a id="location-business-job" class="a-link-button tooltip"> Apply for Business Job</a>
<a id="location-business-consultant-job" class="a-link-button tooltip"> Apply for Business Consultant Job </a>
<a id="location-security-job" class="a-link-button tooltip"> Apply for Security Job</a>
<a id="location-agent-job" class="a-link-button tooltip"> Apply to be an Agent</a>
<a id="location-employee-job" class="a-link-button tooltip"> Apply to be an Employee </a>
<a id="location-parttime-employee-job" class="a-link-button tooltip"> Apply to be a Part-time Employee </a>
<a id="location-waiter-job" class="a-link-button tooltip"> Apply to be a Waiter</a>
<a id="location-parttime-waiter-job" class="a-link-button tooltip"> Apply to be a Part-time Waiter</a>
<a id="location-work" class="a-link-button"> Work </a>
<!-- Gym -->
<a id="location-gym-train-str" class="a-link-button">Train Strength</a>
<a id="location-gym-train-def" class="a-link-button">Train Defense </a>
<a id="location-gym-train-dex" class="a-link-button">Train Dexterity</a>
<a id="location-gym-train-agi" class="a-link-button">Train Agility</a>
<!-- Study/Take classes at a university -->
<a id="location-study-computer-science" class="a-link-button">Study Computer Science (free)</a>
<a id="location-data-structures-class" class="a-link-button">Take Data Structures course</a>
<a id="location-networks-class" class="a-link-button">Take Networks course</a>
<a id="location-algorithms-class" class="a-link-button">Take Algorithms course</a>
<a id="location-management-class" class="a-link-button">Take Management course</a>
<a id="location-leadership-class" class="a-link-button">Take Leadership course</a>
<!-- Purchase servers -->
<a id="location-purchase-2gb" class="a-link-button"> Purchase 2GB Server - $150,000</a>
<a id="location-purchase-4gb" class="a-link-button"> Purchase 4GB Server - $300,000</a>
<a id="location-purchase-8gb" class="a-link-button"> Purchase 8GB Server - $600,000</a>
<a id="location-purchase-16gb" class="a-link-button"> Purchase 16GB Server - $1,200,000</a>
<a id="location-purchase-32gb" class="a-link-button"> Purchase 32GB Server - $2,400,000</a>
<a id="location-purchase-64gb" class="a-link-button"> Purchase 64GB Server - $4,800,000</a>
<a id="location-purchase-128gb" class="a-link-button"> Purchase 128GB Server - $9,600,000</a>
<a id="location-purchase-256gb" class="a-link-button"> Purchase 256GB Server - $19,200,000</a>
<a id="location-purchase-512gb" class="a-link-button"> Purchase 512GB Server - $38,400,000</a>
<a id="location-purchase-1tb" class="a-link-button"> Purchase 1TB Server - $75,000,000</a>
<a id="location-purchase-tor" class="a-link-button"> Purchase TOR Router - $100,000</a>
<a id="location-purchase-home-ram" class="a-link-button"> Purchase additional RAM for Home computer </a>
<a id="location-purchase-home-cores" class="a-link-button"> Purchase additional Core for Home computer </a>
<!-- Infiltrate -->
<a id="location-infiltrate" class="a-link-button tooltip"> Infiltrate Company
<span class="tooltiptext">
Infiltrate this company's facility to try and steal their classified secrets!
Warning: You may end up hospitalized if you are unsuccessful!
</span>
</a>
<!-- Hospital -->
<a id="location-hospital-treatment" class="a-link-button"> Get Treatment for Wounds </a>
<!-- Travel agency -->
<p id="location-travel-agency-text">
From here, you can travel to any other city! A ticket costs $200,000.
</p>
<a id="location-travel-to-aevum" class="a-link-button"> Travel to Aevum </a>
<a id="location-travel-to-chongqing" class="a-link-button"> Travel to Chongqing</a>
<a id="location-travel-to-sector12" class="a-link-button"> Travel to Sector-12</a>
<a id="location-travel-to-newtokyo" class="a-link-button"> Travel to New Tokyo</a>
<a id="location-travel-to-ishima" class="a-link-button"> Travel to Ishima</a>
<a id="location-travel-to-volhaven" class="a-link-button"> Travel to Volhaven</a>
<!-- Slums -->
<p id="location-slums-description">
You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and
other shadowy entities. The city's government and police have neglected this area for years...
<br/><br/><br/>
In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always
successful. Your chance at successfully committing a crime is determined by your stats.
</p>
<a class="a-link-button tooltip" id="location-slums-shoplift"> Shoplift </a>
<a id="location-slums-rob-store" class="a-link-button tooltip"> Rob a store </a>
<a id="location-slums-mug" class="a-link-button tooltip"> Mug someone </a>
<a id="location-slums-larceny" class="a-link-button tooltip"> Commit Larceny </a>
<a id="location-slums-deal-drugs" class="a-link-button tooltip"> Deal Drugs </a>
<a id="location-slums-bond-forgery" class="a-link-button tooltip">Bond Forgery</a>
<a id="location-slums-traffic-arms" class="a-link-button tooltip">Traffick Illegal Arms</a>
<a id="location-slums-homicide" class="a-link-button tooltip">Homicide</a>
<a id="location-slums-gta" class="a-link-button tooltip"> Grand Theft Auto </a>
<a id="location-slums-kidnap" class="a-link-button tooltip"> Kidnap and Ransom </a>
<a id="location-slums-assassinate" class="a-link-button tooltip"> Assassinate </a>
<a id="location-slums-heist" class="a-link-button tooltip"> Heist </a>
<!-- City Hall -->
<a id="location-cityhall-create-corporation" class="a-link-button">Create a Corporation</a>
<!-- Bladeburner @ NSA -->
<a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a>
<!-- Re-sleeving @ VitaLife -->
<a id="location-vitalife-resleeve" class="a-link-button">Re-Sleeve</a>
</div>
<div id="infiltration-container" class="generic-menupage-container">

View File

@ -1,9 +1,10 @@
import {post} from "./ui/postToTerminal";
import { IMap } from "./types";
import { post } from "./ui/postToTerminal";
let Aliases = {};
let GlobalAliases = {};
export let Aliases: IMap<string> = {};
export let GlobalAliases: IMap<string> = {};
function loadAliases(saveString) {
export function loadAliases(saveString: string): void {
if (saveString === "") {
Aliases = {};
} else {
@ -11,7 +12,7 @@ function loadAliases(saveString) {
}
}
function loadGlobalAliases(saveString) {
export function loadGlobalAliases(saveString: string): void {
if (saveString === "") {
GlobalAliases = {};
} else {
@ -20,7 +21,7 @@ function loadGlobalAliases(saveString) {
}
//Print all aliases to terminal
function printAliases() {
export function printAliases(): void {
for (var name in Aliases) {
if (Aliases.hasOwnProperty(name)) {
post("alias " + name + "=" + Aliases[name]);
@ -34,7 +35,7 @@ function printAliases() {
}
//True if successful, false otherwise
function parseAliasDeclaration(dec,global=false) {
export function parseAliasDeclaration(dec: string, global: boolean=false) {
var re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
var matches = dec.match(re);
if (matches == null || matches.length != 3) {return false;}
@ -46,50 +47,53 @@ function parseAliasDeclaration(dec,global=false) {
return true;
}
function addAlias(name, value) {
if (name in GlobalAliases){
function addAlias(name: string, value: string): void {
if (name in GlobalAliases) {
delete GlobalAliases[name];
}
Aliases[name] = value;
}
function addGlobalAlias(name, value) {
function addGlobalAlias(name: string, value: string): void {
if (name in Aliases){
delete Aliases[name];
}
GlobalAliases[name] = value;
}
function getAlias(name) {
function getAlias(name: string): string | null {
if (Aliases.hasOwnProperty(name)) {
return Aliases[name];
}
return null;
}
function getGlobalAlias(name) {
function getGlobalAlias(name: string): string | null {
if (GlobalAliases.hasOwnProperty(name)) {
return GlobalAliases[name];
}
return null;
}
function removeAlias(name) {
export function removeAlias(name: string): boolean {
if (Aliases.hasOwnProperty(name)) {
delete Aliases[name];
return true;
}
if (GlobalAliases.hasOwnProperty(name)) {
delete GlobalAliases[name];
return true;
}
return false;
}
//Returns the original string with any aliases substituted in
//Aliases only applied to "whole words", one level deep
function substituteAliases(origCommand) {
var commandArray = origCommand.split(" ");
export function substituteAliases(origCommand: string): string {
const commandArray = origCommand.split(" ");
if (commandArray.length > 0){
// For the unalias command, dont substite
if (commandArray[0] === "unalias") { return commandArray.join(" "); }
@ -112,6 +116,3 @@ function substituteAliases(origCommand) {
}
return commandArray.join(" ");
}
export {Aliases, GlobalAliases, printAliases, parseAliasDeclaration,
removeAlias, substituteAliases, loadAliases, loadGlobalAliases};

View File

@ -2097,12 +2097,6 @@ function displayAugmentationsContent(contentEl) {
innerText:"Purchased Augmentations",
}));
//Bladeburner text, once mechanic is unlocked
var bladeburnerText = "\n";
if (Player.bitNodeN === 6 || hasBladeburnerSF) {
bladeburnerText = "Bladeburner Progress\n\n";
}
contentEl.appendChild(createElement("pre", {
width:"70%", whiteSpace:"pre-wrap", display:"block",
innerText:"Below is a list of all Augmentations you have purchased but not yet installed. Click the button below to install them.\n" +
@ -2114,7 +2108,6 @@ function displayAugmentationsContent(contentEl) {
"Hacknet Nodes\n" +
"Faction/Company reputation\n" +
"Stocks\n" +
bladeburnerText +
"Installing Augmentations lets you start over with the perks and benefits granted by all " +
"of the Augmentations you have ever installed. Also, you will keep any scripts and RAM/Core upgrades " +
"on your home computer (but you will lose all programs besides NUKE.exe)."

View File

@ -6,7 +6,6 @@ import { Engine } from "./engine";
import { Faction } from "./Faction/Faction";
import { Factions, factionExists } from "./Faction/Factions";
import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers";
import { Locations } from "./Locations";
import { Player } from "./Player";
import { hackWorldDaemon, redPillFlag } from "./RedPill";
import { numeralWrapper } from "./ui/numeralFormat";
@ -218,7 +217,7 @@ $(document).keydown(function(event) {
});
function City(params={}) {
this.name = params.name ? params.name : Locations.Sector12;
this.name = params.name ? params.name : CityNames[2]; // Sector-12
//Synthoid population and estimate
this.pop = params.pop ? params.pop : getRandomInt(PopulationThreshold, 1.5 * PopulationThreshold);
@ -690,7 +689,7 @@ function Bladeburner(params={}) {
for (var i = 0; i < CityNames.length; ++i) {
this.cities[CityNames[i]] = new City({name:CityNames[i]});
}
this.city = Locations.Sector12;
this.city = CityNames[2]; // Sector-12
//Map of SkillNames -> level
this.skills = {};

View File

@ -1,8 +1,11 @@
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
import { CompanyPosition } from "./CompanyPosition";
import * as posNames from "./data/companypositionnames";
import { CONSTANTS } from "../Constants";
import { IMap } from "../types";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
export interface IConstructorParams {
name: string;
info: string;
@ -93,6 +96,43 @@ export class Company {
}
}
hasAgentPositions(): boolean {
return (this.companyPositions[posNames.AgentCompanyPositions[0]] != null);
}
hasBusinessConsultantPositions(): boolean {
return (this.companyPositions[posNames.BusinessConsultantCompanyPositions[0]] != null);
}
hasBusinessPositions(): boolean {
return (this.companyPositions[posNames.BusinessCompanyPositions[0]] != null);
}
hasEmployeePositions(): boolean {
return (this.companyPositions[posNames.MiscCompanyPositions[1]] != null);
}
hasITPositions(): boolean {
return (this.companyPositions[posNames.ITCompanyPositions[0]] != null);
}
hasSecurityPositions(): boolean {
return (this.companyPositions[posNames.SecurityCompanyPositions[2]] != null);
}
hasSoftwareConsultantPositions(): boolean {
return (this.companyPositions[posNames.SoftwareConsultantCompanyPositions[0]] != null);
}
hasSoftwarePositions(): boolean {
return (this.companyPositions[posNames.SoftwareCompanyPositions[0]] != null);
}
hasWaiterPositions(): boolean {
return (this.companyPositions[posNames.MiscCompanyPositions[0]] != null);
}
gainFavor(): void {
if (this.favor == null) { this.favor = 0; }
if (this.rolloverRep == null) { this.rolloverRep = 0; }

View File

@ -1,5 +1,5 @@
import { CONSTANTS } from "../Constants";
import * as names from "./data/CompanyPositionNames";
import * as names from "./data/companypositionnames";
/* tslint:disable:completed-docs */

View File

@ -3,7 +3,7 @@
import { CompanyPosition } from "./CompanyPosition";
import { CompanyPositions } from "./CompanyPositions";
export function getNextCompanyPosition(currPos: CompanyPosition | null): CompanyPosition | null {
export function getNextCompanyPositionHelper(currPos: CompanyPosition | null): CompanyPosition | null {
if (currPos == null) { return null; }
const nextPosName: string | null = currPos.nextPosition;

View File

@ -1,7 +1,8 @@
import { IConstructorParams } from "../Company";
import { Locations } from "../../Locations";
import * as posNames from "./CompanyPositionNames";
import { IMap } from "../../types";
import * as posNames from "./companypositionnames";
import { IConstructorParams } from "../Company";
import { IMap } from "../../types";
import { LocationName } from "../../Locations/data/LocationNames";
// Create Objects containing Company Positions by category
// Will help in metadata construction later
@ -89,7 +90,7 @@ CEOOnly[posNames.BusinessCompanyPositions[5]] = true;
// Metadata
export const companiesMetadata: IConstructorParams[] = [
{
name: Locations.AevumECorp,
name: LocationName.AevumECorp,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -101,7 +102,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 249,
},
{
name: Locations.Sector12MegaCorp,
name: LocationName.Sector12MegaCorp,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -113,7 +114,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 249,
},
{
name: Locations.AevumBachmanAndAssociates,
name: LocationName.AevumBachmanAndAssociates,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -125,7 +126,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.Sector12BladeIndustries,
name: LocationName.Sector12BladeIndustries,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -137,7 +138,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.VolhavenNWO,
name: LocationName.VolhavenNWO,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -149,7 +150,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 249,
},
{
name: Locations.AevumClarkeIncorporated,
name: LocationName.AevumClarkeIncorporated,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -161,7 +162,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.VolhavenOmniTekIncorporated,
name: LocationName.VolhavenOmniTekIncorporated,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -173,7 +174,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.Sector12FourSigma,
name: LocationName.Sector12FourSigma,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -185,7 +186,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.ChongqingKuaiGongInternational,
name: LocationName.ChongqingKuaiGongInternational,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -197,7 +198,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.AevumFulcrumTechnologies,
name: LocationName.AevumFulcrumTechnologies,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -208,7 +209,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.IshimaStormTechnologies,
name: LocationName.IshimaStormTechnologies,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -220,7 +221,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.NewTokyoDefComm,
name: LocationName.NewTokyoDefComm,
info: "",
companyPositions: Object.assign({},
CEOOnly,
@ -232,7 +233,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.VolhavenHeliosLabs,
name: LocationName.VolhavenHeliosLabs,
info: "",
companyPositions: Object.assign({},
CEOOnly,
@ -244,7 +245,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.NewTokyoVitaLife,
name: LocationName.NewTokyoVitaLife,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -256,7 +257,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.Sector12IcarusMicrosystems,
name: LocationName.Sector12IcarusMicrosystems,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -268,7 +269,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.Sector12UniversalEnergy,
name: LocationName.Sector12UniversalEnergy,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -280,7 +281,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.AevumGalacticCybersystems,
name: LocationName.AevumGalacticCybersystems,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -292,7 +293,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.AevumAeroCorp,
name: LocationName.AevumAeroCorp,
info: "",
companyPositions: Object.assign({},
CEOOnly,
@ -305,7 +306,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.VolhavenOmniaCybersystems,
name: LocationName.VolhavenOmniaCybersystems,
info: "",
companyPositions: Object.assign({},
CEOOnly,
@ -318,7 +319,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.ChongqingSolarisSpaceSystems,
name: LocationName.ChongqingSolarisSpaceSystems,
info: "",
companyPositions: Object.assign({},
CEOOnly,
@ -331,7 +332,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.Sector12DeltaOne,
name: LocationName.Sector12DeltaOne,
info: "",
companyPositions: Object.assign({},
CEOOnly,
@ -344,7 +345,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.NewTokyoGlobalPharmaceuticals,
name: LocationName.NewTokyoGlobalPharmaceuticals,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -357,7 +358,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 224,
},
{
name: Locations.IshimaNovaMedical,
name: LocationName.IshimaNovaMedical,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -370,7 +371,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 199,
},
{
name: Locations.Sector12CIA,
name: LocationName.Sector12CIA,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToHeadOfEngineering,
@ -385,7 +386,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 149,
},
{
name: Locations.Sector12NSA,
name: LocationName.Sector12NSA,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToHeadOfEngineering,
@ -400,7 +401,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 149,
},
{
name: Locations.AevumWatchdogSecurity,
name: LocationName.AevumWatchdogSecurity,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToHeadOfEngineering,
@ -415,7 +416,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 124,
},
{
name: Locations.VolhavenLexoCorp,
name: LocationName.VolhavenLexoCorp,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -428,7 +429,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 99,
},
{
name: Locations.AevumRhoConstruction,
name: LocationName.AevumRhoConstruction,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToLeadDeveloper,
@ -439,7 +440,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 49,
},
{
name: Locations.Sector12AlphaEnterprises,
name: LocationName.Sector12AlphaEnterprises,
info: "",
companyPositions: Object.assign({},
SoftwarePositionsUpToLeadDeveloper,
@ -451,7 +452,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 99,
},
{
name: Locations.AevumPolice,
name: LocationName.AevumPolice,
info: "",
companyPositions: Object.assign({},
AllSecurityPositions,
@ -462,7 +463,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 99,
},
{
name: Locations.VolhavenSysCoreSecurities,
name: LocationName.VolhavenSysCoreSecurities,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions
@ -472,7 +473,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 124,
},
{
name: Locations.VolhavenCompuTek,
name: LocationName.VolhavenCompuTek,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions
@ -482,7 +483,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 74,
},
{
name: Locations.AevumNetLinkTechnologies,
name: LocationName.AevumNetLinkTechnologies,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions
@ -492,7 +493,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 99,
},
{
name: Locations.Sector12CarmichaelSecurity,
name: LocationName.Sector12CarmichaelSecurity,
info: "",
companyPositions: Object.assign({},
AllTechnologyPositions,
@ -505,7 +506,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 74,
},
{
name: Locations.Sector12FoodNStuff,
name: LocationName.Sector12FoodNStuff,
info: "",
companyPositions: Object.assign({},
EmployeeOnly, PartTimeEmployeeOnly
@ -515,7 +516,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 0,
},
{
name: Locations.Sector12JoesGuns,
name: LocationName.Sector12JoesGuns,
info: "",
companyPositions: Object.assign({},
EmployeeOnly, PartTimeEmployeeOnly
@ -525,7 +526,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 0,
},
{
name: Locations.IshimaOmegaSoftware,
name: LocationName.IshimaOmegaSoftware,
info: "",
companyPositions: Object.assign({},
AllSoftwarePositions,
@ -537,7 +538,7 @@ export const companiesMetadata: IConstructorParams[] = [
jobStatReqOffset: 49,
},
{
name: Locations.NewTokyoNoodleBar,
name: LocationName.NewTokyoNoodleBar,
info: "",
companyPositions: Object.assign({},
WaiterOnly, PartTimeWaiterOnly

View File

@ -1,6 +1,6 @@
// Metadata used for constructing Company Positions
import { IConstructorParams } from "../CompanyPosition";
import * as posNames from "./CompanyPositionNames";
import * as posNames from "./companypositionnames";
export const companyPositionMetadata: IConstructorParams[] = [
{

View File

@ -6,7 +6,7 @@
import {IMap} from "./types";
export let CONSTANTS: IMap<any> = {
Version: "0.46.0",
Version: "0.46.1",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -273,21 +273,16 @@ export let CONSTANTS: IMap<any> = {
LatestUpdate:
`
v0.46.0
* Added BitNode-9: Hacktocracy
* Changed BitNode-11's multipliers to make it slightly harder overall
* Source-File 11 is now slightly stronger
* Added several functions to Netscript Sleeve API for buying Sleeve augmentations (by hydroflame)
* Added a new stat for Duplicate Sleeves: Memory
* Increase baseline experience earned from Infiltration, but it now gives diminishing returns (on exp) as you get to higher difficulties/levels
* In Bladeburner, stamina gained from Hyperbolic Regeneration Chamber is now a percentage of your max stamina
v0.46.1
* Added a very rudimentary directory system to the Terminal
** Details here: https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#filesystem-directories
* Corporation Changes:
** 'Demand' value of products decreases more slowly
** Bug Fix: Fixed a Corporation issue that broke the Market-TA2 Research
** Bug Fix: Issuing New Shares now works properly
* Bug Fix: Money Statistics tracker was incorrectly recording profits when selling stocks manually
* Bug Fix: Fixed an issue with the job requirement tooltip for security jobs
* Added numHashes(), hashCost(), and spendHashes() functions to the Netscript Hacknet Node API
* 'Generate Coding Contract' hash upgrade is now more expensive
* 'Generate Coding Contract' hash upgrade now generates the contract randomly on the server, rather than on home computer
* The cost of selling hashes for money no longer increases each time
* Selling hashes for money now costs 4 hashes (in exchange for $1m)
* Bug Fix: Hacknet Node earnings should work properly when game is inactive/offline
* Bug Fix: Duplicate Sleeve augmentations are now properly reset when switching to a new BitNode
`
}

View File

@ -18,8 +18,8 @@ import { BitNodeMultipliers } from "../BitNode/BitNode
import { CONSTANTS } from "../Constants";
import { Factions } from "../Faction/Factions";
import { showLiterature } from "../Literature";
import { Locations } from "../Locations";
import { createCityMap } from "../Locations/Cities";
import { CityName } from "../Locations/data/CityNames";
import { Player } from "../Player";
import { numeralWrapper } from "../ui/numeralFormat";
@ -113,15 +113,15 @@ $(document).mousedown(function(event) {
var empManualAssignmentModeActive = false;
function Industry(params={}) {
this.offices = { //Maps locations to offices. 0 if no office at that location
[Locations.Aevum]: 0,
[Locations.Chongqing]: 0,
[Locations.Sector12]: new OfficeSpace({
loc:Locations.Sector12,
[CityName.Aevum]: 0,
[CityName.Chongqing]: 0,
[CityName.Sector12]: new OfficeSpace({
loc:CityName.Sector12,
size:OfficeInitialSize,
}),
[Locations.NewTokyo]: 0,
[Locations.Ishima]: 0,
[Locations.Volhaven]: 0
[CityName.NewTokyo]: 0,
[CityName.Ishima]: 0,
[CityName.Volhaven]: 0
};
this.name = params.name ? params.name : 0;
@ -172,17 +172,17 @@ function Industry(params={}) {
this.newInd = true;
this.warehouses = { //Maps locations to warehouses. 0 if no warehouse at that location
[Locations.Aevum]: 0,
[Locations.Chonqing]: 0,
[Locations.Sector12]: new Warehouse({
[CityName.Aevum]: 0,
[CityName.Chonqing]: 0,
[CityName.Sector12]: new Warehouse({
corp: params.corp,
industry: this,
loc: Locations.Sector12,
loc: CityName.Sector12,
size: WarehouseInitialSize,
}),
[Locations.NewTokyo]: 0,
[Locations.Ishima]: 0,
[Locations.Volhaven]: 0
[CityName.NewTokyo]: 0,
[CityName.Ishima]: 0,
[CityName.Volhaven]: 0
};
this.init();
@ -571,7 +571,7 @@ Industry.prototype.processProductMarket = function(marketCycles=1) {
const product = this.products[name];
let change = getRandomInt(0, 3) * 0.0004;
if (change === 0) { continue; }
if (this.type === Industries.Pharmaceutical || this.type === Industries.Software ||
this.type === Industries.Robotics) {
change *= 3;

View File

@ -3,11 +3,9 @@ import { MaterialSizes } from "./MaterialSizes";
import { ProductRatingWeights,
IProductRatingWeight } from "./ProductRatingWeights";
import { Cities } from "../Locations/Cities";
import { createCityMap } from "../Locations/createCityMap";
import { IMap } from "../types";
import { Generic_fromJSON,
Generic_toJSON,
Reviver } from "../../utils/JSONReviver";

View File

@ -1417,7 +1417,7 @@ export class CorporationEventHandler {
}
// Array of all cities. Used later
const cities = Object.values(Cities);
const cities = Object.keys(Cities);
// Parse quantity
if (inputQty.value.includes("MAX") || inputQty.value.includes("PROD")) {

View File

@ -11,7 +11,7 @@ import { overviewPage } from "./Routing";
import { OfficeSpace } from "../Corporation";
import { Cities } from "../../Locations/Cities";
import { CityName } from "../../Locations/data/CityNames";
export class MainPanel extends BaseReactComponent {
constructor(props) {
@ -19,13 +19,13 @@ export class MainPanel extends BaseReactComponent {
this.state = {
division: "",
city: Cities.Sector12,
city: CityName.Sector12,
}
}
// We can pass this setter to child components
changeCityState(newCity) {
if (Object.values(Cities).includes(newCity)) {
if (Object.values(CityName).includes(newCity)) {
this.state.city = newCity;
} else {
console.error(`Tried to change MainPanel's city state to an invalid city: ${newCity}`);
@ -45,7 +45,7 @@ export class MainPanel extends BaseReactComponent {
const currentDivision = this.routing().current();
if (currentDivision !== this.state.division) {
this.state.division = currentDivision;
this.state.city = Cities.Sector12;
this.state.city = CityName.Sector12;
}
return this.renderDivisionPage();

View File

@ -54,7 +54,7 @@ export class Overview extends BaseReactComponent {
`Dividends per share: ${numeralWrapper.format(dividendsPerShare, "$0.000a")} / s<br>` +
`Your earnings as a shareholder (Pre-Tax): ${numeralWrapper.format(playerEarnings, "$0.000a")} / s<br>` +
`Dividend Tax Rate: ${this.corp().dividendTaxPercentage}%<br>` +
`Your earnings as a shareholder (Post-Tax): ${numeralWrapper.format(playerEarnings * (1 - (this.corp().dividendTaxPercentage / 100)), "$0.000a")} / s<br>`;
`Your earnings as a shareholder (Post-Tax): ${numeralWrapper.format(playerEarnings * (1 - (this.corp().dividendTaxPercentage / 100)), "$0.000a")} / s<br><br>`;
}
let txt = "Total Funds: " + numeralWrapper.format(this.corp().funds.toNumber(), '$0.000a') + "<br>" +

View File

@ -7,7 +7,6 @@ import { Engine } from "../engine";
import { Faction } from "./Faction";
import { Factions } from "./Factions";
import { FactionInfos } from "./FactionInfo";
import { Locations} from "../Location";
import { HackingMission, setInMission } from "../Missions";
import { Player } from "../Player";
import { PurchaseAugmentationsOrderSetting } from "../Settings/SettingEnums";

View File

@ -15,7 +15,7 @@ import { HacknetServer,
import { HashManager } from "./HashManager";
import { HashUpgrades } from "./HashUpgrades";
import { generateRandomContractOnHome } from "../CodingContractGenerator";
import { generateRandomContract } from "../CodingContractGenerator";
import { iTutorialSteps, iTutorialNextStep,
ITutorial} from "../InteractiveTutorial";
import { Player } from "../Player";
@ -45,25 +45,6 @@ export function hasHacknetServers() {
return (Player.bitNodeN === 9 || SourceFileFlags[9] > 0);
}
export function createHacknetServer() {
const numOwned = Player.hacknetNodes.length;
const name = `hacknet-node-${numOwned}`;
const server = new HacknetServer({
adminRights: true,
hostname: name,
player: Player,
});
Player.hacknetNodes.push(server.ip);
// Configure the HacknetServer to actually act as a Server
AddToAllServers(server);
const homeComputer = Player.getHomeComputer();
homeComputer.serversOnNetwork.push(server.ip);
server.serversOnNetwork.push(homeComputer.ip);
return server;
}
export function purchaseHacknet() {
/* INTERACTIVE TUTORIAL */
if (ITutorial.isRunning) {
@ -84,7 +65,7 @@ export function purchaseHacknet() {
if (!Player.canAfford(cost)) { return -1; }
Player.loseMoney(cost);
const server = createHacknetServer();
const server = Player.createHacknetServer();
Player.hashManager.updateCapacity(Player);
return numOwned;
@ -281,9 +262,9 @@ export function processHacknetEarnings(numCycles) {
// call the appropriate function
if (Player.hacknetNodes.length === 0) { return 0; }
if (hasHacknetServers()) {
return processAllHacknetServerEarnings();
return processAllHacknetServerEarnings(numCycles);
} else if (Player.hacknetNodes[0] instanceof HacknetNode) {
return processAllHacknetNodeEarnings();
return processAllHacknetNodeEarnings(numCycles);
} else {
return 0;
}
@ -421,7 +402,7 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
break;
}
case "Generate Coding Contract": {
generateRandomContractOnHome();
generateRandomContract();
break;
}
default:

View File

@ -3,13 +3,13 @@
*/
import { CONSTANTS } from "../Constants";
import { IHacknetNode } from "./IHacknetNode";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { IHacknetNode } from "../Hacknet/IHacknetNode";
import { IPlayer } from "../PersonObjects/IPlayer";
import { BaseServer } from "../Server/BaseServer";
import { RunningScript } from "../Script/RunningScript";
import { dialogBoxCreate } from "../../utils/DialogBox";
import { createRandomIp } from "../../utils/IPAddress";
import { Generic_fromJSON,

View File

@ -151,13 +151,12 @@ export class HashManager {
*/
upgrade(upgName: string): boolean {
const upg = HashUpgrades[upgName];
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null) {
if (upg == null) {
console.error(`Invalid Upgrade Name given to HashManager.upgrade(): ${upgName}`);
return false;
}
const cost = upg.getCost(currLevel);
const cost = this.getUpgradeCost(upgName);
if (this.hashes < cost) {
return false;

View File

@ -2,6 +2,7 @@
* Object representing an upgrade that can be purchased with hashes
*/
export interface IConstructorParams {
cost?: number;
costPerLevel: number;
desc: string;
hasTargetServer?: boolean;
@ -10,6 +11,14 @@ export interface IConstructorParams {
}
export class HashUpgrade {
/**
* If the upgrade has a flat cost (never increases), it goes here
* Otherwise, this property should be undefined
*
* This property overrides the 'costPerLevel' property
*/
cost?: number;
/**
* Base cost for this upgrade. Every time the upgrade is purchased,
* its cost increases by this same amount (so its 1x, 2x, 3x, 4x, etc.)
@ -35,6 +44,8 @@ export class HashUpgrade {
value: number = 0;
constructor(p: IConstructorParams) {
if (p.cost != null) { this.cost = p.cost; }
this.costPerLevel = p.costPerLevel;
this.desc = p.desc;
this.hasTargetServer = p.hasTargetServer ? p.hasTargetServer : false;
@ -43,6 +54,8 @@ export class HashUpgrade {
}
getCost(levels: number): number {
if (typeof this.cost === "number") { return this.cost; }
return Math.round((levels + 1) * this.costPerLevel);
}
}

View File

@ -3,7 +3,8 @@ import { IConstructorParams } from "../HashUpgrade";
export const HashUpgradesMetadata: IConstructorParams[] = [
{
costPerLevel: 1,
cost: 4,
costPerLevel: 4,
desc: "Sell hashes for $1m",
name: "Sell for Money",
value: 1e6,
@ -62,8 +63,8 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
value: 10,
},
{
costPerLevel: 150,
desc: "Generate a random Coding Contract on your home computer",
costPerLevel: 200,
desc: "Generate a random Coding Contract somewhere on the network",
name: "Generate Coding Contract",
value: 1,
},

10
src/IEngine.ts Normal file
View File

@ -0,0 +1,10 @@
/**
* TypeScript interface for the game engine (engine.js), which can't be converted
* to TypeScript at the moment
*/
export interface IEngine {
loadBladeburnerContent: () => void;
loadInfiltrationContent: () => void;
loadResleevingContent: () => void;
loadStockMarketContent: () => void;
}

7
src/Infiltration.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { LocationName } from "./Locations/data/LocationNames";
export declare function beginInfiltration(companyName: LocationName,
startLevel: number,
rewardVal: number,
maxClearance: number,
diff: number): void;

View File

@ -382,13 +382,13 @@ function iTutorialEvaluateStep() {
//Flash 'City' menu and set its tutorial click handler
cityMainMenu.setAttribute("class", "flashing-button");
cityMainMenu.addEventListener("click", function() {
Engine.loadWorldContent();
Engine.loadLocationContent();
iTutorialNextStep();
return false;
});
break;
case iTutorialSteps.WorldDescription:
Engine.loadWorldContent();
Engine.loadLocationContent();
iTutorialSetText("This page lists all of the different locations you can currently " +
"travel to. Each location has something that you can do. " +
"There's a lot of content out in the world, make sure " +

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +0,0 @@
import { IMap } from "./types";
/**
* Display Location Content when visiting somewhere in the World
*/
// tslint:disable-next-line:variable-name
export const Locations: IMap<string> = {
// Cities
Aevum: "Aevum",
Chongqing: "Chongqing",
Ishima: "Ishima",
NewTokyo: "New Tokyo",
Sector12: "Sector-12",
Volhaven: "Volhaven",
// Aevum Locations
AevumAeroCorp: "AeroCorp",
AevumBachmanAndAssociates: "Bachman & Associates",
AevumClarkeIncorporated: "Clarke Incorporated",
AevumCrushFitnessGym: "Crush Fitness Gym",
AevumECorp: "ECorp",
AevumFulcrumTechnologies: "Fulcrum Technologies",
AevumGalacticCybersystems: "Galactic Cybersystems",
AevumNetLinkTechnologies: "NetLink Technologies",
AevumPolice: "Aevum Police Headquarters",
AevumRhoConstruction: "Rho Construction",
AevumSlums: "Aevum Slums",
AevumSnapFitnessGym: "Snap Fitness Gym",
AevumSummitUniversity: "Summit University",
AevumTravelAgency: "Aevum Travel Agency",
AevumWatchdogSecurity: "Watchdog Security",
// Chongqing locations
ChongqingKuaiGongInternational: "KuaiGong International",
ChongqingSlums: "Chongqing Slums",
ChongqingSolarisSpaceSystems: "Solaris Space Systems",
ChongqingTravelAgency: "Chongqing Travel Agency",
// Sector 12
Sector12AlphaEnterprises: "Alpha Enterprises",
Sector12BladeIndustries: "Blade Industries",
Sector12CIA: "Central Intelligence Agency",
Sector12CarmichaelSecurity: "Carmichael Security",
Sector12CityHall: "Sector-12 City Hall",
Sector12DeltaOne: "DeltaOne",
Sector12FoodNStuff: "FoodNStuff",
Sector12FourSigma: "Four Sigma",
Sector12IcarusMicrosystems: "Icarus Microsystems",
Sector12IronGym: "Iron Gym",
Sector12JoesGuns: "Joe's Guns",
Sector12MegaCorp: "MegaCorp",
Sector12NSA: "National Security Agency",
Sector12PowerhouseGym: "Powerhouse Gym",
Sector12RothmanUniversity: "Rothman University",
Sector12Slums: "Sector-12 Slums",
Sector12TravelAgency: "Sector-12 Travel Agency",
Sector12UniversalEnergy: "Universal Energy",
// New Tokyo
NewTokyoDefComm: "DefComm",
NewTokyoGlobalPharmaceuticals: "Global Pharmaceuticals",
NewTokyoNoodleBar: "Noodle Bar",
NewTokyoSlums: "New Tokyo Slums",
NewTokyoTravelAgency: "New Tokyo Travel Agency",
NewTokyoVitaLife: "VitaLife",
// Ishima
IshimaNovaMedical: "Nova Medical",
IshimaOmegaSoftware: "Omega Software",
IshimaSlums: "Ishima Slums",
IshimaStormTechnologies: "Storm Technologies",
IshimaTravelAgency: "Ishima Travel Agency",
// Volhaven
VolhavenCompuTek: "CompuTek",
VolhavenHeliosLabs: "Helios Labs",
VolhavenLexoCorp: "LexoCorp",
VolhavenMilleniumFitnessGym: "Millenium Fitness Gym",
VolhavenNWO: "NWO",
VolhavenOmniTekIncorporated: "OmniTek Incorporated",
VolhavenOmniaCybersystems: "Omnia Cybersystems",
VolhavenSlums: "Volhaven Slums",
VolhavenSysCoreSecurities: "SysCore Securities",
VolhavenTravelAgency: "Volhaven Travel Agency",
VolhavenZBInstituteOfTechnology: "ZB Institute of Technology",
// Generic locations
Hospital: "Hospital",
WorldStockExchange: "World Stock Exchange",
};

View File

@ -1,14 +1,8 @@
/**
* Map of all Cities in the game
* Key = City Name, Value = City object
*/
import { City } from "./City";
import { IMap } from "../types";
/**
* Display Location Content when visiting somewhere in the World
*/
// tslint:disable-next-line:variable-name
export const Cities: IMap<string> = {
Aevum: "Aevum",
Chongqing: "Chongqing",
Ishima: "Ishima",
NewTokyo: "New Tokyo",
Sector12: "Sector-12",
Volhaven: "Volhaven",
};
export const Cities: IMap<City> = {};

26
src/Locations/City.ts Normal file
View File

@ -0,0 +1,26 @@
/**
* Class representing a City in the game
*/
import { CityName } from "./data/CityNames";
import { LocationName } from "./data/LocationNames";
export class City {
/**
* List of all locations in this city
*/
locations: LocationName[];
/**
* Name of this city
*/
name: CityName;
constructor(name: CityName, locations: LocationName[]=[]) {
this.name = name;
this.locations = locations;
}
addLocation(loc: LocationName): void {
this.locations.push(loc);
}
}

82
src/Locations/Location.ts Normal file
View File

@ -0,0 +1,82 @@
/**
* Class representing a visitable location in the world
*/
import { CityName } from "./data/CityNames";
import { LocationName } from "./data/LocationNames";
import { LocationType } from "./LocationTypeEnum";
interface IInfiltrationMetadata {
baseRewardValue: number;
difficulty: number;
maxClearanceLevel: number;
startingSecurityLevel: number;
}
export interface IConstructorParams {
city?: CityName | null;
costMult?: number;
expMult?: number;
infiltrationData?: IInfiltrationMetadata;
name?: LocationName;
types?: LocationType[];
techVendorMaxRam?: number;
techVendorMinRam?: number;
}
export class Location {
/**
* Name of city this location is in. If this property is null, it means this i
* is a generic location that is available in all cities
*/
city: CityName | null = null;
/**
* Cost multiplier that influences how expensive a gym/university is
*/
costMult: number = 0;
/**
* Exp multiplier that influences how effective a gym/university is
*/
expMult: number = 0;
/**
* Companies can be infiltrated. This contains the data required for that
* infiltration event
*/
infiltrationData?: IInfiltrationMetadata;
/**
* Identifier for location
*/
name: LocationName = LocationName.Void;
/**
* List of what type(s) this location is. A location can be multiple types
* (e.g. company and tech vendor)
*/
types: LocationType[] = [];
/**
* Tech vendors allow you to purchase servers.
* This property defines the max RAM server you can purchase from this vendor
*/
techVendorMaxRam: number = 0;
/**
* Tech vendors allow you to purchase servers.
* This property defines the max RAM server you can purchase from this vendor
*/
techVendorMinRam: number = 0;
constructor(p: IConstructorParams) {
if (p.city) { this.city = p.city; }
if (p.costMult) { this.costMult = p.costMult; }
if (p.expMult) { this.expMult = p.expMult; }
if (p.infiltrationData) { this.infiltrationData = p.infiltrationData; }
if (p.name) { this.name = p.name; }
if (p.types) { this.types = p.types; }
if (p.techVendorMaxRam) { this.techVendorMaxRam = p.techVendorMaxRam; }
if (p.techVendorMinRam) { this.techVendorMinRam = p.techVendorMinRam; }
}
}

View File

@ -0,0 +1,14 @@
/**
* Enum defining the different types of possible locations
*/
export enum LocationType {
Company,
Gym,
Hospital,
Slums,
Special, // This location has special options/activities (e.g. Bladeburner, Re-sleeving)
StockMarket,
TechVendor,
TravelAgency,
University,
}

View File

@ -0,0 +1,56 @@
/**
* Map of all Locations in the game
* Key = Location name, value = Location object
*/
import { City } from "./City";
import { Cities } from "./Cities";
import { Location,
IConstructorParams } from "./Location";
import { CityName } from "./data/CityNames";
import { LocationsMetadata } from "./data/LocationsMetadata";
import { IMap } from "../types";
export const Locations: IMap<Location> = {};
/**
* Here, we'll initialize both Locations and Cities data. These can both
* be initialized from the `LocationsMetadata`
*/
function constructLocation(p: IConstructorParams): Location {
if (!p.name) {
throw new Error(`Invalid constructor parameters for Location. No 'name' property`);
}
if (Locations[p.name] instanceof Location) {
console.warn(`Property with name ${p.name} already exists and is being overwritten`);
}
Locations[p.name] = new Location(p);
return Locations[p.name];
}
// First construct all cities
Cities[CityName.Aevum] = new City(CityName.Aevum);
Cities[CityName.Chongqing] = new City(CityName.Chongqing);
Cities[CityName.Ishima] = new City(CityName.Ishima);
Cities[CityName.NewTokyo] = new City(CityName.NewTokyo);
Cities[CityName.Sector12] = new City(CityName.Sector12);
Cities[CityName.Volhaven] = new City(CityName.Volhaven);
// Then construct all locations, and add them to the cities as we go.
for (const metadata of LocationsMetadata) {
const loc = constructLocation(metadata);
const cityName = loc.city;
if (cityName === null) {
// Generic location, add to all cities
for (const city in Cities) {
Cities[city].addLocation(loc.name);
}
} else {
Cities[cityName].addLocation(loc.name);
}
}

View File

@ -0,0 +1,282 @@
/**
* Location and traveling-related helper functions.
* Mostly used for UI
*/
import { CONSTANTS } from "../Constants";
import { CityName } from "./data/CityNames";
import { IPlayer } from "../PersonObjects/IPlayer";
import { AllServers,
AddToAllServers } from "../Server/AllServers";
import { Server } from "../Server/Server";
import { getPurchaseServerCost,
purchaseRamForHomeComputer,
purchaseServer } from "../Server/ServerPurchases";
import { SpecialServerIps } from "../Server/SpecialServerIps";
import { Settings } from "../Settings/Settings";
import { numeralWrapper } from "../ui/numeralFormat";
import { dialogBoxCreate } from "../../utils/DialogBox";
import { createRandomIp } from "../../utils/IPAddress";
import { yesNoBoxGetYesButton,
yesNoBoxGetNoButton,
yesNoBoxClose,
yesNoBoxCreate,
yesNoTxtInpBoxGetYesButton,
yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxClose,
yesNoTxtInpBoxCreate } from "../../utils/YesNoBox";
import { createElement } from "../../utils/uiHelpers/createElement";
import { createPopup } from "../../utils/uiHelpers/createPopup";
import { createPopupCloseButton } from "../../utils/uiHelpers/createPopupCloseButton";
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
/**
* Create a pop-up box that lets the player confirm traveling to a different city
* If settings are configured to suppress this popup, just instantly travel
* The actual "Travel" implementation is implemented in the UI, and is passed in
* as an argument
*/
type TravelFunction = (to: CityName) => void;
export function createTravelPopup(destination: CityName, travelFn: TravelFunction) {
const cost = CONSTANTS.TravelCost;
if (Settings.SuppressTravelConfirmation) {
travelFn(destination);
return;
}
const yesBtn = yesNoBoxGetYesButton();
const noBtn = yesNoBoxGetNoButton();
if (yesBtn == null || noBtn == null) {
console.warn(`Could nto find YesNo pop-up box buttons`);
return;
}
yesBtn.innerHTML = "Yes";
yesBtn.addEventListener("click", () => {
yesNoBoxClose();
travelFn(destination);
return false;
});
noBtn.innerHTML = "No";
noBtn.addEventListener("click", () => {
yesNoBoxClose();
return false;
});
yesNoBoxCreate(`Would you like to travel to ${destination}? The trip will ` +
`cost ${numeralWrapper.formatMoney(cost)}`);
}
/**
* Create a pop-up box that lets the player purchase a server.
* @param ram - Amount of RAM (GB) on server
* @param p - Player object
*/
export function createPurchaseServerPopup(ram: number, p: IPlayer) {
const cost = getPurchaseServerCost(ram);
if (cost === Infinity) {
dialogBoxCreate("Something went wrong when trying to purchase this server. Please contact developer");
return;
}
var yesBtn = yesNoTxtInpBoxGetYesButton();
var noBtn = yesNoTxtInpBoxGetNoButton();
if (yesBtn == null || noBtn == null) { return; }
yesBtn.innerHTML = "Purchase Server";
noBtn.innerHTML = "Cancel";
yesBtn.addEventListener("click", function() {
purchaseServer(ram, p);
yesNoTxtInpBoxClose();
});
noBtn.addEventListener("click", function() {
yesNoTxtInpBoxClose();
});
yesNoTxtInpBoxCreate(
`Would you like to purchase a new server with ${ram} GB of RAM for ` +
`${numeralWrapper.formatMoney(cost)}?<br><br>Please enter the server hostname below:<br>`
);
}
/**
* Create a popup that lets the player start a Corporation
*/
export function createStartCorporationPopup(p: IPlayer) {
if (!p.canAccessCorporation() || p.hasCorporation) { return; }
const popupId = "create-corporation-popup";
const txt = createElement("p", {
innerHTML: "Would you like to start a corporation? This will require $150b for registration " +
"and initial funding. This $150b can either be self-funded, or you can obtain " +
"the seed money from the government in exchange for 500 million shares<br><br>" +
"If you would like to start one, please enter a name for your corporation below:",
});
const nameInput = createElement("input", {
placeholder: "Corporation Name",
}) as HTMLInputElement;
const selfFundedButton = createElement("button", {
class: "popup-box-button",
innerText: "Self-Fund",
clickListener: () => {
if (!p.canAfford(150e9)) {
dialogBoxCreate("You don't have enough money to create a corporation! You need $150b");
return false;
}
p.loseMoney(150e9);
const companyName = nameInput.value;
if (companyName == null || companyName == "") {
dialogBoxCreate("Invalid company name!");
return false;
}
p.startCorporation(companyName);
const worldHeader = document.getElementById("world-menu-header");
if (worldHeader instanceof HTMLElement) {
worldHeader.click(); worldHeader.click();
}
dialogBoxCreate("Congratulations! You just self-funded your own corporation. You can visit " +
"and manage your company in the City");
removeElementById(popupId);
return false;
}
});
const seedMoneyButton = createElement("button", {
class: "popup-box-button",
innerText: "Use Seed Money",
clickListener: () => {
const companyName = nameInput.value;
if (companyName == null || companyName == "") {
dialogBoxCreate("Invalid company name!");
return false;
}
p.startCorporation(companyName, 500e6);
const worldHeader = document.getElementById("world-menu-header");
if (worldHeader instanceof HTMLElement) {
worldHeader.click(); worldHeader.click();
}
dialogBoxCreate("Congratulations! You just started your own corporation with government seed money. " +
"You can visit and manage your company in the City");
removeElementById(popupId);
return false;
}
})
const cancelBtn = createPopupCloseButton(popupId, { class: "popup-box-button" });
createPopup(popupId, [txt, nameInput, cancelBtn, selfFundedButton, seedMoneyButton]);
nameInput.focus();
}
/**
* Create a popup that lets the player upgrade the cores on his/her home computer
* @param p - Player object
*/
export function createUpgradeHomeCoresPopup(p: IPlayer) {
const currentCores = p.getHomeComputer().cpuCores;
if (currentCores >= 8) { return; } // Max of 8 cores
//Cost of purchasing another cost is found by indexing this array with number of current cores
const allCosts = [0,
10e9, // 1->2 Cores - 10 bn
250e9, // 2->3 Cores - 250 bn
5e12, // 3->4 Cores - 5 trillion
100e12, // 4->5 Cores - 100 trillion
1e15, // 5->6 Cores - 1 quadrillion
20e15, // 6->7 Cores - 20 quadrillion
200e15]; // 7->8 Cores - 200 quadrillion
const cost: number = allCosts[currentCores];
const yesBtn = yesNoBoxGetYesButton();
const noBtn = yesNoBoxGetNoButton();
if (yesBtn == null || noBtn == null) { return; }
yesBtn.innerHTML = "Purchase";
yesBtn.addEventListener("click", ()=>{
if (!p.canAfford(cost)) {
dialogBoxCreate("You do not have enough money to purchase an additional CPU Core for your home computer!");
} else {
p.loseMoney(cost);
p.getHomeComputer().cpuCores++;
dialogBoxCreate("You purchased an additional CPU Core for your home computer! It now has " +
p.getHomeComputer().cpuCores + " cores.");
}
yesNoBoxClose();
});
noBtn.innerHTML = "Cancel";
noBtn.addEventListener("click", ()=>{
yesNoBoxClose();
});
yesNoBoxCreate("Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " +
"lets you start with an additional Core Node in Hacking Missions.<br><br>" +
"Purchasing an additional core (for a total of " + (p.getHomeComputer().cpuCores + 1) + ") will " +
"cost " + numeralWrapper.formatMoney(cost));
}
/**
* Create a popup that lets the player upgrade the RAM on his/her home computer
* @param p - Player object
*/
export function createUpgradeHomeRamPopup(p: IPlayer) {
const cost: number = p.getUpgradeHomeRamCost();
const ram: number = p.getHomeComputer().maxRam;
const yesBtn = yesNoBoxGetYesButton();
const noBtn = yesNoBoxGetNoButton();
if (yesBtn == null || noBtn == null) { return; }
yesBtn.innerText = "Purchase";
yesBtn.addEventListener("click", ()=>{
purchaseRamForHomeComputer(cost, p);
yesNoBoxClose();
});
noBtn.innerText = "Cancel";
noBtn.addEventListener("click", ()=>{
yesNoBoxClose();
});
yesNoBoxCreate("Would you like to purchase additional RAM for your home computer? <br><br>" +
"This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB. <br><br>" +
"This will cost " + numeralWrapper.format(cost, '$0.000a'));
}
/**
* Attempt to purchase a TOR router
* @param p - Player object
*/
export function purchaseTorRouter(p: IPlayer) {
if (!p.canAfford(CONSTANTS.TorRouterCost)) {
dialogBoxCreate("You cannot afford to purchase the Tor router");
return;
}
p.loseMoney(CONSTANTS.TorRouterCost);
const darkweb = new Server({
ip: createRandomIp(), hostname:"darkweb", organizationName:"",
isConnectedTo:false, adminRights:false, purchasedByPlayer:false, maxRam:1
});
AddToAllServers(darkweb);
SpecialServerIps.addIp("Darkweb Server", darkweb.ip);
p.getHomeComputer().serversOnNetwork.push(darkweb.ip);
darkweb.serversOnNetwork.push(p.getHomeComputer().ip);
dialogBoxCreate("You have purchased a Tor router!<br>" +
"You now have access to the dark web from your home computer<br>" +
"Use the scan/scan-analyze commands to search for the dark web connection.");
}

View File

@ -9,7 +9,7 @@ import { IMap } from "../types";
export function createCityMap<T>(initValue: T): IMap<T> {
const map: IMap<any> = {};
const cities = Object.values(Cities);
const cities = Object.keys(Cities);
for (let i = 0; i < cities.length; ++i) {
map[cities[i]] = initValue;
}

View File

@ -0,0 +1,12 @@
/**
* All possible Cities in the game. Names only, not actual "City" object
* Implemented as an enum for typing purposes
*/
export enum CityName {
Aevum = "Aevum",
Chongqing = "Chongqing",
Ishima = "Ishima",
NewTokyo = "New Tokyo",
Sector12 = "Sector-12",
Volhaven = "Volhaven",
};

View File

@ -0,0 +1,80 @@
/**
* Names of all locations
*/
export enum LocationName {
// Cities
Aevum = "Aevum",
Chongqing = "Chongqing",
Ishima = "Ishima",
NewTokyo = "New Tokyo",
Sector12 = "Sector-12",
Volhaven = "Volhaven",
// Aevum Locations
AevumAeroCorp = "AeroCorp",
AevumBachmanAndAssociates = "Bachman & Associates",
AevumClarkeIncorporated = "Clarke Incorporated",
AevumCrushFitnessGym = "Crush Fitness Gym",
AevumECorp = "ECorp",
AevumFulcrumTechnologies = "Fulcrum Technologies",
AevumGalacticCybersystems = "Galactic Cybersystems",
AevumNetLinkTechnologies = "NetLink Technologies",
AevumPolice = "Aevum Police Headquarters",
AevumRhoConstruction = "Rho Construction",
AevumSnapFitnessGym = "Snap Fitness Gym",
AevumSummitUniversity = "Summit University",
AevumWatchdogSecurity = "Watchdog Security",
// Chongqing locations
ChongqingKuaiGongInternational = "KuaiGong International",
ChongqingSolarisSpaceSystems = "Solaris Space Systems",
// Sector 12
Sector12AlphaEnterprises = "Alpha Enterprises",
Sector12BladeIndustries = "Blade Industries",
Sector12CIA = "Central Intelligence Agency",
Sector12CarmichaelSecurity = "Carmichael Security",
Sector12CityHall = "Sector-12 City Hall",
Sector12DeltaOne = "DeltaOne",
Sector12FoodNStuff = "FoodNStuff",
Sector12FourSigma = "Four Sigma",
Sector12IcarusMicrosystems = "Icarus Microsystems",
Sector12IronGym = "Iron Gym",
Sector12JoesGuns = "Joe's Guns",
Sector12MegaCorp = "MegaCorp",
Sector12NSA = "National Security Agency",
Sector12PowerhouseGym = "Powerhouse Gym",
Sector12RothmanUniversity = "Rothman University",
Sector12UniversalEnergy = "Universal Energy",
// New Tokyo
NewTokyoDefComm = "DefComm",
NewTokyoGlobalPharmaceuticals = "Global Pharmaceuticals",
NewTokyoNoodleBar = "Noodle Bar",
NewTokyoVitaLife = "VitaLife",
// Ishima
IshimaNovaMedical = "Nova Medical",
IshimaOmegaSoftware = "Omega Software",
IshimaStormTechnologies = "Storm Technologies",
// Volhaven
VolhavenCompuTek = "CompuTek",
VolhavenHeliosLabs = "Helios Labs",
VolhavenLexoCorp = "LexoCorp",
VolhavenMilleniumFitnessGym = "Millenium Fitness Gym",
VolhavenNWO = "NWO",
VolhavenOmniTekIncorporated = "OmniTek Incorporated",
VolhavenOmniaCybersystems = "Omnia Cybersystems",
VolhavenSysCoreSecurities = "SysCore Securities",
VolhavenZBInstituteOfTechnology = "ZB Institute of Technology",
// Generic locations
Hospital = "Hospital",
Slums = "The Slums",
TravelAgency = "Travel Agency",
WorldStockExchange = "World Stock Exchange",
// Default name for Location objects
Void = "The Void",
};

View File

@ -0,0 +1,502 @@
/**
* Metadata for constructing Location objects for all Locations
* in the game
*/
import { CityName } from "./CityNames";
import { LocationName } from "./LocationNames";
import { IConstructorParams } from "../Location";
import { LocationType } from "../LocationTypeEnum";
export const LocationsMetadata: IConstructorParams[] = [
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 32,
difficulty: 4.4,
maxClearanceLevel: 50,
startingSecurityLevel: 1350,
},
name: LocationName.AevumAeroCorp,
types: [LocationType.Company],
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 42,
difficulty: 4.1,
maxClearanceLevel: 60,
startingSecurityLevel: 1350,
},
name: LocationName.AevumBachmanAndAssociates,
types: [LocationType.Company],
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 34,
difficulty: 3.6,
maxClearanceLevel: 75,
startingSecurityLevel: 1800,
},
name: LocationName.AevumClarkeIncorporated,
types: [LocationType.Company],
},
{
city: CityName.Aevum,
costMult: 3,
expMult: 2,
name: LocationName.AevumCrushFitnessGym,
types: [LocationType.Gym],
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 116,
difficulty: 6,
maxClearanceLevel: 150,
startingSecurityLevel: 4800,
},
name: LocationName.AevumECorp,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 512,
techVendorMinRam: 128,
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 96,
difficulty: 6.2,
maxClearanceLevel: 100,
startingSecurityLevel: 4140,
},
name: LocationName.AevumFulcrumTechnologies,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 1024,
techVendorMinRam: 256,
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 30,
difficulty: 3.95,
maxClearanceLevel: 50,
startingSecurityLevel: 1260,
},
name: LocationName.AevumGalacticCybersystems,
types: [LocationType.Company],
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 10,
difficulty: 1.4,
maxClearanceLevel: 25,
startingSecurityLevel: 144,
},
name: LocationName.AevumNetLinkTechnologies,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 64,
techVendorMinRam: 8,
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 18,
difficulty: 2.2,
maxClearanceLevel: 25,
startingSecurityLevel: 565,
},
name: LocationName.AevumPolice,
types: [LocationType.Company],
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 16,
difficulty: 1.9,
maxClearanceLevel: 20,
startingSecurityLevel: 485,
},
name: LocationName.AevumRhoConstruction,
types: [LocationType.Company],
},
{
city: CityName.Aevum,
costMult: 10,
expMult: 5,
name: LocationName.AevumSnapFitnessGym,
types: [LocationType.Gym],
},
{
city: CityName.Aevum,
costMult: 4,
expMult: 3,
name: LocationName.AevumSummitUniversity,
types: [LocationType.University],
},
{
city: CityName.Aevum,
infiltrationData: {
baseRewardValue: 20,
difficulty: 3,
maxClearanceLevel: 30,
startingSecurityLevel: 690,
},
name: LocationName.AevumWatchdogSecurity,
types: [LocationType.Company],
},
{
city: CityName.Chongqing,
infiltrationData: {
baseRewardValue: 100,
difficulty: 6.1,
maxClearanceLevel: 100,
startingSecurityLevel: 4450,
},
name: LocationName.ChongqingKuaiGongInternational,
types: [LocationType.Company],
},
{
city: CityName.Chongqing,
infiltrationData: {
baseRewardValue: 52,
difficulty: 6,
maxClearanceLevel: 75,
startingSecurityLevel: 2915,
},
name: LocationName.ChongqingSolarisSpaceSystems,
types: [LocationType.Company],
},
{
city: CityName.Ishima,
infiltrationData: {
baseRewardValue: 20,
difficulty: 3.2,
maxClearanceLevel: 50,
startingSecurityLevel: 485,
},
name: LocationName.IshimaNovaMedical,
types: [LocationType.Company],
},
{
city: CityName.Ishima,
infiltrationData: {
baseRewardValue: 10,
difficulty: 1.6,
maxClearanceLevel: 40,
startingSecurityLevel: 130,
},
name: LocationName.IshimaOmegaSoftware,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 128,
techVendorMinRam: 4,
},
{
city: CityName.Ishima,
infiltrationData: {
baseRewardValue: 24,
difficulty: 4.1,
maxClearanceLevel: 100,
startingSecurityLevel: 570,
},
name: LocationName.IshimaStormTechnologies,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 512,
techVendorMinRam: 32,
},
{
city: CityName.NewTokyo,
infiltrationData: {
baseRewardValue: 28,
difficulty: 4,
maxClearanceLevel: 70,
startingSecurityLevel: 1050,
},
name: LocationName.NewTokyoDefComm,
types: [LocationType.Company],
},
{
city: CityName.NewTokyo,
infiltrationData: {
baseRewardValue: 24,
difficulty: 3.8,
maxClearanceLevel: 80,
startingSecurityLevel: 700,
},
name: LocationName.NewTokyoGlobalPharmaceuticals,
types: [LocationType.Company],
},
{
city: CityName.NewTokyo,
name: LocationName.NewTokyoNoodleBar,
types: [LocationType.Company],
},
{
city: CityName.NewTokyo,
infiltrationData: {
baseRewardValue: 22,
difficulty: 3.5,
maxClearanceLevel: 100,
startingSecurityLevel: 605,
},
name: LocationName.NewTokyoVitaLife,
types: [LocationType.Company, LocationType.Special],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 14,
difficulty: 2.25,
maxClearanceLevel: 40,
startingSecurityLevel: 200,
},
name: LocationName.Sector12AlphaEnterprises,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 8,
techVendorMinRam: 2,
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 46,
difficulty: 4.2,
maxClearanceLevel: 100,
startingSecurityLevel: 2160,
},
name: LocationName.Sector12BladeIndustries,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12CIA,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 18,
difficulty: 2.5,
maxClearanceLevel: 60,
startingSecurityLevel: 405,
},
name: LocationName.Sector12CarmichaelSecurity,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12CityHall,
types: [LocationType.Special],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 24,
difficulty: 4.3,
maxClearanceLevel: 50,
startingSecurityLevel: 700,
},
name: LocationName.Sector12DeltaOne,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12FoodNStuff,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 58,
difficulty: 7,
maxClearanceLevel: 100,
startingSecurityLevel: 1350,
},
name: LocationName.Sector12FourSigma,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 32,
difficulty: 5.4,
maxClearanceLevel: 70,
startingSecurityLevel: 730,
},
name: LocationName.Sector12IcarusMicrosystems,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
expMult: 1,
costMult: 1,
name: LocationName.Sector12IronGym,
types: [LocationType.Gym],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 8,
difficulty: 1.8,
maxClearanceLevel: 20,
startingSecurityLevel: 120,
},
name: LocationName.Sector12JoesGuns,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 114,
difficulty: 6.75,
maxClearanceLevel: 125,
startingSecurityLevel: 4500,
},
name: LocationName.Sector12MegaCorp,
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12NSA,
types: [LocationType.Company, LocationType.Special],
},
{
city: CityName.Sector12,
costMult: 20,
expMult: 10,
name: LocationName.Sector12PowerhouseGym,
types: [LocationType.Gym],
},
{
city: CityName.Sector12,
costMult: 3,
expMult: 2,
name: LocationName.Sector12RothmanUniversity,
types: [LocationType.University],
},
{
city: CityName.Sector12,
infiltrationData: {
baseRewardValue: 24,
difficulty: 4.3,
maxClearanceLevel: 50,
startingSecurityLevel: 700,
},
name: LocationName.Sector12UniversalEnergy,
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 12,
difficulty: 2.1,
maxClearanceLevel: 60,
startingSecurityLevel: 195,
},
name: LocationName.VolhavenCompuTek,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 256,
techVendorMinRam: 8,
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 28,
difficulty: 3,
maxClearanceLevel: 75,
startingSecurityLevel: 1080,
},
name: LocationName.VolhavenHeliosLabs,
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 14,
difficulty: 2,
maxClearanceLevel: 60,
startingSecurityLevel: 340,
},
name: LocationName.VolhavenLexoCorp,
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
costMult: 7,
expMult: 4,
name: LocationName.VolhavenMilleniumFitnessGym,
types: [LocationType.Gym],
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 56,
difficulty: 6.8,
maxClearanceLevel: 200,
startingSecurityLevel: 1460,
},
name: LocationName.VolhavenNWO,
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 44,
difficulty: 4.4,
maxClearanceLevel: 100,
startingSecurityLevel: 1215,
},
name: LocationName.VolhavenOmniTekIncorporated,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 1024,
techVendorMinRam: 128,
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 28,
difficulty: 4.9,
maxClearanceLevel: 90,
startingSecurityLevel: 725,
},
name: LocationName.VolhavenOmniaCybersystems,
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
infiltrationData: {
baseRewardValue: 18,
difficulty: 2.4,
maxClearanceLevel: 75,
startingSecurityLevel: 430,
},
name: LocationName.VolhavenSysCoreSecurities,
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
costMult: 5,
expMult: 4,
name: LocationName.VolhavenZBInstituteOfTechnology,
types: [LocationType.University],
},
{
city: null,
name: LocationName.Hospital,
types: [LocationType.Hospital],
},
{
city: null,
name: LocationName.Slums,
types: [LocationType.Slums],
},
{
city: null,
name: LocationName.TravelAgency,
types: [LocationType.TravelAgency],
},
{
city: null,
name: LocationName.WorldStockExchange,
types: [LocationType.StockMarket],
},
];

View File

@ -0,0 +1,48 @@
/**
* React Component for a button that's used to apply for a job
*/
import * as React from "react";
import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition";
import { getJobRequirementText } from "../../Company/GetJobRequirementText";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
company: Company;
entryPosType: CompanyPosition;
onClick: (e: React.MouseEvent<HTMLElement>) => void;
p: IPlayer;
style?: object;
text: string;
}
export class ApplyToJobButton extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
this.getJobRequirementTooltip = this.getJobRequirementTooltip.bind(this);
}
getJobRequirementTooltip(): string {
const pos = this.props.p.getNextCompanyPosition(this.props.company, this.props.entryPosType);
if (pos == null) { return "" };
if (!this.props.company.hasPosition(pos)) { return ""; }
return getJobRequirementText(this.props.company, pos, true);
}
render() {
return (
<StdButton
onClick={this.props.onClick}
style={this.props.style}
text={this.props.text}
tooltip={this.getJobRequirementTooltip()}
/>
)
}
}

34
src/Locations/ui/City.tsx Normal file
View File

@ -0,0 +1,34 @@
/**
* React Component for displaying a City's UI.
* This UI shows all of the available locations in the city, and lets the player
* visit those locations
*/
import * as React from "react";
import { City } from "../City";
import { LocationName } from "../data/LocationNames";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
city: City;
enterLocation: (to: LocationName) => void;
}
export class LocationCity extends React.Component<IProps, any> {
render() {
const locationButtons = this.props.city.locations.map((locName) => {
return (
<li key={locName}>
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} />
</li>
)
});
return (
<ul>
{locationButtons}
</ul>
)
}
}

View File

@ -0,0 +1,371 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a company
*
* This subcomponent renders all of the buttons for applying to jobs at a company
*/
import * as React from "react";
import { ApplyToJobButton } from "./ApplyToJobButton";
import { Location } from "../Location";
import { Locations } from "../Locations";
import { LocationName } from "../data/LocationNames";
import { IEngine } from "../../IEngine";
import { beginInfiltration } from "../../Infiltration";
import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition";
import { CompanyPositions } from "../../Company/CompanyPositions";
import * as posNames from "../../Company/data/companypositionnames";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { numeralWrapper } from "../../ui/numeralFormat";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
engine: IEngine;
locName: LocationName;
p: IPlayer;
}
type IState = {
employedHere: boolean;
}
export class CompanyLocation extends React.Component<IProps, IState> {
/**
* We'll keep a reference to the Company that this component is being rendered for,
* so we don't have to look it up every time
*/
company: Company;
/**
* CompanyPosition object for the job that the player holds at this company
* (if he has one)
*/
companyPosition: CompanyPosition | null = null;
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
/**
* Reference to the Location that this component is being rendered for
*/
location: Location;
/**
* Name of company position that player holds, if applicable
*/
jobTitle: string | null = null;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.applyForAgentJob = this.applyForAgentJob.bind(this);
this.applyForBusinessConsultantJob = this.applyForBusinessConsultantJob.bind(this);
this.applyForBusinessJob = this.applyForBusinessJob.bind(this);
this.applyForEmployeeJob = this.applyForEmployeeJob.bind(this);
this.applyForItJob = this.applyForItJob.bind(this);
this.applyForPartTimeEmployeeJob = this.applyForPartTimeEmployeeJob.bind(this);
this.applyForPartTimeWaiterJob = this.applyForPartTimeWaiterJob.bind(this);
this.applyForSecurityJob = this.applyForSecurityJob.bind(this);
this.applyForSoftwareConsultantJob = this.applyForSoftwareConsultantJob.bind(this);
this.applyForSoftwareJob = this.applyForSoftwareJob.bind(this);
this.applyForWaiterJob = this.applyForWaiterJob.bind(this);
this.startInfiltration = this.startInfiltration.bind(this);
this.work = this.work.bind(this);
this.location = Locations[props.locName];
if (this.location == null) {
throw new Error(`CompanyLocation component constructed with invalid location: ${props.locName}`);
}
this.company = Companies[props.locName];
if (this.company == null) {
throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`);
}
this.state = {
employedHere: false,
}
this.checkIfEmployedHere(false);
}
applyForAgentJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForAgentJob();
this.checkIfEmployedHere(true);
}
applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForBusinessConsultantJob();
this.checkIfEmployedHere(true);
}
applyForBusinessJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForBusinessJob();
this.checkIfEmployedHere(true);
}
applyForEmployeeJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForEmployeeJob();
this.checkIfEmployedHere(true);
}
applyForItJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForItJob();
this.checkIfEmployedHere(true);
}
applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForPartTimeEmployeeJob();
this.checkIfEmployedHere(true);
}
applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForPartTimeWaiterJob();
this.checkIfEmployedHere(true);
}
applyForSecurityJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSecurityJob();
this.checkIfEmployedHere(true);
}
applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSoftwareConsultantJob();
this.checkIfEmployedHere(true);
}
applyForSoftwareJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSoftwareJob();
this.checkIfEmployedHere(true);
}
applyForWaiterJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForWaiterJob();
this.checkIfEmployedHere(true);
}
checkIfEmployedHere(updateState=false) {
this.jobTitle = this.props.p.jobs[this.props.locName];
if (this.jobTitle != null) {
this.companyPosition = CompanyPositions[this.jobTitle];
}
if (updateState) {
this.setState({
employedHere: this.jobTitle != null
});
}
}
startInfiltration(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
const loc = this.location;
this.props.engine.loadInfiltrationContent();
const data = loc.infiltrationData;
if (data == null) { return false; }
beginInfiltration(this.props.locName, data.startingSecurityLevel, data.baseRewardValue, data.maxClearanceLevel, data.difficulty);
}
work(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
const pos = this.companyPosition;
if (pos instanceof CompanyPosition) {
if (pos.isPartTimeJob() || pos.isSoftwareConsultantJob() || pos.isBusinessConsultantJob()) {
this.props.p.startWorkPartTime(this.props.locName);
} else {
this.props.p.startWork(this.props.locName);
}
}
}
render() {
const isEmployedHere = this.jobTitle != null;
const favorGain = this.company.getFavorGain();
return (
<div>
{
isEmployedHere &&
<div>
<p>Job Title: {this.jobTitle}</p>
<p>--------------------</p>
<p className={"tooltip"}>
Company reputation: {numeralWrapper.format(this.company.playerReputation, "0,0.000")}
<span className={"tooltiptext"}>
You will earn {numeralWrapper.format(favorGain[0], "0,0")} company
favor upon resetting after installing Augmentations
</span>
</p>
<p>--------------------</p>
<p className={"tooltip"}>
Company Favor: {numeralWrapper.format(this.company.favor, "0,0")}
<span className={"tooltiptext"}>
Company favor increases the rate at which you earn reputation for this company by
1% per favor. Company favor is gained whenever you reset after installing Augmentations. The amount
of favor you gain depends on how much reputation you have with the comapny.
</span>
</p>
<StdButton
id={"foo-work-button-id"}
onClick={this.work}
style={this.btnStyle}
text={"Work"}
/>
</div>
}
{
this.company.hasAgentPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.AgentCompanyPositions[0]]}
onClick={this.applyForAgentJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for Agent Job"}
/>
}
{
this.company.hasBusinessConsultantPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]]}
onClick={this.applyForBusinessConsultantJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for Business Consultant Job"}
/>
}
{
this.company.hasBusinessPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.BusinessCompanyPositions[0]]}
onClick={this.applyForBusinessJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for Business Job"}
/>
}
{
this.company.hasEmployeePositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[1]]}
onClick={this.applyForEmployeeJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply to be an Employee"}
/>
}
{
this.company.hasEmployeePositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[1]]}
onClick={this.applyForPartTimeEmployeeJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply to be a part-time Employee"}
/>
}
{
this.company.hasITPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.ITCompanyPositions[0]]}
onClick={this.applyForItJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for IT Job"}
/>
}
{
this.company.hasSecurityPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.SecurityCompanyPositions[2]]}
onClick={this.applyForSecurityJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for Security Job"}
/>
}
{
this.company.hasSoftwareConsultantPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]]}
onClick={this.applyForSoftwareConsultantJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for Software Consultant Job"}
/>
}
{
this.company.hasSoftwarePositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.SoftwareCompanyPositions[0]]}
onClick={this.applyForSoftwareJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply for Software Job"}
/>
}
{
this.company.hasWaiterPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[0]]}
onClick={this.applyForWaiterJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply to be a Waiter"}
/>
}
{
this.company.hasWaiterPositions() &&
<ApplyToJobButton
company={this.company}
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[0]]}
onClick={this.applyForPartTimeWaiterJob}
p={this.props.p}
style={this.btnStyle}
text={"Apply to be a part-time Waiter"}
/>
}
{
(this.location.infiltrationData != null) &&
<StdButton
onClick={this.startInfiltration}
style={this.btnStyle}
text={"Infiltration Company"}
/>
}
</div>
)
}
}

View File

@ -0,0 +1,148 @@
/**
* React Component for displaying a location's UI
*
* This is a "router" component of sorts, meaning it deduces the type of
* location that is being rendered and then creates the proper component(s) for that.
*/
import * as React from "react";
import { CompanyLocation } from "./CompanyLocation";
import { GymLocation } from "./GymLocation";
import { HospitalLocation } from "./HospitalLocation";
import { SlumsLocation } from "./SlumsLocation";
import { SpecialLocation } from "./SpecialLocation";
import { TechVendorLocation } from "./TechVendorLocation";
import { TravelAgencyLocation } from "./TravelAgencyLocation";
import { UniversityLocation } from "./UniversityLocation";
import { Location } from "../Location";
import { LocationType } from "../LocationTypeEnum";
import { CityName } from "../data/CityNames";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
engine: IEngine;
loc: Location;
p: IPlayer;
returnToCity: () => void;
travel: (to: CityName) => void;
}
export class GenericLocation extends React.Component<IProps, any> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
}
/**
* Determine what needs to be rendered for this location based on the locations
* type. Returns an array of React components that should be rendered
*/
getLocationSpecificContent(): React.ReactNode[] {
const content: React.ReactNode[] = [];
if (this.props.loc.types.includes(LocationType.Company)) {
content.push(
<CompanyLocation
engine={this.props.engine}
key={"companylocation"}
locName={this.props.loc.name}
p={this.props.p}
/>
)
}
if (this.props.loc.types.includes(LocationType.Gym)) {
content.push(
<GymLocation
key={"gymlocation"}
loc={this.props.loc}
p={this.props.p}
/>
)
}
if (this.props.loc.types.includes(LocationType.Hospital)) {
content.push(
<HospitalLocation
key={"hospitallocation"}
p={this.props.p}
/>
)
}
if (this.props.loc.types.includes(LocationType.Slums)) {
content.push(
<SlumsLocation
key={"slumslocation"}
p={this.props.p}
/>
)
}
if (this.props.loc.types.includes(LocationType.Special)) {
content.push(
<SpecialLocation
engine={this.props.engine}
key={"speciallocation"}
loc={this.props.loc}
p={this.props.p}
/>
)
}
if (this.props.loc.types.includes(LocationType.TechVendor)) {
content.push(
<TechVendorLocation
key={"techvendorlocation"}
loc={this.props.loc}
p={this.props.p}
/>
)
}
if (this.props.loc.types.includes(LocationType.TravelAgency)) {
content.push(
<TravelAgencyLocation
key={"travelagencylocation"}
p={this.props.p}
travel={this.props.travel}
/>
)
}
if (this.props.loc.types.includes(LocationType.University)) {
content.push(
<UniversityLocation
key={"universitylocation"}
loc={this.props.loc}
p={this.props.p}
/>
)
}
return content;
}
render() {
const locContent: React.ReactNode[] = this.getLocationSpecificContent();
return (
<div>
<StdButton onClick={this.props.returnToCity} style={this.btnStyle} text={"Return to World"} />
<h1>{this.props.loc.name}</h1>
{locContent}
</div>
)
}
}

View File

@ -0,0 +1,89 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a gym
*
* This subcomponent renders all of the buttons for training at the gym
*/
import * as React from "react";
import { Location } from "../Location";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { numeralWrapper } from "../../ui/numeralFormat";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
loc: Location;
p: IPlayer;
}
export class GymLocation extends React.Component<IProps, any> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.trainStrength = this.trainStrength.bind(this);
this.trainDefense = this.trainDefense.bind(this);
this.trainDexterity = this.trainDexterity.bind(this);
this.trainAgility = this.trainAgility.bind(this);
}
train(stat: string) {
const loc = this.props.loc;
this.props.p.startClass(loc.costMult, loc.expMult, stat);
}
trainStrength() {
return this.train(CONSTANTS.ClassGymStrength);
}
trainDefense() {
return this.train(CONSTANTS.ClassGymDefense);
}
trainDexterity() {
return this.train(CONSTANTS.ClassGymDexterity);
}
trainAgility() {
return this.train(CONSTANTS.ClassGymAgility);
}
render() {
const costMult: number = this.props.loc.costMult;
const cost = CONSTANTS.ClassGymBaseCost * costMult;
return (
<div>
<StdButton
onClick={this.trainStrength}
style={this.btnStyle}
text={`Train Strength (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
<StdButton
onClick={this.trainDefense}
style={this.btnStyle}
text={`Train Defense (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
<StdButton
onClick={this.trainDexterity}
style={this.btnStyle}
text={`Train Dexterity (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
<StdButton
onClick={this.trainAgility}
style={this.btnStyle}
text={`Train Agility (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
</div>
)
}
}

View File

@ -0,0 +1,76 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a hospital
*
* This subcomponent renders all of the buttons for hospital options
*/
import * as React from "react";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { numeralWrapper } from "../../ui/numeralFormat";
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
import { dialogBoxCreate } from "../../../utils/DialogBox";
type IProps = {
p: IPlayer;
}
type IState = {
currHp: number;
}
export class HospitalLocation extends React.Component<IProps, IState> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.getCost = this.getCost.bind(this);
this.getHealed = this.getHealed.bind(this);
this.state = {
currHp: this.props.p.hp,
}
}
getCost(): number {
return (this.props.p.max_hp - this.props.p.hp) * CONSTANTS.HospitalCostPerHp;
}
getHealed(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
if (this.props.p.hp < 0) { this.props.p.hp = 0; }
if (this.props.p.hp >= this.props.p.max_hp) { return; }
const cost = this.getCost();
this.props.p.loseMoney(cost);
this.props.p.hp = this.props.p.max_hp;
// This just forces a re-render to update the cost
this.setState({
currHp: this.props.p.hp,
});
dialogBoxCreate(`You were healed to full health! The hospital billed you for ${numeralWrapper.formatMoney(cost)}`);
}
render() {
const cost = this.getCost();
return (
<AutoupdatingStdButton
onClick={this.getHealed}
style={this.btnStyle}
text={`Get treatment for wounds - ${numeralWrapper.formatMoney(cost)}`}
/>
)
}
}

151
src/Locations/ui/Root.tsx Normal file
View File

@ -0,0 +1,151 @@
/**
* Root React Component for displaying overall Location UI
*/
import * as React from "react";
import { LocationCity } from "./City";
import { GenericLocation } from "./GenericLocation";
import { Cities } from "../Cities";
import { Locations } from "../Locations";
import { LocationType } from "../LocationTypeEnum";
import { CityName } from "../data/CityNames";
import { LocationName } from "../data/LocationNames";
import { CONSTANTS } from "../../Constants";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { dialogBoxCreate } from "../../../utils/DialogBox";
type IProps = {
initiallyInCity?: boolean;
engine: IEngine;
p: IPlayer;
}
type IState = {
city: CityName;
inCity: boolean;
location: LocationName;
}
export class LocationRoot extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
city: props.p.city,
inCity: props.initiallyInCity == null ? true : props.initiallyInCity,
location: props.p.location,
}
this.enterLocation = this.enterLocation.bind(this);
this.returnToCity = this.returnToCity.bind(this);
this.travel = this.travel.bind(this);
}
enterLocation(to: LocationName): void {
this.props.p.gotoLocation(to);
this.setState({
inCity: false,
location: to,
});
}
/**
* Click listener for a button that lets the player go from a specific location
* back to the city
*/
returnToCity(): void {
this.setState({
inCity: true,
});
}
/**
* Render UI for a city
*/
renderCity(): React.ReactNode {
const city = Cities[this.state.city];
if (city == null) {
throw new Error(`Invalid city when rendering UI: ${this.state.city}`);
}
return (
<div>
<h2>{this.state.city}</h2>
<LocationCity city={city} enterLocation={this.enterLocation} />
</div>
)
}
/**
* Render UI for a specific location
*/
renderLocation(): React.ReactNode {
const loc = Locations[this.state.location];
if (loc == null) {
throw new Error(`Invalid location when rendering UI: ${this.state.location}`);
}
if (loc.types.includes(LocationType.StockMarket)) {
this.props.engine.loadStockMarketContent();
}
return (
<GenericLocation
engine={this.props.engine}
loc={loc}
p={this.props.p}
returnToCity={this.returnToCity}
travel={this.travel}
/>
)
}
/**
* Travel to a different city
* @param {CityName} to - Destination city
*/
travel(to: CityName): void {
const p = this.props.p;
const cost = CONSTANTS.TravelCost;
if (!p.canAfford(cost)) {
dialogBoxCreate(`You cannot afford to travel to ${to}`);
return;
}
p.loseMoney(cost);
p.travel(to);
dialogBoxCreate(`You are now in ${to}!`);
// Dynamically update main menu
if (p.firstTimeTraveled === false) {
p.firstTimeTraveled = true;
const travelTab = document.getElementById("travel-tab");
const worldHeader = document.getElementById("world-menu-header");
if (travelTab != null && worldHeader !== null) {
travelTab.style.display = "list-item";
worldHeader.click(); worldHeader.click();
}
}
if (this.props.p.travel(to)) {
this.setState({
inCity: true,
city: to
});
}
}
render() {
if (this.state.inCity) {
return this.renderCity();
} else {
return this.renderLocation();
}
}
}

View File

@ -0,0 +1,206 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a slum
*
* This subcomponent renders all of the buttons for committing crimes
*/
import * as React from "react";
import { Crimes } from "../../Crime/Crimes";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { numeralWrapper } from "../../ui/numeralFormat";
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
type IProps = {
p: IPlayer;
}
export class SlumsLocation extends React.Component<IProps, any> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.shoplift = this.shoplift.bind(this);
this.robStore = this.robStore.bind(this);
this.mug = this.mug.bind(this);
this.larceny = this.larceny.bind(this);
this.dealDrugs = this.dealDrugs.bind(this);
this.bondForgery = this.bondForgery.bind(this);
this.traffickArms = this.traffickArms.bind(this);
this.homicide = this.homicide.bind(this);
this.grandTheftAuto = this.grandTheftAuto.bind(this);
this.kidnap = this.kidnap.bind(this);
this.assassinate = this.assassinate.bind(this);
this.heist = this.heist.bind(this);
}
shoplift(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Shoplift.commit(this.props.p);
}
robStore(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.RobStore.commit(this.props.p);
}
mug(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Mug.commit(this.props.p);
}
larceny(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Larceny.commit(this.props.p);
}
dealDrugs(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.DealDrugs.commit(this.props.p);
}
bondForgery(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.BondForgery.commit(this.props.p);
}
traffickArms(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.TraffickArms.commit(this.props.p);
}
homicide(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Homicide.commit(this.props.p);
}
grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.GrandTheftAuto.commit(this.props.p);
}
kidnap(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Kidnap.commit(this.props.p);
}
assassinate(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Assassination.commit(this.props.p);
}
heist(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.Heist.commit(this.props.p);
}
render() {
const shopliftChance = Crimes.Shoplift.successRate(this.props.p);
const robStoreChance = Crimes.RobStore.successRate(this.props.p);
const mugChance = Crimes.Mug.successRate(this.props.p);
const larcenyChance = Crimes.Larceny.successRate(this.props.p);
const drugsChance = Crimes.DealDrugs.successRate(this.props.p);
const bondChance = Crimes.BondForgery.successRate(this.props.p);
const armsChance = Crimes.TraffickArms.successRate(this.props.p);
const homicideChance = Crimes.Homicide.successRate(this.props.p);
const gtaChance = Crimes.GrandTheftAuto.successRate(this.props.p);
const kidnapChance = Crimes.Kidnap.successRate(this.props.p);
const assassinateChance = Crimes.Assassination.successRate(this.props.p);
const heistChance = Crimes.Heist.successRate(this.props.p);
return (
<div>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.shoplift}
style={this.btnStyle}
text={`Shoplift (${numeralWrapper.formatPercentage(shopliftChance)} chance of success)`}
tooltip={"Attempt to shoplift from a low-end retailer"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.robStore}
style={this.btnStyle}
text={`Rob store (${numeralWrapper.formatPercentage(robStoreChance)} chance of success)`}
tooltip={"Attempt to commit armed robbery on a high-end store"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.mug}
style={this.btnStyle}
text={`Mug someone (${numeralWrapper.formatPercentage(mugChance)} chance of success)`}
tooltip={"Attempt to mug a random person on the street"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.larceny}
style={this.btnStyle}
text={`Larceny (${numeralWrapper.formatPercentage(larcenyChance)} chance of success)`}
tooltip={"Attempt to rob property from someone's house"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.dealDrugs}
style={this.btnStyle}
text={`Deal Drugs (${numeralWrapper.formatPercentage(drugsChance)} chance of success)`}
tooltip={"Attempt to deal drugs"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.bondForgery}
style={this.btnStyle}
text={`Bond Forgery (${numeralWrapper.formatPercentage(bondChance)} chance of success)`}
tooltip={"Attempt to forge corporate bonds"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.traffickArms}
style={this.btnStyle}
text={`Traffick illegal Arms (${numeralWrapper.formatPercentage(armsChance)} chance of success)`}
tooltip={"Attempt to smuggle illegal arms into the city"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.homicide}
style={this.btnStyle}
text={`Homicide (${numeralWrapper.formatPercentage(homicideChance)} chance of success)`}
tooltip={"Attempt to murder a random person on the street"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.grandTheftAuto}
style={this.btnStyle}
text={`Grand theft Auto (${numeralWrapper.formatPercentage(gtaChance)} chance of success)`}
tooltip={"Attempt to commit grand theft auto"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.kidnap}
style={this.btnStyle}
text={`Kidnap and Ransom (${numeralWrapper.formatPercentage(kidnapChance)} chance of success)`}
tooltip={"Attempt to kidnap and ransom a high-profile-target"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.assassinate}
style={this.btnStyle}
text={`Assassinate (${numeralWrapper.formatPercentage(assassinateChance)} chance of success)`}
tooltip={"Attempt to assassinate a high-profile target"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.heist}
style={this.btnStyle}
text={`Heist (${numeralWrapper.formatPercentage(heistChance)} chance of success)`}
tooltip={"Attempt to pull off the ultimate heist"}
/>
</div>
)
}
}

View File

@ -0,0 +1,149 @@
/**
* React Subcomponent for displaying a location's UI, when that location has special
* actions/options/properties
*
* Examples:
* - Bladeburner @ NSA
* - Re-sleeving @ VitaLife
* - Create Corporation @ City Hall
*
* This subcomponent creates all of the buttons for interacting with those special
* properties
*/
import * as React from "react";
import { Location } from "../Location";
import { createStartCorporationPopup } from "../LocationsHelpers";
import { LocationName } from "../data/LocationNames";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
import { StdButton } from "../../ui/React/StdButton";
import { dialogBoxCreate } from "../../../utils/DialogBox";
type IProps = {
engine: IEngine;
loc: Location;
p: IPlayer;
}
type IState = {
inBladeburner: boolean;
}
export class SpecialLocation extends React.Component<IProps, IState> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.createCorporationPopup = this.createCorporationPopup.bind(this);
this.handleBladeburner = this.handleBladeburner.bind(this);
this.handleResleeving = this.handleResleeving.bind(this);
this.state = {
inBladeburner: this.props.p.inBladeburner(),
}
}
/**
* Click handler for "Create Corporation" button at Sector-12 City Hall
*/
createCorporationPopup() {
createStartCorporationPopup(this.props.p);
}
/**
* Click handler for Bladeburner button at Sector-12 NSA
*/
handleBladeburner() {
const p = this.props.p;
if (p.inBladeburner()) {
// Enter Bladeburner division
this.props.engine.loadBladeburnerContent();
} else {
// Apply for Bladeburner division
if (p.strength >= 100 && p.defense >= 100 && p.dexterity >= 100 && p.agility >= 100) {
p.startBladeburner({ new: true });
dialogBoxCreate("You have been accepted into the Bladeburner division!");
this.setState({
inBladeburner: true,
});
const worldHeader = document.getElementById("world-menu-header");
if (worldHeader instanceof HTMLElement) {
worldHeader.click(); worldHeader.click();
}
} else {
dialogBoxCreate("Rejected! Please apply again when you have 100 of each combat stat (str, def, dex, agi)");
}
}
}
/**
* Click handler for Resleeving button at New Tokyo VitaLife
*/
handleResleeving() {
this.props.engine.loadResleevingContent();
}
renderBladeburner(): React.ReactNode {
if (!this.props.p.canAccessBladeburner()) { return null; }
const text = this.state.inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
return (
<StdButton
onClick={this.handleBladeburner}
style={this.btnStyle}
text={text}
/>
)
}
renderCreateCorporation(): React.ReactNode {
if (!this.props.p.canAccessCorporation()) { return null; }
return (
<AutoupdatingStdButton
disabled={!this.props.p.canAccessCorporation() || this.props.p.hasCorporation()}
onClick={this.createCorporationPopup}
style={this.btnStyle}
text={"Create a Corporation"}
/>
)
}
renderResleeving(): React.ReactNode {
if (!this.props.p.canAccessResleeving()) { return null; }
return (
<StdButton
onClick={this.handleResleeving}
style={this.btnStyle}
text={"Re-Sleeve"}
/>
)
}
render() {
switch (this.props.loc.name) {
case LocationName.NewTokyoVitaLife: {
return this.renderResleeving();
}
case LocationName.Sector12CityHall: {
return this.renderCreateCorporation();
}
case LocationName.Sector12NSA: {
return this.renderBladeburner();
}
default:
console.error(`Location ${this.props.loc.name} doesn't have any special properties`);
break;
}
}
}

View File

@ -0,0 +1,106 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a tech vendor
*
* This subcomponent renders all of the buttons for purchasing things from tech vendors
*/
import * as React from "react";
import { Location } from "../Location";
import { createPurchaseServerPopup,
createUpgradeHomeCoresPopup,
createUpgradeHomeRamPopup,
purchaseTorRouter } from "../LocationsHelpers";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { getPurchaseServerCost } from "../../Server/ServerPurchases";
import { numeralWrapper } from "../../ui/numeralFormat";
import { StdButtonPurchased } from "../../ui/React/StdButtonPurchased";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
loc: Location;
p: IPlayer;
}
export class TechVendorLocation extends React.Component<IProps, any> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.state = {
torPurchased: props.p.hasTorRouter(),
}
this.createUpgradeHomeCoresPopup = this.createUpgradeHomeCoresPopup.bind(this);
this.createUpgradeHomeRamPopup = this.createUpgradeHomeRamPopup.bind(this);
this.purchaseTorRouter = this.purchaseTorRouter.bind(this);
}
createUpgradeHomeCoresPopup() {
createUpgradeHomeCoresPopup(this.props.p);
}
createUpgradeHomeRamPopup() {
createUpgradeHomeRamPopup(this.props.p);
}
purchaseTorRouter() {
purchaseTorRouter(this.props.p);
}
render() {
const loc: Location = this.props.loc;
const purchaseServerButtons: React.ReactNode[] = [];
for (let i = loc.techVendorMinRam; i <= loc.techVendorMaxRam; i *= 2) {
const cost = getPurchaseServerCost(i);
purchaseServerButtons.push(
<StdButton
key={i}
onClick={() => createPurchaseServerPopup(i, this.props.p)}
style={this.btnStyle}
text={`Purchase ${i}GB Server - ${numeralWrapper.formatMoney(cost)}`}
/>
)
}
return (
<div>
{purchaseServerButtons}
{
this.state.torPurchased ? (
<StdButtonPurchased
style={this.btnStyle}
text={"TOR Router - Purchased"}
/>
) : (
<StdButton
onClick={this.purchaseTorRouter}
style={this.btnStyle}
text={`Purchase TOR Router - ${numeralWrapper.formatMoney(CONSTANTS.TorRouterCost)}`}
/>
)
}
<StdButton
onClick={this.createUpgradeHomeRamPopup}
style={this.btnStyle}
text={`Purchase additional RAM for Home computer`}
/>
<StdButton
onClick={this.createUpgradeHomeCoresPopup}
style={this.btnStyle}
text={`Purchase additional Core for Home computer`}
/>
</div>
)
}
}

View File

@ -0,0 +1,62 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a Travel Agency
*
* This subcomponent renders all of the buttons for traveling to different cities
*/
import * as React from "react";
import { CityName } from "../data/CityNames";
import { createTravelPopup } from "../LocationsHelpers";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { numeralWrapper } from "../../ui/numeralFormat";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
p: IPlayer;
travel: (to: CityName) => void;
}
export class TravelAgencyLocation extends React.Component<IProps, any> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
}
render() {
const travelBtns: React.ReactNode[] = [];
for (const key in CityName) {
const city = CityName[key];
// Skip current city
if (city === this.props.p.city) { continue; }
travelBtns.push(
<StdButton
key={city}
onClick={createTravelPopup.bind(null, city, this.props.travel)}
style={this.btnStyle}
text={`Travel to ${city}`}
/>
)
}
return (
<div>
<p>
From here, you can travel to any other city! A ticket
costs {numeralWrapper.formatMoney(CONSTANTS.TravelCost)}
</p>
{travelBtns}
</div>
)
}
}

View File

@ -0,0 +1,114 @@
/**
* React Subcomponent for displaying a location's UI, when that location is a university
*
* This subcomponent renders all of the buttons for studying/taking courses
*/
import * as React from "react";
import { Location } from "../Location";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { numeralWrapper } from "../../ui/numeralFormat";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
loc: Location;
p: IPlayer;
}
export class UniversityLocation extends React.Component<IProps, any> {
/**
* Stores button styling that sets them all to block display
*/
btnStyle: object;
constructor(props: IProps) {
super(props);
this.btnStyle = { display: "block" };
this.take = this.take.bind(this);
this.study = this.study.bind(this);
this.dataStructures = this.dataStructures.bind(this);
this.networks = this.networks.bind(this);
this.algorithms = this.algorithms.bind(this);
this.management = this.management.bind(this);
this.leadership = this.leadership.bind(this);
}
take(stat: string) {
const loc = this.props.loc;
this.props.p.startClass(loc.costMult, loc.expMult, stat);
}
study() {
return this.take(CONSTANTS.ClassStudyComputerScience);
}
dataStructures() {
return this.take(CONSTANTS.ClassDataStructures);
}
networks() {
return this.take(CONSTANTS.ClassNetworks);
}
algorithms() {
return this.take(CONSTANTS.ClassAlgorithms);
}
management() {
return this.take(CONSTANTS.ClassManagement);
}
leadership() {
return this.take(CONSTANTS.ClassLeadership);
}
render() {
const costMult: number = this.props.loc.costMult;
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
const algorithmsCost = CONSTANTS.ClassAlgorithmsBaseCost * costMult;
const managementCost = CONSTANTS.ClassManagementBaseCost * costMult;
const leadershipCost = CONSTANTS.ClassLeadershipBaseCost * costMult;
return (
<div>
<StdButton
onClick={this.study}
style={this.btnStyle}
text={`Study Computer Science (free)`}
/>
<StdButton
onClick={this.dataStructures}
style={this.btnStyle}
text={`Take Data Structures course (${numeralWrapper.formatMoney(dataStructuresCost)} / sec)`}
/>
<StdButton
onClick={this.networks}
style={this.btnStyle}
text={`Take Networks course (${numeralWrapper.formatMoney(networksCost)} / sec)`}
/>
<StdButton
onClick={this.algorithms}
style={this.btnStyle}
text={`Take Algorithms course (${numeralWrapper.formatMoney(algorithmsCost)} / sec)`}
/>
<StdButton
onClick={this.management}
style={this.btnStyle}
text={`Take Management course (${numeralWrapper.formatMoney(managementCost)} / sec)`}
/>
<StdButton
onClick={this.leadership}
style={this.btnStyle}
text={`Take Leadership course (${numeralWrapper.formatMoney(leadershipCost)} / sec)`}
/>
</div>
)
}
}

View File

@ -70,7 +70,11 @@ function checkForMessagesToSend() {
}
} else if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) {
sendMessage(jumper0);
Player.getHomeComputer().programs.push(Programs.Flight.name);
const flightName = Programs.Flight.name;
const homeComp = Player.getHomeComputer();
if (!homeComp.programs.includes(flightName)) {
homeComp.programs.push(flightName);
}
} else if (jumper1 && !jumper1.recvd && Player.hacking_skill >= 40) {
sendMessage(jumper1);
} else if (cybersecTest && !cybersecTest.recvd && Player.hacking_skill >= 50) {

View File

@ -35,10 +35,13 @@ import { netscriptCanGrow,
import { getCostOfNextHacknetNode,
getCostOfNextHacknetServer,
purchaseHacknet,
hasHacknetServers,
purchaseHacknet } from "./Hacknet/HacknetHelpers";
purchaseHashUpgrade } from "./Hacknet/HacknetHelpers";
import { CityName } from "./Locations/data/CityNames";
import { LocationName } from "./Locations/data/LocationNames";
import { HacknetServer } from "./Hacknet/HacknetServer";
import {Locations} from "./Locations";
import { Message } from "./Message/Message";
import { Messages } from "./Message/MessageHelpers";
import {inMission} from "./Missions";
@ -360,6 +363,19 @@ function NetscriptFunctions(workerScript) {
if (!hasHacknetServers()) { return Infinity; }
const node = getHacknetNode(i);
return node.calculateCacheUpgradeCost(n);
},
numHashes : function() {
if (!hasHacknetServers()) { return 0; }
return Player.hashManager.hashes;
},
hashCost : function(upgName) {
if (!hasHacknetServers()) { return Infinity; }
return Player.hashManager.getUpgradeCost(upgName);
},
spendHashes : function(upgName, upgTarget) {
if (!hasHacknetServers()) { return false; }
return purchaseHashUpgrade(upgName, upgTarget);
}
},
sprintf : sprintf,
@ -2299,56 +2315,14 @@ function NetscriptFunctions(workerScript) {
if (ip == null || ip === "") {
ip = workerScript.serverIp;
}
var s = getServer(ip);
if (s == null) {
throw makeRuntimeRejectMsg(workerScript, `Invalid server specified for rm(): ${ip}`);
const s = safeGetServer(ip, "rm");
const status = s.removeFile(fn);
if (!status.res) {
workerScript.log(status.msg);
}
if (fn.endsWith(".exe")) {
for (var i = 0; i < s.programs.length; ++i) {
if (s.programs[i] === fn) {
s.programs.splice(i, 1);
return true;
}
}
} else if (isScriptFilename(fn)) {
for (var i = 0; i < s.scripts.length; ++i) {
if (s.scripts[i].filename === fn) {
//Check that the script isnt currently running
for (var j = 0; j < s.runningScripts.length; ++j) {
if (s.runningScripts[j].filename === fn) {
workerScript.scriptRef.log("Cannot delete a script that is currently running!");
return false;
}
}
s.scripts.splice(i, 1);
return true;
}
}
} else if (fn.endsWith(".lit")) {
for (var i = 0; i < s.messages.length; ++i) {
var f = s.messages[i];
if (!(f instanceof Message) && isString(f) && f === fn) {
s.messages.splice(i, 1);
return true;
}
}
} else if (fn.endsWith(".txt")) {
for (var i = 0; i < s.textFiles.length; ++i) {
if (s.textFiles[i].fn === fn) {
s.textFiles.splice(i, 1);
return true;
}
}
} else if (fn.endsWith(".cct")) {
for (var i = 0; i < s.contracts.length; ++i) {
if (s.contracts[i].fn === fn) {
s.contracts.splice(i, 1);
return true;
}
}
}
return false;
return status.res;
},
scriptRunning : function(scriptname, ip) {
if (workerScript.checkingRam) {
@ -2615,30 +2589,30 @@ function NetscriptFunctions(workerScript) {
var costMult, expMult;
switch(universityName.toLowerCase()) {
case Locations.AevumSummitUniversity.toLowerCase():
if (Player.city != Locations.Aevum) {
case LocationName.AevumSummitUniversity.toLowerCase():
if (Player.city != CityName.Aevum) {
workerScript.scriptRef.log("ERROR: You cannot study at Summit University because you are not in Aevum. universityCourse() failed");
return false;
}
Player.location = Locations.AevumSummitUniversity;
Player.gotoLocation(LocationName.AevumSummitUniversity);
costMult = 4;
expMult = 3;
break;
case Locations.Sector12RothmanUniversity.toLowerCase():
if (Player.city != Locations.Sector12) {
case LocationName.Sector12RothmanUniversity.toLowerCase():
if (Player.city != CityName.Sector12) {
workerScript.scriptRef.log("ERROR: You cannot study at Rothman University because you are not in Sector-12. universityCourse() failed");
return false;
}
Player.location = Locations.Sector12RothmanUniversity;
Player.location = LocationName.Sector12RothmanUniversity;
costMult = 3;
expMult = 2;
break;
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
if (Player.city != Locations.Volhaven) {
case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase():
if (Player.city != CityName.Volhaven) {
workerScript.scriptRef.log("ERROR: You cannot study at ZB Institute of Technology because you are not in Volhaven. universityCourse() failed");
return false;
}
Player.location = Locations.VolhavenZBInstituteOfTechnology;
Player.location = LocationName.VolhavenZBInstituteOfTechnology;
costMult = 5;
expMult = 4;
break;
@ -2703,48 +2677,48 @@ function NetscriptFunctions(workerScript) {
}
var costMult, expMult;
switch(gymName.toLowerCase()) {
case Locations.AevumCrushFitnessGym.toLowerCase():
if (Player.city != Locations.Aevum) {
case LocationName.AevumCrushFitnessGym.toLowerCase():
if (Player.city != CityName.Aevum) {
workerScript.scriptRef.log("ERROR: You cannot workout at Crush Fitness because you are not in Aevum. gymWorkout() failed");
return false;
}
Player.location = Locations.AevumCrushFitnessGym;
Player.location = LocationName.AevumCrushFitnessGym;
costMult = 3;
expMult = 2;
break;
case Locations.AevumSnapFitnessGym.toLowerCase():
if (Player.city != Locations.Aevum) {
case LocationName.AevumSnapFitnessGym.toLowerCase():
if (Player.city != CityName.Aevum) {
workerScript.scriptRef.log("ERROR: You cannot workout at Snap Fitness because you are not in Aevum. gymWorkout() failed");
return false;
}
Player.location = Locations.AevumSnapFitnessGym;
Player.location = LocationName.AevumSnapFitnessGym;
costMult = 10;
expMult = 5;
break;
case Locations.Sector12IronGym.toLowerCase():
if (Player.city != Locations.Sector12) {
case LocationName.Sector12IronGym.toLowerCase():
if (Player.city != CityName.Sector12) {
workerScript.scriptRef.log("ERROR: You cannot workout at Iron Gym because you are not in Sector-12. gymWorkout() failed");
return false;
}
Player.location = Locations.Sector12IronGym;
Player.location = LocationName.Sector12IronGym;
costMult = 1;
expMult = 1;
break;
case Locations.Sector12PowerhouseGym.toLowerCase():
if (Player.city != Locations.Sector12) {
case LocationName.Sector12PowerhouseGym.toLowerCase():
if (Player.city != CityName.Sector12) {
workerScript.scriptRef.log("ERROR: You cannot workout at Powerhouse Gym because you are not in Sector-12. gymWorkout() failed");
return false;
}
Player.location = Locations.Sector12PowerhouseGym;
Player.location = LocationName.Sector12PowerhouseGym;
costMult = 20;
expMult = 10;
break;
case Locations.VolhavenMilleniumFitnessGym.toLowerCase():
if (Player.city != Locations.Volhaven) {
case LocationName.VolhavenMilleniumFitnessGym.toLowerCase():
if (Player.city != CityName.Volhaven) {
workerScript.scriptRef.log("ERROR: You cannot workout at Millenium Fitness Gym because you are not in Volhaven. gymWorkout() failed");
return false;
}
Player.location = Locations.VolhavenMilleniumFitnessGym;
Player.location = LocationName.VolhavenMilleniumFitnessGym;
costMult = 7;
expMult = 4;
break;
@ -2795,12 +2769,12 @@ function NetscriptFunctions(workerScript) {
}
switch(cityname) {
case Locations.Aevum:
case Locations.Chongqing:
case Locations.Sector12:
case Locations.NewTokyo:
case Locations.Ishima:
case Locations.Volhaven:
case CityName.Aevum:
case CityName.Chongqing:
case CityName.Sector12:
case CityName.NewTokyo:
case CityName.Ishima:
case CityName.Volhaven:
if(Player.money.lt(CONSTANTS.TravelCost)) {
workerScript.scriptRef.log("ERROR: not enough money to travel with travelToCity().");
throw makeRuntimeRejectMsg(workerScript, "ERROR: not enough money to travel with travelToCity().");
@ -2849,10 +2823,6 @@ function NetscriptFunctions(workerScript) {
AddToAllServers(darkweb);
SpecialServerIps.addIp("Darkweb Server", darkweb.ip);
const purchaseTor = document.getElementById("location-purchase-tor");
purchaseTor.setAttribute("class", "a-link-button-bought");
purchaseTor.innerHTML = "TOR Router - Purchased";
Player.getHomeComputer().serversOnNetwork.push(darkweb.ip);
darkweb.serversOnNetwork.push(Player.getHomeComputer().ip);
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
@ -3618,29 +3588,8 @@ function NetscriptFunctions(workerScript) {
}
}
//Set Location to slums
switch(Player.city) {
case Locations.Aevum:
Player.location = Locations.AevumSlums;
break;
case Locations.Chongqing:
Player.location = Locations.ChongqingSlums;
break;
case Locations.Sector12:
Player.location = Locations.Sector12Slums;
break;
case Locations.NewTokyo:
Player.location = Locations.NewTokyoSlums;
break;
case Locations.Ishima:
Player.location = Locations.IshimaSlums;
break;
case Locations.Volhaven:
Player.location = Locations.VolhavenSlums;
break;
default:
console.log("Invalid Player.city value");
}
// Set Location to slums
Player.gotoLocation(LocationName.Slums);
const crime = findCrime(crimeRoughName.toLowerCase());
if(crime == null) { // couldn't find crime

View File

@ -1,33 +1,44 @@
// Interface for an object that represents the player (PlayerObject)
// Used because at the time of implementation, the PlayerObject
// cant be converted to TypeScript.
//
// Only contains the needed properties for Sleeve implementation
/**
* Interface for an object that represents the player (PlayerObject)
* Used because at the time of implementation, the PlayerObject
* cant be converted to TypeScript.
*/
import { Resleeve } from "./Resleeving/Resleeve";
import { Sleeve } from "./Sleeve/Sleeve";
import { IMap } from "../types";
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { HacknetNode } from "../Hacknet/HacknetNode";
import { HacknetServer } from "../Hacknet/HacknetServer";
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { Company } from "../Company/Company";
import { CompanyPosition } from "../Company/CompanyPosition";
import { CityName } from "../Locations/data/CityNames";
import { HashManager } from "../Hacknet/HashManager";
import { HacknetNode } from "../Hacknet/HacknetNode";
import { LocationName } from "../Locations/data/LocationNames";
import { Server } from "../Server/Server";
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
export interface IPlayer {
// Class members
augmentations: IPlayerOwnedAugmentation[];
bladeburner: any;
bitNodeN: number;
city: string;
city: CityName;
companyName: string;
corporation: any;
currentServer: string;
factions: string[];
firstTimeTraveled: boolean;
hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server
hashManager: HashManager;
hasWseAccount: boolean;
homeComputer: string;
hp: number;
jobs: IMap<string>;
karma: number;
location: LocationName;
max_hp: number;
money: any;
moneySourceA: MoneySourceTracker;
moneySourceB: MoneySourceTracker;
@ -87,6 +98,23 @@ export interface IPlayer {
crime_money_mult: number;
// Methods
applyForAgentJob(sing?: boolean): boolean | void;
applyForBusinessConsultantJob(sing?: boolean): boolean | void;
applyForBusinessJob(sing?: boolean): boolean | void;
applyForEmployeeJob(sing?: boolean): boolean | void;
applyForItJob(sing?: boolean): boolean | void;
applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean | void;
applyForNetworkEngineerJob(sing?: boolean): boolean | void;
applyForPartTimeEmployeeJob(sing?: boolean): boolean | void;
applyForPartTimeWaiterJob(sing?: boolean): boolean | void;
applyForSecurityEngineerJob(sing?: boolean): boolean | void;
applyForSecurityJob(sing?: boolean): boolean | void;
applyForSoftwareConsultantJob(sing?: boolean): boolean | void;
applyForSoftwareJob(sing?: boolean): boolean | void;
applyForWaiterJob(sing?: boolean): boolean | void;
canAccessBladeburner(): boolean;
canAccessCorporation(): boolean;
canAccessResleeving(): boolean;
canAfford(cost: number): boolean;
gainHackingExp(exp: number): void;
gainStrengthExp(exp: number): void;
@ -95,13 +123,24 @@ export interface IPlayer {
gainAgilityExp(exp: number): void;
gainCharismaExp(exp: number): void;
gainMoney(money: number): void;
getCurrentServer(): Server;
getHomeComputer(): Server;
getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition;
getUpgradeHomeRamCost(): number;
gotoLocation(to: LocationName): boolean;
hasCorporation(): boolean;
hasTorRouter(): boolean;
inBladeburner(): boolean;
inGang(): boolean;
isQualified(company: Company, position: CompanyPosition): boolean;
loseMoney(money: number): void;
reapplyAllAugmentations(resetMultipliers: boolean): void;
reapplyAllSourceFiles(): void;
regenerateHp(amt: number): void;
recordMoneySource(amt: number, source: string): void;
startBladeburner(p: object): void;
startClass(costMult: number, expMult: number, className: string): void;
startCorporation(corpName: string, additionalShares?: number): void;
startCrime(crimeType: string,
hackExp: number,
strExp: number,
@ -112,4 +151,7 @@ export interface IPlayer {
money: number,
time: number,
singParams: any): void;
startWork(companyName: string): void;
startWorkPartTime(companyName: string): void;
travel(to: CityName): boolean;
}

View File

@ -3,7 +3,7 @@ import { Augmentation } from "../Augmentation/Augmentation";
import { Augmentations } from "../Augmentation/Augmentations";
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Cities } from "../Locations/Cities";
import { CityName } from "../Locations/data/CityNames";
import { CONSTANTS } from "../Constants";
// Interface that defines a generic object used to track experience/money
@ -105,7 +105,7 @@ export abstract class Person {
/**
* City that the person is in
*/
city: string = Cities.Sector12;
city: CityName = CityName.Sector12;
constructor() {}

View File

@ -0,0 +1,212 @@
import * as generalMethods from "./PlayerObjectGeneralMethods";
import * as serverMethods from "./PlayerObjectServerMethods";
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
import * as corporationMethods from "./PlayerObjectCorporationMethods";
import { HashManager } from "../../Hacknet/HashManager";
import { CityName } from "../../Locations/data/CityNames";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { Reviver,
Generic_toJSON,
Generic_fromJSON } from "../../../utils/JSONReviver";
import Decimal from "decimal.js";
export function PlayerObject() {
//Skills and stats
this.hacking_skill = 1;
//Combat stats
this.hp = 10;
this.max_hp = 10;
this.strength = 1;
this.defense = 1;
this.dexterity = 1;
this.agility = 1;
//Labor stats
this.charisma = 1;
//Special stats
this.intelligence = 0;
//Hacking multipliers
this.hacking_chance_mult = 1;
this.hacking_speed_mult = 1;
this.hacking_money_mult = 1;
this.hacking_grow_mult = 1;
//Experience and multipliers
this.hacking_exp = 0;
this.strength_exp = 0;
this.defense_exp = 0;
this.dexterity_exp = 0;
this.agility_exp = 0;
this.charisma_exp = 0;
this.intelligence_exp= 0;
this.hacking_mult = 1;
this.strength_mult = 1;
this.defense_mult = 1;
this.dexterity_mult = 1;
this.agility_mult = 1;
this.charisma_mult = 1;
this.hacking_exp_mult = 1;
this.strength_exp_mult = 1;
this.defense_exp_mult = 1;
this.dexterity_exp_mult = 1;
this.agility_exp_mult = 1;
this.charisma_exp_mult = 1;
this.company_rep_mult = 1;
this.faction_rep_mult = 1;
//Money
this.money = new Decimal(1000);
//IP Address of Starting (home) computer
this.homeComputer = "";
//Location information
this.city = CityName.Sector12;
this.location = "";
// Jobs that the player holds
// Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object)
// The CompanyPosition name must match a key value in CompanyPositions
this.jobs = {};
// Company at which player is CURRENTLY working (only valid when the player is actively working)
this.companyName = ""; // Name of Company. Must match a key value in Companies map
// Servers
this.currentServer = ""; //IP address of Server currently being accessed through terminal
this.purchasedServers = []; //IP Addresses of purchased servers
// Hacknet Nodes/Servers
this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers
this.hashManager = new HashManager();
//Factions
this.factions = []; //Names of all factions player has joined
this.factionInvitations = []; //Outstanding faction invitations
//Augmentations
this.queuedAugmentations = [];
this.augmentations = [];
this.sourceFiles = [];
//Crime statistics
this.numPeopleKilled = 0;
this.karma = 0;
this.crime_money_mult = 1;
this.crime_success_mult = 1;
//Flags/variables for working (Company, Faction, Creating Program, Taking Class)
this.isWorking = false;
this.workType = "";
this.currentWorkFactionName = "";
this.currentWorkFactionDescription = "";
this.workHackExpGainRate = 0;
this.workStrExpGainRate = 0;
this.workDefExpGainRate = 0;
this.workDexExpGainRate = 0;
this.workAgiExpGainRate = 0;
this.workChaExpGainRate = 0;
this.workRepGainRate = 0;
this.workMoneyGainRate = 0;
this.workMoneyLossRate = 0;
this.workHackExpGained = 0;
this.workStrExpGained = 0;
this.workDefExpGained = 0;
this.workDexExpGained = 0;
this.workAgiExpGained = 0;
this.workChaExpGained = 0;
this.workRepGained = 0;
this.workMoneyGained = 0;
this.createProgramName = "";
this.createProgramReqLvl = 0;
this.className = "";
this.crimeType = "";
this.timeWorked = 0; //in ms
this.timeWorkedCreateProgram = 0;
this.timeNeededToCompleteWork = 0;
this.work_money_mult = 1;
//Hacknet Node multipliers
this.hacknet_node_money_mult = 1;
this.hacknet_node_purchase_cost_mult = 1;
this.hacknet_node_ram_cost_mult = 1;
this.hacknet_node_core_cost_mult = 1;
this.hacknet_node_level_cost_mult = 1;
//Stock Market
this.hasWseAccount = false;
this.hasTixApiAccess = false;
this.has4SData = false;
this.has4SDataTixApi = false;
//Gang
this.gang = 0;
//Corporation
this.corporation = 0;
//Bladeburner
this.bladeburner = 0;
this.bladeburner_max_stamina_mult = 1;
this.bladeburner_stamina_gain_mult = 1;
this.bladeburner_analysis_mult = 1; //Field Analysis Only
this.bladeburner_success_chance_mult = 1;
// Sleeves & Re-sleeving
this.sleeves = [];
this.resleeves = [];
this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant
//bitnode
this.bitNodeN = 1;
//Flags for determining whether certain "thresholds" have been achieved
this.firstFacInvRecvd = false;
this.firstAugPurchased = false;
this.firstTimeTraveled = false;
this.firstProgramAvailable = false;
//Used to store the last update time.
this.lastUpdate = 0;
this.totalPlaytime = 0;
this.playtimeSinceLastAug = 0;
this.playtimeSinceLastBitnode = 0;
// Keep track of where money comes from
this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation
this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run
// Production since last Augmentation installation
this.scriptProdSinceLastAug = 0;
};
Object.assign(PlayerObject.prototype, generalMethods, serverMethods, bladeburnerMethods, corporationMethods);
PlayerObject.prototype.toJSON = function() {
return Generic_toJSON("PlayerObject", this);
}
PlayerObject.fromJSON = function(value) {
return Generic_fromJSON(PlayerObject, value.data);
}
Reviver.constructors.PlayerObject = PlayerObject;

View File

@ -0,0 +1,17 @@
import { Bladeburner } from "../../Bladeburner";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
export function canAccessBladeburner() {
if (this.bitNodeN === 8) { return false; }
return (this.bitNodeN === 6) || (this.bitNodeN === 7) || (SourceFileFlags[6] > 0);
}
export function inBladeburner() {
if (this.bladeburner == null) { return false; }
return (this.bladeburner instanceof Bladeburner);
}
export function startBladeburner() {
this.bladeburner = new Bladeburner({ new: true });
}

View File

@ -0,0 +1,19 @@
import { Corporation } from "../../Corporation/Corporation";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
export function canAccessCorporation() {
return this.bitNodeN === 3 || (SourceFileFlags[3] > 0);
}
export function hasCorporation() {
if (this.corporation == null) { return false; }
return (this.corporation instanceof Corporation);
}
export function startCorporation(corpName, additionalShares=0) {
this.corporation = new Corporation({
name: corpName
});
this.corporation.totalShares += additionalShares;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
/**
* Server and HacknetServer-related methods for the Player class (PlayerObject)
*/
import { IPlayer } from "../IPlayer";
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { HacknetServer } from "../../Hacknet/HacknetServer";
import { AddToAllServers,
AllServers } from "../../Server/AllServers";
import { SpecialServerIps } from "../../Server/SpecialServerIps";
export function hasTorRouter(this: IPlayer) {
return SpecialServerIps.hasOwnProperty("Darkweb Server");
}
export function getCurrentServer(this: IPlayer) {
return AllServers[this.currentServer];
}
export function getHomeComputer(this: IPlayer) {
return AllServers[this.homeComputer];
}
export function getUpgradeHomeRamCost(this: IPlayer) {
//Calculate how many times ram has been upgraded (doubled)
const currentRam = this.getHomeComputer().maxRam;
const numUpgrades = Math.log2(currentRam);
//Calculate cost
//Have cost increase by some percentage each time RAM has been upgraded
const mult = Math.pow(1.58, numUpgrades);
var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost;
return cost;
}
export function createHacknetServer(this: IPlayer): HacknetServer {
const numOwned = this.hacknetNodes.length;
const name = `hacknet-node-${numOwned}`;
const server = new HacknetServer({
adminRights: true,
hostname: name,
player: this,
});
this.hacknetNodes.push(server.ip);
// Configure the HacknetServer to actually act as a Server
AddToAllServers(server);
const homeComputer = this.getHomeComputer();
homeComputer.serversOnNetwork.push(server.ip);
server.serversOnNetwork.push(homeComputer.ip);
return server;
}

View File

@ -22,8 +22,6 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Crime } from "../../Crime/Crime";
import { Crimes } from "../../Crime/Crimes";
import { Cities } from "../../Locations/Cities";
import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition";
@ -35,7 +33,8 @@ import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
import { Locations } from "../../Locations";
import { CityName } from "../../Locations/data/CityNames";
import { LocationName } from "../../Locations/data/LocationNames";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver";
@ -436,20 +435,30 @@ export class Sleeve extends Person {
* Called on every sleeve for a Source File prestige
*/
prestige(p: IPlayer) {
// Reset exp
this.hacking_exp = 0;
this.strength_exp = 0;
this.defense_exp = 0;
this.dexterity_exp = 0;
this.agility_exp = 0;
this.charisma_exp = 0;
// Reset task-related stuff
this.resetTaskStatus();
this.earningsForSleeves = createTaskTracker();
this.earningsForPlayer = createTaskTracker();
this.logs = [];
this.shockRecovery(p);
// Reset augs and multipliers
this.augmentations = [];
this.resetMultipliers();
// Reset sleeve-related stats
this.shock = 1;
this.storedCycles = 0;
this.sync = Math.max(this.memory, 1);
this.shockRecovery(p);
this.logs = [];
}
/**
@ -592,21 +601,21 @@ export class Sleeve extends Person {
let costMult: number = 1;
let expMult: number = 1;
switch (universityName.toLowerCase()) {
case Locations.AevumSummitUniversity.toLowerCase():
if (this.city !== Cities.Aevum) { return false; }
this.currentTaskLocation = Locations.AevumSummitUniversity;
case LocationName.AevumSummitUniversity.toLowerCase():
if (this.city !== CityName.Aevum) { return false; }
this.currentTaskLocation = LocationName.AevumSummitUniversity;
costMult = 4;
expMult = 3;
break;
case Locations.Sector12RothmanUniversity.toLowerCase():
if (this.city !== Cities.Sector12) { return false; }
this.currentTaskLocation = Locations.Sector12RothmanUniversity;
case LocationName.Sector12RothmanUniversity.toLowerCase():
if (this.city !== CityName.Sector12) { return false; }
this.currentTaskLocation = LocationName.Sector12RothmanUniversity;
costMult = 3;
expMult = 2;
break;
case Locations.VolhavenZBInstituteOfTechnology.toLowerCase():
if (this.city !== Cities.Volhaven) { return false; }
this.currentTaskLocation = Locations.VolhavenZBInstituteOfTechnology;
case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase():
if (this.city !== CityName.Volhaven) { return false; }
this.currentTaskLocation = LocationName.VolhavenZBInstituteOfTechnology;
costMult = 5;
expMult = 4;
break;
@ -658,11 +667,7 @@ export class Sleeve extends Person {
/**
* Travel to another City. Costs money from player
*/
travel(p: IPlayer, newCity: string): boolean {
if (Cities[newCity] == null) {
return false;
}
travel(p: IPlayer, newCity: CityName): boolean {
p.loseMoney(CONSTANTS.TravelCost);
this.city = newCity;
@ -791,33 +796,33 @@ export class Sleeve extends Person {
let costMult: number = 1;
let expMult: number = 1;
switch (gymName.toLowerCase()) {
case Locations.AevumCrushFitnessGym.toLowerCase():
if (this.city != Cities.Aevum) { return false; }
this.currentTaskLocation = Locations.AevumCrushFitnessGym;
case LocationName.AevumCrushFitnessGym.toLowerCase():
if (this.city != CityName.Aevum) { return false; }
this.currentTaskLocation = LocationName.AevumCrushFitnessGym;
costMult = 3;
expMult = 2;
break;
case Locations.AevumSnapFitnessGym.toLowerCase():
if (this.city != Cities.Aevum) { return false; }
this.currentTaskLocation = Locations.AevumSnapFitnessGym;
case LocationName.AevumSnapFitnessGym.toLowerCase():
if (this.city != CityName.Aevum) { return false; }
this.currentTaskLocation = LocationName.AevumSnapFitnessGym;
costMult = 10;
expMult = 5;
break;
case Locations.Sector12IronGym.toLowerCase():
if (this.city != Cities.Sector12) { return false; }
this.currentTaskLocation = Locations.Sector12IronGym;
case LocationName.Sector12IronGym.toLowerCase():
if (this.city != CityName.Sector12) { return false; }
this.currentTaskLocation = LocationName.Sector12IronGym;
costMult = 1;
expMult = 1;
break;
case Locations.Sector12PowerhouseGym.toLowerCase():
if (this.city != Cities.Sector12) { return false; }
this.currentTaskLocation = Locations.Sector12PowerhouseGym;
case LocationName.Sector12PowerhouseGym.toLowerCase():
if (this.city != CityName.Sector12) { return false; }
this.currentTaskLocation = LocationName.Sector12PowerhouseGym;
costMult = 20;
expMult = 10;
break;
case Locations.VolhavenMilleniumFitnessGym:
if (this.city != Cities.Volhaven) { return false; }
this.currentTaskLocation = Locations.VolhavenMilleniumFitnessGym;
case LocationName.VolhavenMilleniumFitnessGym:
if (this.city != CityName.Volhaven) { return false; }
this.currentTaskLocation = LocationName.VolhavenMilleniumFitnessGym;
costMult = 7;
expMult = 4;
break;

View File

@ -9,15 +9,16 @@ import { SleeveFaq } from "./data/SleeveFaq";
import { IPlayer } from "../IPlayer";
import { CONSTANTS } from "../../Constants";
import { Locations } from "../../Locations";
import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum";
import { Cities } from "../../Locations/Cities";
import { Crime } from "../../Crime/Crime";
import { Crimes } from "../../Crime/Crimes";
import { Cities } from "../../Locations/Cities";
import { CityName } from "../../Locations/data/CityNames";
import { LocationName } from "../../Locations/data/LocationNames";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Page,
@ -243,20 +244,20 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
`Traveling to a different city costs ${numeralWrapper.formatMoney(CONSTANTS.TravelCost)}. ` +
"It will also CANCEL the sleeve's current task (setting it to idle)",
}));
for (const label in Cities) {
if (sleeve.city === Cities[label]) { continue; }
(function(sleeve, label) {
for (const cityName in Cities) {
if (sleeve.city === cityName) { continue; }
(function(sleeve, cityName) {
popupArguments.push(createElement("div", {
// Reusing this css class. It adds a border and makes it so that
// the background color changes when you hover
class: "cmpy-mgmt-find-employee-option",
innerText: Cities[label],
innerText: cityName,
clickListener: () => {
if (!playerRef!.canAfford(CONSTANTS.TravelCost)) {
dialogBoxCreate("You cannot afford to have this sleeve travel to another city", false);
return false;
}
sleeve.city = Cities[label];
sleeve.city = <CityName>cityName;
playerRef!.loseMoney(CONSTANTS.TravelCost);
sleeve.resetTaskStatus();
removeElementById(popupId);
@ -265,7 +266,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems {
return false;
}
}));
})(sleeve, label);
})(sleeve, cityName);
}
createPopup(popupId, popupArguments);
@ -569,14 +570,14 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
// Second selector has which university
switch (sleeve.city) {
case Cities.Aevum:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSummitUniversity));
case CityName.Aevum:
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.AevumSummitUniversity));
break;
case Cities.Sector12:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12RothmanUniversity));
case CityName.Sector12:
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.Sector12RothmanUniversity));
break;
case Cities.Volhaven:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenZBInstituteOfTechnology));
case CityName.Volhaven:
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.VolhavenZBInstituteOfTechnology));
break;
default:
elems.taskDetailsSelector2!.add(createOptionElement("No university available in city!"));
@ -597,30 +598,30 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee
// Second selector has gym
// In this switch statement we also set the initial value of the second selector
switch (sleeve.city) {
case Cities.Aevum:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumCrushFitnessGym));
elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSnapFitnessGym));
case CityName.Aevum:
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.AevumCrushFitnessGym));
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.AevumSnapFitnessGym));
// Set initial value
if (sleeve.currentTaskLocation === Locations.AevumCrushFitnessGym) {
if (sleeve.currentTaskLocation === LocationName.AevumCrushFitnessGym) {
elems.taskDetailsSelector2!.selectedIndex = 0;
} else if (sleeve.currentTaskLocation === Locations.AevumSnapFitnessGym) {
} else if (sleeve.currentTaskLocation === LocationName.AevumSnapFitnessGym) {
elems.taskDetailsSelector2!.selectedIndex = 1;
}
break;
case Cities.Sector12:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12IronGym));
elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12PowerhouseGym));
case CityName.Sector12:
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.Sector12IronGym));
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.Sector12PowerhouseGym));
// Set initial value
if (sleeve.currentTaskLocation === Locations.Sector12IronGym) {
if (sleeve.currentTaskLocation === LocationName.Sector12IronGym) {
elems.taskDetailsSelector2!.selectedIndex = 0;
} else if (sleeve.currentTaskLocation === Locations.Sector12PowerhouseGym) {
} else if (sleeve.currentTaskLocation === LocationName.Sector12PowerhouseGym) {
elems.taskDetailsSelector2!.selectedIndex = 1;
}
break;
case Cities.Volhaven:
elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenMilleniumFitnessGym));
case CityName.Volhaven:
elems.taskDetailsSelector2!.add(createOptionElement(LocationName.VolhavenMilleniumFitnessGym));
break;
default:
elems.taskDetailsSelector2!.add(createOptionElement("No gym available in city!"));

File diff suppressed because it is too large Load Diff

View File

@ -14,9 +14,7 @@ import { Faction } from "./Faction/Faction";
import { Factions,
initFactions } from "./Faction/Factions";
import { joinFaction } from "./Faction/FactionHelpers";
import { createHacknetServer } from "./Hacknet/HacknetHelpers";
import {deleteGangDisplayContent} from "./Gang";
import {Locations} from "./Location";
import { Message } from "./Message/Message";
import { initMessages,
Messages } from "./Message/MessageHelpers";
@ -98,9 +96,6 @@ function prestigeAugmentation() {
//Re-create foreign servers
initForeignServers(Player.getHomeComputer());
//Darkweb is purchase-able
document.getElementById("location-purchase-tor").setAttribute("class", "a-link-button");
//Gain favor for Companies
for (var member in Companies) {
if (Companies.hasOwnProperty(member)) {
@ -341,7 +336,8 @@ function prestigeSourceFile() {
// Source-File 9 (level 3) effect
if (SourceFileFlags[9] >= 3) {
const hserver = createHacknetServer();
const hserver = Player.createHacknetServer();
hserver.level = 100;
hserver.cores = 10;
hserver.cache = 5;

View File

@ -17,6 +17,7 @@ import { AllServers } from "../Server/AllServers";
import { processSingleServerGrowth } from "../Server/ServerHelpers";
import { Settings } from "../Settings/Settings";
import { EditorSetting } from "../Settings/SettingEnums";
import { isValidFilePath } from "../Terminal/DirectoryHelpers";
import {TextFile} from "../TextFile";
import {Page, routing} from "../ui/navigationTracking";
@ -247,7 +248,7 @@ function saveAndCloseScriptEditor() {
return;
}
if (checkValidFilename(filename) == false) {
if (filename !== ".fconf" && !isValidFilePath(filename)) {
dialogBoxCreate("Script filename can contain only alphanumerics, hyphens, and underscores");
return;
}
@ -292,17 +293,6 @@ function saveAndCloseScriptEditor() {
Engine.loadTerminalContent();
}
//Checks that the string contains only valid characters for a filename, which are alphanumeric,
// underscores, hyphens, and dots
function checkValidFilename(filename) {
var regex = /^[.a-zA-Z0-9_-]+$/;
if (filename.match(regex)) {
return true;
}
return false;
}
//Called when the game is loaded. Loads all running scripts (from all servers)
//into worker scripts so that they will start running
export function loadAllRunningScripts() {

View File

@ -16,7 +16,7 @@ import { Reviver } from "../../utils/JSONReviver";
export let AllServers: IMap<Server | HacknetServer> = {};
// Saftely add a Server to the AllServers map
export function AddToAllServers(server: Server): void {
export function AddToAllServers(server: Server | HacknetServer): void {
var serverIp = server.ip;
if (ipExists(serverIp)) {
console.log("IP of server that's being added: " + serverIp);

View File

@ -6,6 +6,7 @@ import { Message } from "../Message/Message";
import { RunningScript } from "../Script/RunningScript";
import { Script } from "../Script/Script";
import { TextFile } from "../TextFile";
import { IReturnStatus } from "../types";
import { isScriptFilename } from "../Script/ScriptHelpersTS";
@ -20,7 +21,7 @@ interface IConstructorParams {
organizationName?: string;
}
export abstract class BaseServer {
export class BaseServer {
// Coding Contract files on this server
contracts: CodingContract[] = [];
@ -123,6 +124,20 @@ export abstract class BaseServer {
return null;
}
/**
* Returns boolean indicating whether the given script is running on this server
*/
isRunning(fn: string): boolean {
// Check that the script isnt currently running
for (const runningScriptObj of this.runningScripts) {
if (runningScriptObj.filename === fn) {
return true;
}
}
return false;
}
removeContract(contract: CodingContract) {
if (contract instanceof CodingContract) {
this.contracts = this.contracts.filter((c) => {
@ -135,6 +150,60 @@ export abstract class BaseServer {
}
}
/**
* Remove a file from the server
* @param fn {string} Name of file to be deleted
* @returns {IReturnStatus} Return status object indicating whether or not file was deleted
*/
removeFile(fn: string): IReturnStatus {
if (fn.endsWith(".exe")) {
for (let i = 0; i < this.programs.length; ++i) {
if (this.programs[i] === fn) {
this.programs.splice(i, 1);
return { res: true };
}
}
} else if (isScriptFilename(fn)) {
for (let i = 0; i < this.scripts.length; ++i) {
if (this.scripts[i].filename === fn) {
if (this.isRunning(fn)) {
return {
res: false,
msg: "Cannot delete a script that is currently running!",
};
}
this.scripts.splice(i, 1);
return { res: true };
}
}
} else if (fn.endsWith(".lit")) {
for (let i = 0; i < this.messages.length; ++i) {
let f = this.messages[i];
if (typeof f === "string" && f === fn) {
this.messages.splice(i, 1);
return { res: true };
}
}
} else if (fn.endsWith(".txt")) {
for (let i = 0; i < this.textFiles.length; ++i) {
if (this.textFiles[i].fn === fn) {
this.textFiles.splice(i, 1);
return { res: true };
}
}
} else if (fn.endsWith(".cct")) {
for (let i = 0; i < this.contracts.length; ++i) {
if (this.contracts[i].fn === fn) {
this.contracts.splice(i, 1);
return { res: true };
}
}
}
return { res: false, msg: "No such file exists" };
}
/**
* Called when a script is run on this server.
* All this function does is add a RunningScript object to the

View File

@ -6,7 +6,7 @@ import { GetServerByHostname } from "./ServerHelpers";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { createRandomString } from "../utils/createRandomString";
import { createRandomString } from "../utils/helpers/createRandomString";
import { createRandomIp } from "../../utils/IPAddress";
import { Generic_fromJSON,
Generic_toJSON,
@ -136,14 +136,6 @@ export class Server extends BaseServer {
this.minDifficulty = Math.max(1, this.minDifficulty);
}
/**
* Strengthens a server's security level (difficulty) by the specified amount
*/
fortify(amt: number): void {
this.hackDifficulty += amt;
this.capDifficulty();
}
/**
* Change this server's maximum money
* @param n - Value by which to change the server's maximum money
@ -157,6 +149,14 @@ export class Server extends BaseServer {
}
}
/**
* Strengthens a server's security level (difficulty) by the specified amount
*/
fortify(amt: number): void {
this.hackDifficulty += amt;
this.capDifficulty();
}
/**
* Lowers the server's security level (difficulty) by the specified amount)
*/

View File

@ -4,9 +4,8 @@
*/
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../Constants";
import { Player } from "../Player";
import { AllServers,
AddToAllServers } from "../Server/AllServers";
import { IPlayer } from "../PersonObjects/IPlayer";
import { AddToAllServers } from "../Server/AllServers";
import { Server } from "../Server/Server";
import { dialogBoxCreate } from "../../utils/DialogBox";
import { createRandomIp } from "../../utils/IPAddress";
@ -15,7 +14,11 @@ import { isPowerOfTwo } from "../../utils/helpers/isPowerOfT
// Returns the cost of purchasing a server with the given RAM
// Returns Infinity for invalid 'ram' arguments
export function getPurchaseServerCost(ram) {
/**
* @param ram Amount of RAM on purchased server (GB)
* @returns Cost of purchasing the given server. Returns infinity for invalid arguments
*/
export function getPurchaseServerCost(ram: number) {
const sanitizedRam = Math.round(ram);
if (isNaN(sanitizedRam) || !isPowerOfTwo(sanitizedRam)) {
return Infinity;
@ -40,17 +43,17 @@ export function getPurchaseServerMaxRam() {
}
// Manually purchase a server (NOT through Netscript)
export function purchaseServer(ram) {
export function purchaseServer(ram: number, p: IPlayer) {
const cost = getPurchaseServerCost(ram);
//Check if player has enough money
if (Player.money.lt(cost)) {
dialogBoxCreate("You don't have enough money to purchase this server!");
if (!p.canAfford(cost)) {
dialogBoxCreate("You don't have enough money to purchase this server!", false);
return;
}
//Maximum server limit
if (Player.purchasedServers.length >= getPurchaseServerLimit()) {
if (p.purchasedServers.length >= getPurchaseServerLimit()) {
dialogBoxCreate("You have reached the maximum limit of " + getPurchaseServerLimit() + " servers. " +
"You cannot purchase any more. You can " +
"delete some of your purchased servers using the deleteServer() Netscript function in a script");
@ -71,26 +74,26 @@ export function purchaseServer(ram) {
AddToAllServers(newServ);
//Add to Player's purchasedServers array
Player.purchasedServers.push(newServ.ip);
p.purchasedServers.push(newServ.ip);
//Connect new server to home computer
var homeComputer = Player.getHomeComputer();
var homeComputer = p.getHomeComputer();
homeComputer.serversOnNetwork.push(newServ.ip);
newServ.serversOnNetwork.push(homeComputer.ip);
Player.loseMoney(cost);
p.loseMoney(cost);
dialogBoxCreate("Server successfully purchased with hostname " + hostname);
}
// Manually upgrade RAM on home computer (NOT through Netscript)
export function purchaseRamForHomeComputer(cost) {
if (Player.money.lt(cost)) {
export function purchaseRamForHomeComputer(cost: number, p: IPlayer) {
if (!p.canAfford(cost)) {
dialogBoxCreate("You do not have enough money to purchase additional RAM for your home computer");
return;
}
const homeComputer = Player.getHomeComputer();
const homeComputer = p.getHomeComputer();
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
dialogBoxCreate(`You cannot upgrade your home computer RAM because it is at its maximum possible value`);
return;
@ -98,7 +101,7 @@ export function purchaseRamForHomeComputer(cost) {
homeComputer.maxRam *= 2;
Player.loseMoney(cost);
p.loseMoney(cost);
dialogBoxCreate("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM.");
}

View File

@ -3,7 +3,7 @@ import { getStockMarket4SDataCost,
getStockMarket4STixApiCost } from "./StockMarketCosts";
import {CONSTANTS} from "../Constants";
import {Locations} from "../Locations";
import { LocationName } from "../Locations/data/LocationNames";
import {hasWallStreetSF, wallStreetSFLvl} from "../NetscriptFunctions";
import {WorkerScript} from "../NetscriptWorker";
import {Player} from "../Player";
@ -190,34 +190,34 @@ function loadStockMarket(saveString) {
function initStockSymbols() {
//Stocks for companies at which you can work
StockSymbols[Locations.AevumECorp] = "ECP";
StockSymbols[Locations.Sector12MegaCorp] = "MGCP";
StockSymbols[Locations.Sector12BladeIndustries] = "BLD";
StockSymbols[Locations.AevumClarkeIncorporated] = "CLRK";
StockSymbols[Locations.VolhavenOmniTekIncorporated] = "OMTK";
StockSymbols[Locations.Sector12FourSigma] = "FSIG";
StockSymbols[Locations.ChongqingKuaiGongInternational] = "KGI";
StockSymbols[Locations.AevumFulcrumTechnologies] = "FLCM";
StockSymbols[Locations.IshimaStormTechnologies] = "STM";
StockSymbols[Locations.NewTokyoDefComm] = "DCOMM";
StockSymbols[Locations.VolhavenHeliosLabs] = "HLS";
StockSymbols[Locations.NewTokyoVitaLife] = "VITA";
StockSymbols[Locations.Sector12IcarusMicrosystems] = "ICRS";
StockSymbols[Locations.Sector12UniversalEnergy] = "UNV";
StockSymbols[Locations.AevumAeroCorp] = "AERO";
StockSymbols[Locations.VolhavenOmniaCybersystems] = "OMN";
StockSymbols[Locations.ChongqingSolarisSpaceSystems] = "SLRS";
StockSymbols[Locations.NewTokyoGlobalPharmaceuticals] = "GPH";
StockSymbols[Locations.IshimaNovaMedical] = "NVMD";
StockSymbols[Locations.AevumWatchdogSecurity] = "WDS";
StockSymbols[Locations.VolhavenLexoCorp] = "LXO";
StockSymbols[Locations.AevumRhoConstruction] = "RHOC";
StockSymbols[Locations.Sector12AlphaEnterprises] = "APHE";
StockSymbols[Locations.VolhavenSysCoreSecurities] = "SYSC";
StockSymbols[Locations.VolhavenCompuTek] = "CTK";
StockSymbols[Locations.AevumNetLinkTechnologies] = "NTLK";
StockSymbols[Locations.IshimaOmegaSoftware] = "OMGA";
StockSymbols[Locations.Sector12FoodNStuff] = "FNS";
StockSymbols[LocationName.AevumECorp] = "ECP";
StockSymbols[LocationName.Sector12MegaCorp] = "MGCP";
StockSymbols[LocationName.Sector12BladeIndustries] = "BLD";
StockSymbols[LocationName.AevumClarkeIncorporated] = "CLRK";
StockSymbols[LocationName.VolhavenOmniTekIncorporated] = "OMTK";
StockSymbols[LocationName.Sector12FourSigma] = "FSIG";
StockSymbols[LocationName.ChongqingKuaiGongInternational] = "KGI";
StockSymbols[LocationName.AevumFulcrumTechnologies] = "FLCM";
StockSymbols[LocationName.IshimaStormTechnologies] = "STM";
StockSymbols[LocationName.NewTokyoDefComm] = "DCOMM";
StockSymbols[LocationName.VolhavenHeliosLabs] = "HLS";
StockSymbols[LocationName.NewTokyoVitaLife] = "VITA";
StockSymbols[LocationName.Sector12IcarusMicrosystems] = "ICRS";
StockSymbols[LocationName.Sector12UniversalEnergy] = "UNV";
StockSymbols[LocationName.AevumAeroCorp] = "AERO";
StockSymbols[LocationName.VolhavenOmniaCybersystems] = "OMN";
StockSymbols[LocationName.ChongqingSolarisSpaceSystems] = "SLRS";
StockSymbols[LocationName.NewTokyoGlobalPharmaceuticals] = "GPH";
StockSymbols[LocationName.IshimaNovaMedical] = "NVMD";
StockSymbols[LocationName.AevumWatchdogSecurity] = "WDS";
StockSymbols[LocationName.VolhavenLexoCorp] = "LXO";
StockSymbols[LocationName.AevumRhoConstruction] = "RHOC";
StockSymbols[LocationName.Sector12AlphaEnterprises] = "APHE";
StockSymbols[LocationName.VolhavenSysCoreSecurities] = "SYSC";
StockSymbols[LocationName.VolhavenCompuTek] = "CTK";
StockSymbols[LocationName.AevumNetLinkTechnologies] = "NTLK";
StockSymbols[LocationName.IshimaOmegaSoftware] = "OMGA";
StockSymbols[LocationName.Sector12FoodNStuff] = "FNS";
//Stocks for other companies
StockSymbols["Sigma Cosmetics"] = "SGC";
@ -241,115 +241,115 @@ function initStockMarket() {
const randInt = getRandomInt;
var ecorp = Locations.AevumECorp;
var ecorp = LocationName.AevumECorp;
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 megacorp = LocationName.Sector12MegaCorp;
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 blade = LocationName.Sector12BladeIndustries;
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 clarke = LocationName.AevumClarkeIncorporated;
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 omnitek = LocationName.VolhavenOmniTekIncorporated;
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 foursigma = LocationName.Sector12FourSigma;
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 kuaigong = LocationName.ChongqingKuaiGongInternational;
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 fulcrum = LocationName.AevumFulcrumTechnologies;
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3), 2e12);
StockMarket[fulcrum] = fulcrumStk;
var storm = Locations.IshimaStormTechnologies;
var storm = LocationName.IshimaStormTechnologies;
var stormStk = new Stock(storm, StockSymbols[storm], randInt(80, 90)/100, true, 7, randInt(20e3, 25e3), 1.2e12);
StockMarket[storm] = stormStk;
var defcomm = Locations.NewTokyoDefComm;
var defcomm = LocationName.NewTokyoDefComm;
var defcommStk = new Stock(defcomm, StockSymbols[defcomm], randInt(60, 70)/100, true, 10, randInt(6e3, 19e3), 900e9);
StockMarket[defcomm] = defcommStk;
var helios = Locations.VolhavenHeliosLabs;
var helios = LocationName.VolhavenHeliosLabs;
var heliosStk = new Stock(helios, StockSymbols[helios], randInt(55, 65)/100, true, 9, randInt(10e3, 18e3), 825e9);
StockMarket[helios] = heliosStk;
var vitalife = Locations.NewTokyoVitaLife;
var vitalife = LocationName.NewTokyoVitaLife;
var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], randInt(70, 80)/100, true, 7, randInt(8e3, 14e3), 1e12);
StockMarket[vitalife] = vitalifeStk;
var icarus = Locations.Sector12IcarusMicrosystems;
var icarus = LocationName.Sector12IcarusMicrosystems;
var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3), 800e9);
StockMarket[icarus] = icarusStk;
var universalenergy = Locations.Sector12UniversalEnergy;
var universalenergy = LocationName.Sector12UniversalEnergy;
var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], randInt(50, 60)/100, true, 10, randInt(16e3, 29e3), 900e9);
StockMarket[universalenergy] = universalenergyStk;
var aerocorp = Locations.AevumAeroCorp;
var aerocorp = LocationName.AevumAeroCorp;
var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], randInt(55, 65)/100, true, 6, randInt(8e3, 17e3), 640e9);
StockMarket[aerocorp] = aerocorpStk;
var omnia = Locations.VolhavenOmniaCybersystems;
var omnia = LocationName.VolhavenOmniaCybersystems;
var omniaStk = new Stock(omnia, StockSymbols[omnia], randInt(65, 75)/100, true, 4.5, randInt(6e3, 15e3), 600e9);
StockMarket[omnia] = omniaStk;
var solaris = Locations.ChongqingSolarisSpaceSystems;
var solaris = LocationName.ChongqingSolarisSpaceSystems;
var solarisStk = new Stock(solaris, StockSymbols[solaris], randInt(70, 80)/100, true, 8.5, randInt(14e3, 28e3), 705e9);
StockMarket[solaris] = solarisStk;
var globalpharm = Locations.NewTokyoGlobalPharmaceuticals;
var globalpharm = LocationName.NewTokyoGlobalPharmaceuticals;
var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], randInt(55, 65)/100, true, 10.5, randInt(12e3, 30e3), 695e9);
StockMarket[globalpharm] = globalpharmStk;
var nova = Locations.IshimaNovaMedical;
var nova = LocationName.IshimaNovaMedical;
var novaStk = new Stock(nova, StockSymbols[nova], randInt(70, 80)/100, true, 5, randInt(15e3, 27e3), 600e9);
StockMarket[nova] = novaStk;
var watchdog = Locations.AevumWatchdogSecurity;
var watchdog = LocationName.AevumWatchdogSecurity;
var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], randInt(240, 260)/100, true, 1.5, randInt(4e3, 8.5e3), 450e9);
StockMarket[watchdog] = watchdogStk;
var lexocorp = Locations.VolhavenLexoCorp;
var lexocorp = LocationName.VolhavenLexoCorp;
var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], randInt(115, 135)/100, true, 6, randInt(4.5e3, 8e3), 300e9);
StockMarket[lexocorp] = lexocorpStk;
var rho = Locations.AevumRhoConstruction;
var rho = LocationName.AevumRhoConstruction;
var rhoStk = new Stock(rho, StockSymbols[rho], randInt(50, 70)/100, true, 1, randInt(2e3, 7e3), 180e9);
StockMarket[rho] = rhoStk;
var alpha = Locations.Sector12AlphaEnterprises;
var alpha = LocationName.Sector12AlphaEnterprises;
var alphaStk = new Stock(alpha, StockSymbols[alpha], randInt(175, 205)/100, true, 10, randInt(4e3, 8.5e3), 240e9);
StockMarket[alpha] = alphaStk;
var syscore = Locations.VolhavenSysCoreSecurities;
var syscore = LocationName.VolhavenSysCoreSecurities;
var syscoreStk = new Stock(syscore, StockSymbols[syscore], randInt(150, 170)/100, true, 3, randInt(3e3, 8e3), 200e9);
StockMarket[syscore] = syscoreStk;
var computek = Locations.VolhavenCompuTek;
var computek = LocationName.VolhavenCompuTek;
var computekStk = new Stock(computek, StockSymbols[computek], randInt(80, 100)/100, true, 4, randInt(1e3, 6e3), 185e9);
StockMarket[computek] = computekStk;
var netlink = Locations.AevumNetLinkTechnologies;
var netlink = LocationName.AevumNetLinkTechnologies;
var netlinkStk = new Stock(netlink, StockSymbols[netlink], randInt(400, 430)/100, true, 1, randInt(1e3, 5e3), 58e9);
StockMarket[netlink] = netlinkStk;
var omega = Locations.IshimaOmegaSoftware;
var omega = LocationName.IshimaOmegaSoftware;
var omegaStk = new Stock(omega, StockSymbols[omega], randInt(90, 110)/100, true, 0.5, randInt(1e3, 8e3), 60e9);
StockMarket[omega] = omegaStk;
var fns = Locations.Sector12FoodNStuff;
var fns = LocationName.Sector12FoodNStuff;
var fnsStk = new Stock(fns, StockSymbols[fns], randInt(70, 80)/100, false, 1, randInt(500, 4.5e3), 45e9);
StockMarket[fns] = fnsStk;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
/**
* Helper functions that implement "directory" functionality in the Terminal.
* These aren't real directories, they're more of a pseudo-directory implementation
*/
/**
* Removes leading forward slash ("/") from a string.
*/
export function removeLeadingSlash(s: string): string {
if (s.startsWith("/")) {
return s.slice(1);
}
return s;
}
/**
* Removes trailing forward slash ("/") from a string.
* Note that this will also remove the slash if it is the leading slash (i.e. if s = "/")
*/
export function removeTrailingSlash(s: string): string {
if (s.endsWith("/")) {
return s.slice(0, -1);
}
return s;
}
/**
* Checks whether a string is a valid filename. Only used for the filename itself,
* not the entire filepath
*/
export function isValidFilename(filename: string): boolean {
// Allows alphanumerics, hyphens, underscores.
// Must have a file exntesion
const regex = /^[.a-zA-Z0-9_-]+[.][.a-zA-Z0-9_-]+$/;
// match() returns null if no match is found
return filename.match(regex) != null;
}
/**
* Checks whether a string is a valid directory name. Only used for the directory itself,
* not an entire path
*/
export function isValidDirectoryName(name: string): boolean {
// Allows alphanumerics, hyphens and underscores.
// Name can begin with a single period, but otherwise cannot have any
const regex = /^.?[a-zA-Z0-9_-]+$/;
// match() returns null if no match is found
return name.match(regex) != null;
}
/**
* Checks whether a string is a valid directory path.
* This only checks if it has the proper formatting. It does NOT check
* if the directories actually exist on Terminal
*/
export function isValidDirectoryPath(path: string): boolean {
let t_path: string = path;
if (t_path.length === 0) { return false; }
if (t_path.length === 1) {
return t_path === "/";
}
// A full path must have a leading slash, but we'll ignore it for the checks
if (t_path.startsWith("/")) {
t_path = t_path.slice(1);
} else {
return false;
}
// Trailing slash does not matter
t_path = removeTrailingSlash(t_path);
// Check that every section of the path is a valid directory name
const dirs = t_path.split("/");
for (const dir of dirs) {
// Special case, "." and ".." are valid for path
if (dir === "." || dir === "..") { continue; }
if (!isValidDirectoryName(dir)) {
return false;
}
}
return true;
}
/**
* Checks whether a string is a valid file path. This only checks if it has the
* proper formatting. It dose NOT check if the file actually exists on Terminal
*/
export function isValidFilePath(path: string): boolean {
let t_path = path;
// Impossible for filename to have less than length of 3
if (t_path.length < 3) { return false; }
// Full filepath can't end with trailing slash because it must be a file
if (t_path.endsWith("/")) { return false; }
// Everything after the last forward slash is the filename. Everything before
// it is the file path
const fnSeparator = t_path.lastIndexOf("/");
if (fnSeparator === -1) {
return isValidFilename(t_path);
}
const fn = t_path.slice(fnSeparator + 1);
const dirPath = t_path.slice(0, fnSeparator + 1);
return isValidDirectoryPath(dirPath) && isValidFilename(fn);
}
/**
* Returns a formatter string for the first parent directory in a filepath. For example:
* /home/var/test/ -> home/
* If there is no first parent directory, then it returns "/" for root
*/
export function getFirstParentDirectory(path: string): string {
let t_path = path;
t_path = removeLeadingSlash(t_path);
t_path = removeTrailingSlash(t_path);
let dirs = t_path.split("/");
if (dirs.length === 0) { return "/"; }
return dirs[0] + "/";
}
/**
* Checks if a file path refers to a file in the root directory.
*/
export function isInRootDirectory(path: string): boolean {
if (!isValidFilePath(path)) { return false; }
if (path == null || path.length === 0) { return false; }
return (path.lastIndexOf("/") <= 0);
}
/**
* Evaluates a directory path, including the processing of linux dots.
* Returns the full, proper path, or null if an invalid path is passed in
*/
export function evaluateDirectoryPath(path: string, currPath?: string): string | null {
let t_path = path;
// If the path begins with a slash, then its an absolute path. Otherwise its relative
// For relative paths, we need to prepend the current directory
if (!t_path.startsWith("/") && currPath != null) {
t_path = currPath + (currPath.endsWith("/") ? "" : "/") + t_path;
}
if (!isValidDirectoryPath(t_path)) { return null; }
// Trim leading/trailing slashes
t_path = removeLeadingSlash(t_path);
t_path = removeTrailingSlash(t_path);
const dirs = t_path.split("/");
const reconstructedPath: string[] = [];
for (const dir of dirs) {
if (dir === ".") {
// Current directory, do nothing
continue;
} else if (dir === "..") {
// Parent directory
const res = reconstructedPath.pop();
if (res == null) {
return null; // Array was empty, invalid path
}
} else {
reconstructedPath.push(dir);
}
}
return "/" + reconstructedPath.join("/");
}
/**
* Evaluates a file path, including the processing of linux dots.
* Returns the full, proper path, or null if an invalid path is passed in
*/
export function evaluateFilePath(path: string, currPath?: string): string | null {
let t_path = path;
// If the path begins with a slash, then its an absolute path. Otherwise its relative
// For relative paths, we need to prepend the current directory
if (!t_path.startsWith("/") && currPath != null) {
t_path = currPath + (currPath.endsWith("/") ? "" : "/") + t_path;
}
if (!isValidFilePath(t_path)) { return null; }
// Trim leading/trailing slashes
t_path = removeLeadingSlash(t_path);
const dirs = t_path.split("/");
const reconstructedPath: string[] = [];
for (const dir of dirs) {
if (dir === ".") {
// Current directory, do nothing
continue;
} else if (dir === "..") {
// Parent directory
const res = reconstructedPath.pop();
if (res == null) {
return null; // Array was empty, invalid path
}
} else {
reconstructedPath.push(dir);
}
}
return "/" + reconstructedPath.join("/");
}

View File

@ -1,10 +1,13 @@
/* tslint:disable:max-line-length completed-docs variable-name*/
import { IMap } from "../types";
export const TerminalHelpText: string =
"Type 'help name' to learn more about the command 'name'<br><br>" +
'alias [-g] [name="value"] Create or display Terminal aliases<br>' +
"analyze Get information about the current machine <br>" +
"buy [-l/program] Purchase a program through the Dark Web<br>" +
"cat [file] Display a .msg, .lit, or .txt file<br>" +
"cd [dir] Change to a new directory<br>" +
"check [script] [args...] Print a script's logs to Terminal<br>" +
"clear Clear all text on the terminal <br>" +
"cls See 'clear' command <br>" +
@ -19,9 +22,10 @@ export const TerminalHelpText: string =
"ifconfig Displays the IP address of the machine<br>" +
"kill [script] [args...] Stops the specified script on the current server <br>" +
"killall Stops all running scripts on the current machine<br>" +
"ls [| grep pattern] Displays all files on the machine<br>" +
"ls [dir] [| grep pattern] Displays all files on the machine<br>" +
"lscpu Displays the number of CPU cores on the machine<br>" +
"mem [script] [-t] [n] Displays the amount of RAM required to run the script<br>" +
"mv [src] [dest] Move/rename a text or script file<br>" +
"nano [file] Text editor - Open up and edit a script or text file<br>" +
"ps Display all scripts that are currently running<br>" +
"rm [file] Delete a file from the server<br>" +
@ -36,9 +40,6 @@ export const TerminalHelpText: string =
'unalias [alias name] Deletes the specified alias<br>' +
"wget [url] [target file] Retrieves code/text from a web server<br>";
interface IMap<T> {
[key: string]: T;
}
export const HelpTexts: IMap<string> = {
alias: 'alias [-g] [name="value"] <br>' +
"Create or display aliases. An alias enables a replacement of a word with another string. " +
@ -74,6 +75,12 @@ export const HelpTexts: IMap<string> = {
"cat j1.msg<br>" +
"cat foo.lit<br>" +
"cat servers.txt",
cd: "cd [dir]<br>" +
"Change to the specified directory. Note that this works even for directories that don't exist. If you " +
"change to a directory that does not exist, it will not be 'created'. Examples:<br><br>" +
"cd scripts/hacking<br>" +
"cd /logs<br>" +
"cd ../",
check: "check [script name] [args...]<br>" +
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by " +
"a space. Remember that a running script is uniquely " +
@ -135,15 +142,18 @@ export const HelpTexts: IMap<string> = {
"Note that after the 'kill' command is issued for a script, it may take a while for the script to actually stop running. " +
"This will happen if the script is in the middle of a command such as grow() or weaken() that takes time to execute. " +
"The script will not be stopped/killed until after that time has elapsed.",
ls: "ls [| grep pattern]<br>" +
"The ls command, with no arguments, prints all files on the current server to the Terminal screen. " +
"This includes all scripts, programs, and message files. " +
ls: "ls [dir] [| grep pattern]<br>" +
"The ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. " +
"The files will be displayed in alphabetical order. <br><br>" +
"The '| grep pattern' optional parameter can be used to only display files whose filenames match the specified pattern. " +
"For example, if you wanted to only display files with the .script extension, you could use: <br><br>" +
"The 'dir' optional parameter can be used to display files/directories in another directory.<br><br>" +
"The '| grep pattern' optional parameter can be used to only display files whose filenames match the specified pattern.<br><br>" +
"Examples:<br><br>" +
"List all files with the '.script' extension in the current directory:<br>" +
"ls | grep .script<br><br>" +
"Alternatively, if you wanted to display all files with the word purchase in the filename, you could use: <br><br>" +
"ls | grep purchase",
"List all files with the '.js' extension in the root directory:<br>" +
"ls / | grep .js<br><br>" +
"List all files with the word 'purchase' in the filename, in the 'scripts' directory:<br>" +
"ls scripts | grep purchase",
lscpu: "lscpu<br>" +
"Prints the number of CPU Cores the current server has",
mem: "mem [script name] [-t] [num threads]<br>" +
@ -154,6 +164,15 @@ export const HelpTexts: IMap<string> = {
"mem foo.script -t 50<br>" +
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example " +
"above will print the amount of RAM needed to run 'foo.script' with 50 threads.",
mv: "mv [src] [dest]<br>" +
"Move the source file to the specified destination. This can also be used to rename files. " +
"This command only works for scripts and text files (.txt). This command CANNOT be used to " +
"convert to different file types<br><br>" +
"Note that, unlike the Linux 'mv' command, the destination argument must be the " +
"full filepath. " +
"Examples: <br><br>" +
"mv hacking-controller.script scripts/hacking-controller.script<br>" +
"mv myScript.js myOldScript.js",
nano: "nano [file name]<br>" +
"Opens up the specified file in the Text Editor. Only scripts (.script) or text files (.txt) can be " +
"edited using the Text Editor. If the file does not already exist, then a new, empty one " +

View File

@ -0,0 +1,214 @@
import {
Aliases,
GlobalAliases
} from "../Alias";
import { DarkWebItems } from "../DarkWeb/DarkWebItems";
import { Message } from "../Message/Message";
import { IPlayer } from "../PersonObjects/IPlayer"
import { AllServers } from "../Server/AllServers";
// An array of all Terminal commands
const commands = [
"alias",
"analyze",
"cat",
"cd",
"check",
"clear",
"cls",
"connect",
"download",
"expr",
"free",
"hack",
"help",
"home",
"hostname",
"ifconfig",
"kill",
"killall",
"ls",
"lscpu",
"mem",
"mv",
"nano",
"ps",
"rm",
"run",
"scan",
"scan-analyze",
"scp",
"sudov",
"tail",
"theme",
"top"
];
export function determineAllPossibilitiesForTabCompletion(p: IPlayer, input: string, index: number=0): string[] {
let allPos: string[] = [];
allPos = allPos.concat(Object.keys(GlobalAliases));
const currServ = p.getCurrentServer();
const homeComputer = p.getHomeComputer();
input = input.toLowerCase();
// Helper functions
function addAllCodingContracts() {
for (const cct of currServ.contracts) {
allPos.push(cct.fn);
}
}
function addAllLitFiles() {
for (const file of currServ.messages) {
if (!(file instanceof Message)) {
allPos.push(file);
}
}
}
function addAllMessages() {
for (const file of currServ.messages) {
if (file instanceof Message) {
allPos.push(file.filename);
}
}
}
function addAllPrograms() {
for (const program of homeComputer.programs) {
allPos.push(program);
}
}
function addAllScripts() {
for (const script of currServ.scripts) {
allPos.push(script.filename);
}
}
function addAllTextFiles() {
for (const txt of currServ.textFiles) {
allPos.push(txt.fn);
}
}
function isCommand(cmd: string) {
let t_cmd = cmd;
if (!t_cmd.endsWith(" ")) {
t_cmd += " ";
}
return input.startsWith(t_cmd);
}
/**
* If the command starts with './' and the index == -1, then the user
* has input ./partialexecutablename so autocomplete the script or program.
* Put './' in front of each script/executable
*/
if (isCommand("./") && index == -1) {
//All programs and scripts
for (var i = 0; i < currServ.scripts.length; ++i) {
allPos.push("./" + currServ.scripts[i].filename);
}
//Programs are on home computer
for(var i = 0; i < homeComputer.programs.length; ++i) {
allPos.push("./" + homeComputer.programs[i]);
}
return allPos;
}
// Autocomplete the command
if (index == -1) {
return commands.concat(Object.keys(Aliases)).concat(Object.keys(GlobalAliases));
}
if (isCommand("buy")) {
let options = [];
for (const i in DarkWebItems) {
const item = DarkWebItems[i]
options.push(item.program);
}
return options.concat(Object.keys(GlobalAliases));
}
if (isCommand("scp") && index === 1) {
for (const iphostname in AllServers) {
allPos.push(AllServers[iphostname].ip);
allPos.push(AllServers[iphostname].hostname);
}
return allPos;
}
if (isCommand("scp") && index === 0) {
addAllScripts();
addAllLitFiles();
addAllTextFiles();
return allPos;
}
if (isCommand("connect")) {
// All network connections
for (var i = 0; i < currServ.serversOnNetwork.length; ++i) {
var serv = AllServers[currServ.serversOnNetwork[i]];
if (serv == null) { continue; }
allPos.push(serv.ip);
allPos.push(serv.hostname);
}
return allPos;
}
if (isCommand("kill") || isCommand("tail") || isCommand("mem") || isCommand("check")) {
addAllScripts();
return allPos;
}
if (isCommand("nano")) {
addAllScripts();
addAllTextFiles();
allPos.push(".fconf");
return allPos;
}
if (isCommand("rm")) {
addAllScripts();
addAllPrograms();
addAllLitFiles();
addAllTextFiles();
addAllCodingContracts();
return allPos;
}
if (isCommand("run")) {
addAllScripts();
addAllPrograms();
addAllCodingContracts();
return allPos;
}
if (isCommand("cat")) {
addAllMessages();
addAllLitFiles();
addAllTextFiles();
return allPos;
}
if (isCommand("download") || isCommand("mv")) {
addAllScripts();
addAllTextFiles();
return allPos;
}
return allPos;
}

View File

@ -0,0 +1,113 @@
import {
post
} from "../ui/postToTerminal";
import {
containsAllStrings,
longestCommonStart
} from "../../utils/StringHelperFunctions";
/**
* Implements tab completion for the Terminal
*
* @param command {string} Terminal command, excluding the last incomplete argument
* @param arg {string} Last argument that is being completed
* @param allPossibilities {string[]} All values that `arg` can complete to
*/
export function tabCompletion(command: string, arg: string, allPossibilities: string[]): void {
if (!(allPossibilities.constructor === Array)) { return; }
if (!containsAllStrings(allPossibilities)) { return; }
// Remove all options in allPossibilities that do not match the current string
// that we are attempting to autocomplete
if (arg === "") {
for (let i = allPossibilities.length-1; i >= 0; --i) {
if (!allPossibilities[i].toLowerCase().startsWith(command.toLowerCase())) {
allPossibilities.splice(i, 1);
}
}
} else {
for (let i = allPossibilities.length-1; i >= 0; --i) {
if (!allPossibilities[i].toLowerCase().startsWith(arg.toLowerCase())) {
allPossibilities.splice(i, 1);
}
}
}
const textBoxElem = document.getElementById("terminal-input-text-box");
if (textBoxElem == null) {
console.warn(`Couldn't find terminal input DOM element (id=terminal-input-text-box) when trying to autocomplete`);
return;
}
const textBox = <HTMLInputElement>textBoxElem;
const oldValue = textBox.value;
const semiColonIndex = oldValue.lastIndexOf(";");
let val = "";
if (allPossibilities.length === 0) {
return;
} else if (allPossibilities.length === 1) {
if (arg === "") {
//Autocomplete command
val = allPossibilities[0] + " ";
} else {
val = command + " " + allPossibilities[0];
}
if (semiColonIndex === -1) {
// No semicolon, so replace the whole command
textBox.value = val;
} else {
// Replace only after the last semicolon
textBox.value = textBox.value.slice(0, semiColonIndex + 1) + " " + val;
}
textBox.focus();
} else {
const longestStartSubstr = longestCommonStart(allPossibilities);
/**
* If the longest common starting substring of remaining possibilities is the same
* as whatevers already in terminal, just list all possible options. Otherwise,
* change the input in the terminal to the longest common starting substr
*/
let allOptionsStr = "";
for (let i = 0; i < allPossibilities.length; ++i) {
allOptionsStr += allPossibilities[i];
allOptionsStr += " ";
}
if (arg === "") {
if (longestStartSubstr === command) {
post("> " + command);
post(allOptionsStr);
} else {
if (semiColonIndex === -1) {
// No semicolon, so replace the whole command
textBox.value = longestStartSubstr;
} else {
// Replace only after the last semicolon
textBox.value = `${textBox.value.slice(0, semiColonIndex + 1)} ${longestStartSubstr}`;
}
textBox.focus();
}
} else {
if (longestStartSubstr === arg) {
// List all possible options
post("> " + command + " " + arg);
post(allOptionsStr);
} else {
if (semiColonIndex == -1) {
// No semicolon, so replace the whole command
textBox.value = `${command} ${longestStartSubstr}`;
} else {
// Replace only after the last semicolon
textBox.value = `${textBox.value.slice(0, semiColonIndex + 1)} ${command} ${longestStartSubstr}`;
}
textBox.focus();
}
}
}
}

View File

@ -27,15 +27,14 @@ import { displayFactionContent, joinFaction,
processPassiveFactionRepGain,
inviteToFaction } from "./Faction/FactionHelpers";
import { FconfSettings } from "./Fconf/FconfSettings";
import {displayLocationContent,
initLocationButtons} from "./Location";
import {Locations} from "./Locations";
import { hasHacknetServers,
renderHacknetNodesUI,
clearHacknetNodesUI,
processHacknetEarnings } from "./Hacknet/HacknetHelpers";
import {iTutorialStart} from "./InteractiveTutorial";
import {initLiterature} from "./Literature";
import { LocationName } from "./Locations/data/LocationNames";
import { LocationRoot } from "./Locations/ui/Root";
import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers";
import {inMission, currMission} from "./Missions";
import {initSingularitySFFlags,
@ -174,7 +173,7 @@ $(document).keydown(function(e) {
Engine.loadHacknetNodesContent();
} else if (e.keyCode === KEY.W && e.altKey) {
e.preventDefault();
Engine.loadWorldContent();
Engine.loadLocationContent();
} else if (e.keyCode === KEY.J && e.altKey) {
e.preventDefault();
Engine.loadJobContent();
@ -233,7 +232,6 @@ const Engine = {
scriptEditorContent: null,
activeScriptsContent: null,
hacknetNodesContent: null,
worldContent: null,
createProgramContent: null,
factionsContent: null,
factionContent: null,
@ -302,14 +300,6 @@ const Engine = {
MainMenuLinks.HacknetNodes.classList.add("active");
},
loadWorldContent: function() {
Engine.hideAllContent();
Engine.Display.worldContent.style.display = "block";
Engine.displayWorldInfo();
routing.navigateTo(Page.World);
MainMenuLinks.City.classList.add("active");
},
loadCreateProgramContent: function() {
Engine.hideAllContent();
Engine.Display.createProgramContent.style.display = "block";
@ -354,54 +344,57 @@ const Engine = {
MainMenuLinks.DevMenu.classList.add("active");
},
loadLocationContent: function() {
loadLocationContent: function(initiallyInCity=true) {
Engine.hideAllContent();
Engine.Display.locationContent.style.display = "block";
try {
displayLocationContent();
} catch(e) {
exceptionAlert(e);
console.error(e);
}
MainMenuLinks.City.classList.add("active");
routing.navigateTo(Page.Location);
const rootComponent = <LocationRoot
initiallyInCity={initiallyInCity}
engine={Engine}
p={Player}
/>
ReactDOM.render(rootComponent, Engine.Display.locationContent);
},
loadTravelContent: function() {
switch(Player.city) {
case Locations.Aevum:
Player.location = Locations.AevumTravelAgency;
break;
case Locations.Chongqing:
Player.location = Locations.ChongqingTravelAgency;
break;
case Locations.Sector12:
Player.location = Locations.Sector12TravelAgency;
break;
case Locations.NewTokyo:
Player.location = Locations.NewTokyoTravelAgency;
break;
case Locations.Ishima:
Player.location = Locations.IshimaTravelAgency;
break;
case Locations.Volhaven:
Player.location = Locations.VolhavenTravelAgency;
break;
default:
dialogBoxCreate("ERROR: Invalid city. This is a bug please contact game dev");
break;
}
Engine.loadLocationContent();
// Same as loadLocationContent() except first set the location to the travel agency,
// and make sure that the 'City' main menu link doesnt become 'active'
Engine.hideAllContent();
Player.gotoLocation(LocationName.TravelAgency);
Engine.Display.locationContent.style.display = "block";
MainMenuLinks.Travel.classList.add("active");
routing.navigateTo(Page.Location);
const rootComponent = <LocationRoot
initiallyInCity={false}
engine={Engine}
p={Player}
/>
ReactDOM.render(rootComponent, Engine.Display.locationContent);
},
loadJobContent: function() {
// Same as loadLocationContent(), except first set the location to the job.
// Make sure that the 'City' main menu link doesnt become 'active'
if (Player.companyName == "") {
dialogBoxCreate("You do not currently have a job! You can visit various companies " +
"in the city and try to find a job.");
return;
}
Player.location = Player.companyName;
Engine.loadLocationContent();
Engine.hideAllContent();
Player.gotoLocation(Player.companyName);
Engine.Display.locationContent.style.display = "block";
MainMenuLinks.Job.classList.add("active");
routing.navigateTo(Page.Location);
const rootComponent = <LocationRoot
initiallyInCity={false}
engine={Engine}
p={Player}
/>
ReactDOM.render(rootComponent, Engine.Display.locationContent);
},
loadWorkInProgressContent: function() {
@ -503,14 +496,13 @@ const Engine = {
}
},
//Helper function that hides all content
// Helper function that hides all content
hideAllContent: function() {
Engine.Display.terminalContent.style.display = "none";
Engine.Display.characterContent.style.display = "none";
Engine.Display.scriptEditorContent.style.display = "none";
Engine.Display.activeScriptsContent.style.display = "none";
clearHacknetNodesUI();
Engine.Display.worldContent.style.display = "none";
Engine.Display.createProgramContent.style.display = "none";
Engine.Display.factionsContent.style.display = "none";
Engine.Display.factionContent.style.display = "none";
@ -518,6 +510,7 @@ const Engine = {
Engine.Display.augmentationsContent.style.display = "none";
Engine.Display.tutorialContent.style.display = "none";
Engine.Display.locationContent.style.display = "none";
ReactDOM.unmountComponentAtNode(Engine.Display.locationContent);
Engine.Display.workInProgressContent.style.display = "none";
Engine.Display.redPillContent.style.display = "none";
Engine.Display.cinematicTextContent.style.display = "none";
@ -542,15 +535,15 @@ const Engine = {
clearResleevesPage();
clearSleevesPage();
//Location lists
Engine.aevumLocationsList.style.display = "none";
Engine.chongqingLocationsList.style.display = "none";
Engine.sector12LocationsList.style.display = "none";
Engine.newTokyoLocationsList.style.display = "none";
Engine.ishimaLocationsList.style.display = "none";
Engine.volhavenLocationsList.style.display = "none";
// Make nav menu tabs inactive
Engine.inactivateMainMenuLinks();
//Make nav menu tabs inactive
// Close dev menu
closeDevMenu();
},
// Remove 'active' css class from all main menu links
inactivateMainMenuLinks: function() {
MainMenuLinks.Terminal.classList.remove("active");
MainMenuLinks.ScriptEditor.classList.remove("active");
MainMenuLinks.ActiveScripts.classList.remove("active");
@ -570,9 +563,6 @@ const Engine = {
MainMenuLinks.Tutorial.classList.remove("active");
MainMenuLinks.Options.classList.remove("active");
MainMenuLinks.DevMenu.classList.remove("active");
// Close dev menu
closeDevMenu();
},
displayCharacterOverviewInfo: function() {
@ -592,99 +582,6 @@ const Engine = {
displayCharacterInfo(Engine.Display.characterInfo, Player);
},
/* Display locations in the world*/
aevumLocationsList: null,
chongqingLocationsList: null,
sector12LocationsList: null,
newTokyoLocationsList: null,
ishimaLocationsList: null,
volhavenLocationsList: null,
displayWorldInfo: function() {
Engine.aevumLocationsList.style.display = "none";
Engine.chongqingLocationsList.style.display = "none";
Engine.sector12LocationsList.style.display = "none";
Engine.newTokyoLocationsList.style.display = "none";
Engine.ishimaLocationsList.style.display = "none";
Engine.volhavenLocationsList.style.display = "none";
document.getElementById("world-city-name").innerHTML = Player.city;
var cityDesc = document.getElementById("world-city-desc"); //TODO
switch(Player.city) {
case Locations.Aevum:
Engine.aevumLocationsList.style.display = "inline";
break;
case Locations.Chongqing:
Engine.chongqingLocationsList.style.display = "inline";
break;
case Locations.Sector12:
Engine.sector12LocationsList.style.display = "inline";
//City hall only in BitNode-3/with Source-File 3
if ((Player.bitNodeN === 3 || hasCorporationSF) && Player.bitNodeN !== 8) {
document.getElementById("sector12-cityhall-li").style.display = "block";
} else {
document.getElementById("sector12-cityhall-li").style.display = "none";
}
break;
case Locations.NewTokyo:
Engine.newTokyoLocationsList.style.display = "inline";
break;
case Locations.Ishima:
Engine.ishimaLocationsList.style.display = "inline";
break;
case Locations.Volhaven:
Engine.volhavenLocationsList.style.display = "inline";
break;
default:
console.log("Invalid city value in Player object!");
break;
}
//Generic Locations (common to every city):
// World Stock Exchange
// Corporation (if applicable)
// Bladeburner HQ (if applicable);
var genericLocationsList = document.getElementById("generic-locations-list");
genericLocationsList.style.display = "inline";
removeChildrenFromElement(genericLocationsList);
var li = createElement("li");
li.appendChild(createElement("a", {
innerText:"World Stock Exchange", class:"a-link-button",
clickListener:()=>{
Player.location = Locations.WorldStockExchange;
Engine.loadStockMarketContent();
return false;
}
}));
genericLocationsList.appendChild(li);
if (Player.corporation instanceof Corporation && document.getElementById("location-corporation-button") == null) {
var li = createElement("li");
li.appendChild(createElement("a", {
innerText:Player.corporation.name, id:"location-corporation-button",
class:"a-link-button",
clickListener:()=>{
Engine.loadCorporationContent();
return false;
}
}));
genericLocationsList.appendChild(li);
}
if (Player.bladeburner instanceof Bladeburner) {
var li = createElement("li");
li.appendChild(createElement("a", {
innerText:"Bladeburner Headquarters", class:"a-link-button",
clickListener:()=>{
Engine.loadBladeburnerContent();
return false;
}
}));
genericLocationsList.appendChild(li);
}
},
displayFactionsInfo: function() {
removeChildrenFromElement(Engine.Display.factionsContent);
@ -1343,9 +1240,6 @@ const Engine = {
Engine.Display.hacknetNodesContent = document.getElementById("hacknet-nodes-container");
Engine.Display.hacknetNodesContent.style.display = "none";
Engine.Display.worldContent = document.getElementById("world-container");
Engine.Display.worldContent.style.display = "none";
Engine.Display.createProgramContent = document.getElementById("create-program-container");
Engine.Display.createProgramContent.style.display = "none";
@ -1378,22 +1272,12 @@ const Engine = {
//Character info
Engine.Display.characterInfo = document.getElementById("character-content");
//Location lists
Engine.aevumLocationsList = document.getElementById("aevum-locations-list");
Engine.chongqingLocationsList = document.getElementById("chongqing-locations-list");
Engine.sector12LocationsList = document.getElementById("sector12-locations-list");
Engine.newTokyoLocationsList = document.getElementById("newtokyo-locations-list");
Engine.ishimaLocationsList = document.getElementById("ishima-locations-list");
Engine.volhavenLocationsList = document.getElementById("volhaven-locations-list");
//Location page (page that shows up when you visit a specific location in World)
Engine.Display.locationContent = document.getElementById("location-container");
//Engine.Display.locationContent.style.visibility = "hidden";
Engine.Display.locationContent.style.display = "none";
//Work In Progress
Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container");
//Engine.Display.workInProgressContent.style.visibility = "hidden";
Engine.Display.workInProgressContent.style.display = "none";
//Red Pill / Hack World Daemon
@ -1404,9 +1288,6 @@ const Engine = {
Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container");
Engine.Display.cinematicTextContent.style.display = "none";
//Init Location buttons
initLocationButtons();
// Initialize references to main menu links
if (!initializeMainMenuLinks()) {
const errorMsg = "Failed to initialize Main Menu Links. Please try refreshing the page. " +
@ -1480,19 +1361,17 @@ const Engine = {
});
MainMenuLinks.City.addEventListener("click", function() {
Engine.loadWorldContent();
Engine.loadLocationContent();
return false;
});
MainMenuLinks.Travel.addEventListener("click", function() {
Engine.loadTravelContent();
MainMenuLinks.Travel.classList.add("active");
return false;
});
MainMenuLinks.Job.addEventListener("click", function() {
Engine.loadJobContent();
MainMenuLinks.Job.classList.add("active");
return false;
});

View File

@ -206,226 +206,6 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<!-- React Component -->
</div>
<!-- World -->
<div id="world-container" class="generic-menupage-container">
<h2 id="world-city-name"> </h2>
<p id="world-city-desc"> </p>
<ul id="aevum-locations-list">
<li id="aevum-travelagency-li">
<a id="aevum-travelagency" class="a-link-button"> Travel Agency </a>
</li>
<li id="aevum-hospital-li">
<a id="aevum-hospital" class="a-link-button">Hospital</a>
</li>
<li id="aevum-summituniversity-li">
<a id="aevum-summituniversity" class="a-link-button"> Summit University </a>
</li>
<li id="aevum-ecorp-li">
<a id="aevum-ecorp" class="a-link-button"> ECorp </a>
</li>
<li id="aevum-bachmanandassociates-li">
<a id="aevum-bachmanandassociates" class="a-link-button"> Bachman & Associates</a>
</li>
<li id="aevum-clarkeincorporated-li">
<a id="aevum-clarkeincorporated" class="a-link-button"> Clarke Incorporated </a>
</li>
<li id="aevum-fulcrumtechnologies-li">
<a id="aevum-fulcrumtechnologies" class="a-link-button"> Fulcrum Technologies </a>
</li>
<li id="aevum-aerocorp-li">
<a id="aevum-aerocorp" class="a-link-button"> AeroCorp </a>
</li>
<li id="aevum-galacticcybersystems-li">
<a id="aevum-galacticcybersystems" class="a-link-button"> Galactic Cybersystems </a>
</li>
<li id="aevum-watchdogsecurity-li">
<a id="aevum-watchdogsecurity" class="a-link-button">Watchdog Security </a>
</li>
<li id="aevum-rhoconstruction-li">
<a id="aevum-rhoconstruction" class="a-link-button">Rho Construction </a>
</li>
<li id="aevum-aevumpolice-li">
<a id="aevum-aevumpolice" class="a-link-button">Aevum Police</a>
</li>
<li id="aevum-netlinktechnologies-li">
<a id="aevum-netlinktechnologies" class="a-link-button">NetLink Technologies</a>
</li>
<li id="aevum-crushfitnessgym-li">
<a id="aevum-crushfitnessgym" class="a-link-button">Crush Fitness Gym </a>
</li>
<li id="aevum-snapfitnessgym-li">
<a id="aevum-snapfitnessgym" class="a-link-button">Snap Fitness Gym</a>
</li>
<li id="aevum-slums-li">
<a id="aevum-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="chongqing-locations-list">
<li id="chongqing-travelagency-li">
<a id="chongqing-travelagency" class="a-link-button"> Travel Agency </a>
</li>
<li id="chongqing-hospital-li">
<a id="chongqing-hospital" class="a-link-button">Hospital</a>
</li>
<li id="chonqging-kuaigonginternational-li">
<a id="chongqing-kuaigonginternational" class="a-link-button">KuaiGong International </a>
</li>
<li id="chongqing-solarisspacesystems-li">
<a id="chongqing-solarisspacesystems" class="a-link-button">Solaris Space Systems</a>
</li>
<li id="chongqing-slums-li">
<a id="chongqing-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="sector12-locations-list">
<li id="sector12-travelagency-li">
<a id="sector12-travelagency" class="a-link-button">Travel Agency </a>
</li>
<li id="sector12-hospital-li">
<a id="sector12-hospital" class="a-link-button">Hospital</a>
</li>
<li id="sector12-rothmanuniversity-li">
<a id="sector12-rothmanuniversity" class="a-link-button"> Rothman University</a>
</li>
<li id="sector12-megacorp-li">
<a id="sector12-megacorp" class="a-link-button">MegaCorp</a>
</li>
<li id="sector12-bladeindustries-li">
<a id="sector12-bladeindustries" class="a-link-button"> Blade Industries</a>
</li>
<li id="sector12-foursigma-li">
<a id="sector12-foursigma" class="a-link-button">Four Sigma</a>
</li>
<li id="sector12-icarusmicrosystems-li">
<a id="sector12-icarusmicrosystems" class="a-link-button"> Icarus Microsystems</a>
</li>
<li id="sector12-universalenergy-li">
<a id="sector12-universalenergy" class="a-link-button">Universal Energy </a>
</li>
<li id="sector12-deltaone-li">
<a id="sector12-deltaone" class="a-link-button">DeltaOne </a>
</li>
<li id="sector12-cia-li">
<a id="sector12-cia" class="a-link-button">Central Intelligence Agency </a>
</li>
<li id="sector12-nsa-li">
<a id="sector12-nsa" class="a-link-button">National Security Agency </a>
</li>
<li id="sector12-alphaenterprises-li">
<a id="sector12-alphaenterprises" class="a-link-button">Alpha Enterprises</a>
</li>
<li id="sector12-carmichaelsecurity-li">
<a id="sector12-carmichaelsecurity" class="a-link-button"> Carmichael Security</a>
</li>
<li id="sector12-foodnstuff-li">
<a id="sector12-foodnstuff" class="a-link-button">FoodNStuff</a>
</li>
<li id="sector12-joesguns-li">
<a id="sector12-joesguns" class="a-link-button"> Joe's Guns</a>
</li>
<li id="sector12-irongym-li">
<a id="sector12-irongym" class="a-link-button">Iron Gym </a>
</li>
<li id="sector12-powerhousegym-li">
<a id="sector12-powerhousegym" class="a-link-button">Powerhouse Gym</a>
</li>
<li id="sector12-slums-li">
<a id="sector12-slums" class="a-link-button">The Slums</a>
</li>
<li id="sector12-cityhall-li">
<a id="sector12-cityhall" class="a-link-button">City Hall</a>
</li>
</ul>
<ul id="newtokyo-locations-list">
<li id="newtokyo-travelagency-li">
<a id="newtokyo-travelagency" class="a-link-button"> Travel Agency</a>
</li>
<li id="newtokyo-hospital-li">
<a id="newtokyo-hospital" class="a-link-button">Hospital</a>
</li>
<li id="newtokyo-defcomm-li">
<a id="newtokyo-defcomm" class="a-link-button"> DefComm</a>
</li>
<li id="newtokyo-vitalife-li">
<a id="newtokyo-vitalife" class="a-link-button">VitaLife </a>
</li>
<li id="newtokyo-globalpharmaceuticals-li">
<a id="newtokyo-globalpharmaceuticals" class="a-link-button">Global Pharmaceuticals</a>
</li>
<li id="newtokyo-noodlebar-li">
<a id="newtokyo-noodlebar" class="a-link-button">Noodle Bar </a>
</li>
<li id="newtokyo-slums-li">
<a id="newtokyo-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="ishima-locations-list">
<li id="ishima-travelagency-li">
<a id="ishima-travelagency" class="a-link-button">Travel Agency </a>
</li>
<li id="ishima-hospital-li">
<a id="ishima-hospital" class="a-link-button">Hospital</a>
</li>
<li id="ishima-stormtechnologies-li">
<a id="ishima-stormtechnologies" class="a-link-button">Storm Technologies</a>
</li>
<li id="ishima-novamedical-li">
<a id="ishima-novamedical" class="a-link-button">Nova Medical</a>
</li>
<li id="ishima-omegasoftware-li">
<a id="ishima-omegasoftware" class="a-link-button">Omega Software </a>
</li>
<li id="ishima-slums-li">
<a id="ishima-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="volhaven-locations-list">
<li id="volhaven-travelagency-li">
<a id="volhaven-travelagency" class="a-link-button">Travel Agency </a>
</li>
<li id="volhaven-hospital-li">
<a id="volhaven-hospital" class="a-link-button">Hospital</a>
</li>
<li id="volhaven-zbinstituteoftechnology-li">
<a id="volhaven-zbinstituteoftechnology" class="a-link-button">ZB Insitute of Technology</a>
</li>
<li id="volhaven-omnitekincorporated-li">
<a id="volhaven-omnitekincorporated" class="a-link-button">OmniTek Incorporated </a>
</li>
<li id="volhaven-nwo-li">
<a id="volhaven-nwo" class="a-link-button">NWO</a>
</li>
<li id="volhaven-helislabs-li">
<a id="volhaven-helioslabs" class="a-link-button">Helios Labs</a>
</li>
<li id="volhaven-omniacybersystems-li">
<a id="volhaven-omniacybersystems" class="a-link-button">Omnia Cybersystems</a>
</li>
<li id="volhaven-lexocorp-li">
<a id="volhaven-lexocorp" class="a-link-button">LexoCorp</a>
</li>
<li id="volhaven-syscoresecurities-li">
<a id="volhaven-syscoresecurities" class="a-link-button">SysCore Securities</a>
</li>
<li id="volhaven-computek-li">
<a id="volhaven-computek" class="a-link-button">CompuTek</a>
</li>
<li id="volhaven-milleniumfitnessgym-li">
<a id="volhaven-milleniumfitnessgym" class="a-link-button">Millenium Fitness Gym</a>
</li>
<li id="volhaven-slums-li">
<a id="volhaven-slums" class="a-link-button">The Slums</a>
</li>
</ul>
<ul id="generic-locations-list"></ul>
</div>
<!-- Create a program(executable) -->
<div id="create-program-container" class="generic-menupage-container">
<p id="create-program-page-text">
@ -453,160 +233,41 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<h1> Tutorial (AKA Links to Documentation) </h1>
<a id="tutorial-getting-started-link" class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html" >
Getting Started
</a><br><br>
Getting Started</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html">
Servers & Networking
</a><br><br>
Servers & Networking</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html">
Hacking
</a><br><br>
Hacking</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html">
Scripts
</a><br><br>
Scripts</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/netscript.html">
Netscript Programming Language
</a><br><br>
Netscript Programming Language</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html">
Traveling
</a><br><br>
Traveling</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html">
Companies
</a><br><br>
Companies</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html">
Infiltration
</a><br><br>
Infiltration</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html">
Factions
</a><br><br>
Factions</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html">
Augmentations
</a><br><br>
Augmentations</a><br><br>
<a class="a-link-button" target="_blank"
href="https://bitburner.readthedocs.io/en/latest/shortcuts.html">
Keyboard Shortcuts
</a>
Keyboard Shortcuts</a>
</div>
<!-- Location (visiting a location in World) -->
<div id="location-container" class="generic-menupage-container">
<a id="location-return-to-world-button" class="a-link-button"> Return to World </a>
<h1 id="location-name"></h1>
<p id="location-info"> </p>
<p id="location-job-title"> </p>
<p id="location-text-divider-1"> --------------- </p>
<p id="location-job-reputation" class="tooltip"> </p>
<p id="location-text-divider-2"> --------------- </p>
<p id="location-company-favor" class="tooltip"> </p>
<p id="location-text-divider-3"> --------------- </p>
<!-- Jobs/Work at a company -->
<a id="location-software-job" class="a-link-button tooltip"> Apply for Software Job</a>
<a id="location-software-consultant-job" class="a-link-button tooltip"> Apply for Software Consultant Job</a>
<a id="location-it-job" class="a-link-button tooltip"> Apply for IT Job </a>
<a id="location-security-engineer-job" class="a-link-button tooltip"> Apply for Security Engineer Job</a>
<a id="location-network-engineer-job" class="a-link-button tooltip"> Apply for Network Engineer Job</a>
<a id="location-business-job" class="a-link-button tooltip"> Apply for Business Job</a>
<a id="location-business-consultant-job" class="a-link-button tooltip"> Apply for Business Consultant Job </a>
<a id="location-security-job" class="a-link-button tooltip"> Apply for Security Job</a>
<a id="location-agent-job" class="a-link-button tooltip"> Apply to be an Agent</a>
<a id="location-employee-job" class="a-link-button tooltip"> Apply to be an Employee </a>
<a id="location-parttime-employee-job" class="a-link-button tooltip"> Apply to be a Part-time Employee </a>
<a id="location-waiter-job" class="a-link-button tooltip"> Apply to be a Waiter</a>
<a id="location-parttime-waiter-job" class="a-link-button tooltip"> Apply to be a Part-time Waiter</a>
<a id="location-work" class="a-link-button"> Work </a>
<!-- Gym -->
<a id="location-gym-train-str" class="a-link-button">Train Strength</a>
<a id="location-gym-train-def" class="a-link-button">Train Defense </a>
<a id="location-gym-train-dex" class="a-link-button">Train Dexterity</a>
<a id="location-gym-train-agi" class="a-link-button">Train Agility</a>
<!-- Study/Take classes at a university -->
<a id="location-study-computer-science" class="a-link-button">Study Computer Science (free)</a>
<a id="location-data-structures-class" class="a-link-button">Take Data Structures course</a>
<a id="location-networks-class" class="a-link-button">Take Networks course</a>
<a id="location-algorithms-class" class="a-link-button">Take Algorithms course</a>
<a id="location-management-class" class="a-link-button">Take Management course</a>
<a id="location-leadership-class" class="a-link-button">Take Leadership course</a>
<!-- Purchase servers -->
<a id="location-purchase-2gb" class="a-link-button"> Purchase 2GB Server - $150,000</a>
<a id="location-purchase-4gb" class="a-link-button"> Purchase 4GB Server - $300,000</a>
<a id="location-purchase-8gb" class="a-link-button"> Purchase 8GB Server - $600,000</a>
<a id="location-purchase-16gb" class="a-link-button"> Purchase 16GB Server - $1,200,000</a>
<a id="location-purchase-32gb" class="a-link-button"> Purchase 32GB Server - $2,400,000</a>
<a id="location-purchase-64gb" class="a-link-button"> Purchase 64GB Server - $4,800,000</a>
<a id="location-purchase-128gb" class="a-link-button"> Purchase 128GB Server - $9,600,000</a>
<a id="location-purchase-256gb" class="a-link-button"> Purchase 256GB Server - $19,200,000</a>
<a id="location-purchase-512gb" class="a-link-button"> Purchase 512GB Server - $38,400,000</a>
<a id="location-purchase-1tb" class="a-link-button"> Purchase 1TB Server - $75,000,000</a>
<a id="location-purchase-tor" class="a-link-button"> Purchase TOR Router - $100,000</a>
<a id="location-purchase-home-ram" class="a-link-button"> Purchase additional RAM for Home computer </a>
<a id="location-purchase-home-cores" class="a-link-button"> Purchase additional Core for Home computer </a>
<!-- Infiltrate -->
<a id="location-infiltrate" class="a-link-button tooltip"> Infiltrate Company
<span class="tooltiptext">
Infiltrate this company's facility to try and steal their classified secrets!
Warning: You may end up hospitalized if you are unsuccessful!
</span>
</a>
<!-- Hospital -->
<a id="location-hospital-treatment" class="a-link-button"> Get Treatment for Wounds </a>
<!-- Travel agency -->
<p id="location-travel-agency-text">
From here, you can travel to any other city! A ticket costs $200,000.
</p>
<a id="location-travel-to-aevum" class="a-link-button"> Travel to Aevum </a>
<a id="location-travel-to-chongqing" class="a-link-button"> Travel to Chongqing</a>
<a id="location-travel-to-sector12" class="a-link-button"> Travel to Sector-12</a>
<a id="location-travel-to-newtokyo" class="a-link-button"> Travel to New Tokyo</a>
<a id="location-travel-to-ishima" class="a-link-button"> Travel to Ishima</a>
<a id="location-travel-to-volhaven" class="a-link-button"> Travel to Volhaven</a>
<!-- Slums -->
<p id="location-slums-description">
You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and
other shadowy entities. The city's government and police have neglected this area for years...
<br /><br /><br />
In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always
successful. Your chance at successfully committing a crime is determined by your stats.
</p>
<a class="a-link-button tooltip" id="location-slums-shoplift"> Shoplift </a>
<a id="location-slums-rob-store" class="a-link-button tooltip"> Rob a store </a>
<a id="location-slums-mug" class="a-link-button tooltip"> Mug someone </a>
<a id="location-slums-larceny" class="a-link-button tooltip"> Commit Larceny </a>
<a id="location-slums-deal-drugs" class="a-link-button tooltip"> Deal Drugs </a>
<a id="location-slums-bond-forgery" class="a-link-button tooltip">Bond Forgery</a>
<a id="location-slums-traffic-arms" class="a-link-button tooltip">Traffick Illegal Arms</a>
<a id="location-slums-homicide" class="a-link-button tooltip">Homicide</a>
<a id="location-slums-gta" class="a-link-button tooltip"> Grand Theft Auto </a>
<a id="location-slums-kidnap" class="a-link-button tooltip"> Kidnap and Ransom </a>
<a id="location-slums-assassinate" class="a-link-button tooltip"> Assassinate </a>
<a id="location-slums-heist" class="a-link-button tooltip"> Heist </a>
<!-- City Hall -->
<a id="location-cityhall-create-corporation" class="a-link-button">Create a Corporation</a>
<!-- Bladeburner @ NSA -->
<a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a>
<!-- Re-sleeving @ VitaLife -->
<a id="location-vitalife-resleeve" class="a-link-button">Re-Sleeve</a>
</div>
<div id="infiltration-container" class="generic-menupage-container">

View File

@ -0,0 +1,80 @@
/**
* Basic stateless button that automatically re-renders itself every X seconds
* Uses the 'std-button' css class
*
* NOT recommended for usage - only if you really have to
*/
import * as React from "react";
interface IProps {
disabled?: boolean;
intervalTime?: number;
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: object;
text: string;
tooltip?: string;
}
interface IState {
i: number;
}
type IInnerHTMLMarkup = {
__html: string;
}
export class AutoupdatingStdButton extends React.Component<IProps, IState> {
/**
* Timer ID for auto-updating implementation (returned value from setInterval())
*/
interval: number = 0;
constructor(props: IProps) {
super(props);
this.state = {
i: 0,
}
}
componentDidMount() {
const time = this.props.intervalTime ? this.props.intervalTime : 1000;
this.interval = setInterval(() => this.tick(), time);
}
componentWillUnmount() {
clearInterval(this.interval);
}
tick() {
this.setState(prevState => ({
i: prevState.i + 1
}));
}
render() {
const hasTooltip = this.props.tooltip != null && this.props.tooltip !== "";
let className = this.props.disabled ? "std-button-disabled" : "std-button";
if (hasTooltip) {
className += " tooltip"
}
// Tooltip will eb set using inner HTML
let tooltipMarkup: IInnerHTMLMarkup | null;
if (hasTooltip) {
tooltipMarkup = {
__html: this.props.tooltip!
}
}
return (
<button className={className} onClick={this.props.onClick} style={this.props.style}>
{this.props.text}
{
hasTooltip &&
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
}
</button>
)
}
}

View File

@ -2,22 +2,44 @@
* Basic stateless button
* Uses the 'std-button' css class
*/
import * as React from "react";
import * as React from "react";
export interface IStdButtonProps {
interface IStdButtonProps {
disabled?: boolean;
id?: string;
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: object;
text: string;
tooltip?: string;
}
type IInnerHTMLMarkup = {
__html: string;
}
export class StdButton extends React.Component<IStdButtonProps, any> {
render() {
const className = this.props.disabled ? "std-button-disabled" : "std-button";
const hasTooltip = this.props.tooltip != null && this.props.tooltip !== "";
let className = this.props.disabled ? "std-button-disabled" : "std-button";
if (hasTooltip) {
className += " tooltip";
}
// Tooltip will be set using inner HTML
let tooltipMarkup: IInnerHTMLMarkup | null;
if (hasTooltip) {
tooltipMarkup = {
__html: this.props.tooltip!
}
}
return (
<button className={className} onClick={this.props.onClick} style={this.props.style}>
<button className={className} id={this.props.id} onClick={this.props.onClick} style={this.props.style}>
{this.props.text}
{
hasTooltip &&
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
}
</button>
)
}

View File

@ -0,0 +1,20 @@
/**
* Stateless button that represents something that has been purchased.
*/
import * as React from "react";
interface IStdButtonPurchasedProps {
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: object;
text: string;
}
export class StdButtonPurchased extends React.Component<IStdButtonPurchasedProps, any> {
render() {
return (
<button className={"std-button-bought"} onClick={this.props.onClick} style={this.props.style}>
{this.props.text}
</button>
)
}
}

View File

@ -28,11 +28,6 @@ export enum Page {
*/
HacknetNodes = "HacknetNodes",
/**
* View the city the player is currently in.
*/
World = "World",
/**
* The list of programs the player could potentially build.
*/
@ -64,7 +59,7 @@ export enum Page {
DevMenu = "Dev Menu",
/**
* Information about the specific location the player at (job, company, etc.);
* Visiting a location in the world
*/
Location = "Location",

View File

@ -33,7 +33,7 @@ interface IPostContentConfig {
color?: string; // Additional class for terminal-line. Does NOT replace
}
function postContent(input: string, config: IPostContentConfig = {}) {
export function postContent(input: string, config: IPostContentConfig = {}) {
// tslint:disable-next-line:max-line-length
const style: string = `color: ${config.color != null ? config.color : "var(--my-font-color)"}; background-color:var(--my-background-color);${config.id === undefined ? " white-space:pre-wrap;" : ""}`;
// tslint:disable-next-line:max-line-length

View File

@ -1,2 +1,2 @@
export function dialogBoxCreate(txt: string, preformatted: boolean): void;
export var dialogBoxOpened: boolean;
export function dialogBoxCreate(txt: string, preformatted?: boolean): void;
export var dialogBoxOpened: boolean;

View File

@ -6,7 +6,8 @@
* 1. Just a Yes/No response from player
* 2. Popup also includes a text input field in addition to the Yes/No response
*/
import {clearEventListeners} from "./uiHelpers/clearEventListeners";
import { clearEventListeners } from "./uiHelpers/clearEventListeners";
import { KEY } from "./helpers/keyCodes";
export let yesNoBoxOpen: boolean = false;
@ -14,9 +15,9 @@ const yesNoBoxContainer: HTMLElement | null = document.getElementById("yes-no-bo
const yesNoBoxTextElement: HTMLElement | null = document.getElementById("yes-no-box-text");
export function yesNoBoxHotkeyHandler(e: KeyboardEvent) {
if (e.keyCode === 27) {
if (e.keyCode === KEY.ESC) {
yesNoBoxClose();
} else if (e.keyCode === 13) {
} else if (e.keyCode === KEY.ENTER) {
const yesBtn: HTMLElement | null = document.getElementById("yes-no-box-yes");
if (yesBtn) {
yesBtn.click();
@ -78,9 +79,9 @@ const yesNoTextInputBoxInput: HTMLInputElement | null = document.getElementById(
const yesNoTextInputBoxTextElement: HTMLElement | null = document.getElementById("yes-no-text-input-box-text");
export function yesNoTxtInpBoxHotkeyHandler(e: KeyboardEvent) {
if (e.keyCode === 27) {
if (e.keyCode === KEY.ESC) {
yesNoTxtInpBoxClose();
} else if (e.keyCode === 13) {
} else if (e.keyCode === KEY.ENTER) {
const yesBtn: HTMLElement | null = document.getElementById("yes-no-text-input-box-yes");
if (yesBtn) {
yesBtn.click();

View File

@ -126,6 +126,7 @@ module.exports = (env, argv) => {
}
},
devServer: {
port: 8000,
publicPath: `/`,
},
resolve: {